l2736 il y a 2 semaines
Parent
commit
504285ae2e
100 fichiers modifiés avec 123 ajouts et 5805 suppressions
  1. 0 1
      Avalonia/Avalonia.Xaml.Behaviors/Avalonia.Xaml.Behaviors.csproj
  2. 0 1
      Avalonia/Avalonia.Xaml.Interactions.Custom/Avalonia.Xaml.Interactions.Custom.csproj
  3. 1 2
      Avalonia/Avalonia.Xaml.Interactions.DragAndDrop/Avalonia.Xaml.Interactions.DragAndDrop.csproj
  4. 0 1
      Avalonia/Avalonia.Xaml.Interactions.Draggable/Avalonia.Xaml.Interactions.Draggable.csproj
  5. 0 1
      Avalonia/Avalonia.Xaml.Interactions.Events/Avalonia.Xaml.Interactions.Events.csproj
  6. 0 1
      Avalonia/Avalonia.Xaml.Interactions.Responsive/Avalonia.Xaml.Interactions.Responsive.csproj
  7. 0 1
      Avalonia/Avalonia.Xaml.Interactions/Avalonia.Xaml.Interactions.csproj
  8. 0 1
      Avalonia/Avalonia.Xaml.Interactivity/Avalonia.Xaml.Interactivity.csproj
  9. 1 1
      Avalonia/ShakerApp/Tools/DispatherInovke.cs
  10. 0 2
      Avalonia/ShakerApp/Tools/ResourceBinding.cs
  11. 1 1
      Avalonia/ShakerApp/ViewModels/Menu/MenuItemViewModel.cs
  12. 1 1
      Avalonia/ShakerApp/ViewModels/ShakerConfig/RandomTransferFunctionViewModel.cs
  13. 0 1
      Avalonia/ShakerApp/ViewModels/ShakerConfig/ShakerConfigViewModel.cs
  14. 1 1
      Avalonia/ShakerApp/ViewModels/SignalPreview/SignalPreviewViewModel.cs
  15. 0 21
      Avalonia/build/SourceLink.props
  16. 0 14
      Avalonia/build/XUnit.props
  17. 3 3
      Calc/FFTW/BufferPool.cs
  18. 3 3
      Calc/FFTW/DFT.cs
  19. 4 2
      Calc/FFTW/FftwInterop.cs
  20. 4 4
      Calc/FFTW/PinnedArray.cs
  21. 2 2
      Calc/FFTW/PinnedGCHandle.cs
  22. 3 1
      Calc/SIMDFxpConvert/SIMDFxpConvert.csproj
  23. 2 2
      Language/Zh-CN/Language.cs
  24. 2 2
      Language/en-us/Language.cs
  25. 5 5
      NIFPGA/FPGA.cs
  26. 1 1
      NIFPGA/FPGABaseProperty.cs
  27. 0 0
      NativeLibraryLoader/IFileCheck.cs
  28. 0 0
      NativeLibraryLoader/INativeLoader.cs
  29. 0 0
      NativeLibraryLoader/Linux/ELFFileCheck.cs
  30. 0 0
      NativeLibraryLoader/Linux/UnixNativeLoader.cs
  31. 0 0
      NativeLibraryLoader/MAC/BSDNativeLoader.cs
  32. 0 0
      NativeLibraryLoader/MAC/MachOFileCheck.cs
  33. 0 0
      NativeLibraryLoader/MachineType.cs
  34. 10 0
      NativeLibraryLoader/NativeLibraryLoader.csproj
  35. 6 6
      NativeLibraryLoader/NativeLoader.cs
  36. 0 0
      NativeLibraryLoader/Windows/PEFileCheck.cs
  37. 0 0
      NativeLibraryLoader/Windows/WindowNativeLoader.cs
  38. 0 23
      NativeLoader/NativeLoader.projitems
  39. 0 13
      NativeLoader/NativeLoader.shproj
  40. 0 11
      OxyPlot/OxyPlot.SkiaSharp.Wpf/AssemblyInfo.cs
  41. 0 95
      OxyPlot/OxyPlot.SkiaSharp.Wpf/JpegExporter.cs
  42. 0 40
      OxyPlot/OxyPlot.SkiaSharp.Wpf/OxyPlot.SkiaSharp.Wpf.csproj
  43. 0 247
      OxyPlot/OxyPlot.SkiaSharp.Wpf/OxySKElement.cs
  44. 0 71
      OxyPlot/OxyPlot.SkiaSharp.Wpf/PdfExporter.cs
  45. 0 91
      OxyPlot/OxyPlot.SkiaSharp.Wpf/PlotView.cs
  46. 0 84
      OxyPlot/OxyPlot.SkiaSharp.Wpf/PngExporter.cs
  47. 0 38
      OxyPlot/OxyPlot.SkiaSharp.Wpf/RenderTarget.cs
  48. 0 36
      OxyPlot/OxyPlot.SkiaSharp.Wpf/SkiaExtensions.cs
  49. 0 1008
      OxyPlot/OxyPlot.SkiaSharp.Wpf/SkiaRenderContext.cs
  50. 0 44
      OxyPlot/OxyPlot.SkiaSharp.Wpf/SvgExporter.cs
  51. 0 7
      OxyPlot/OxyPlot.SkiaSharp.Wpf/VisualStudioToolsManifest.xml
  52. 0 95
      OxyPlot/OxyPlot.SkiaSharp/JpegExporter.cs
  53. 0 31
      OxyPlot/OxyPlot.SkiaSharp/OxyPlot.SkiaSharp.csproj
  54. 0 71
      OxyPlot/OxyPlot.SkiaSharp/PdfExporter.cs
  55. 0 84
      OxyPlot/OxyPlot.SkiaSharp/PngExporter.cs
  56. 0 38
      OxyPlot/OxyPlot.SkiaSharp/RenderTarget.cs
  57. 0 36
      OxyPlot/OxyPlot.SkiaSharp/SkiaExtensions.cs
  58. 0 1008
      OxyPlot/OxyPlot.SkiaSharp/SkiaRenderContext.cs
  59. 0 44
      OxyPlot/OxyPlot.SkiaSharp/SvgExporter.cs
  60. 0 11
      OxyPlot/OxyPlot.Wpf.Shared/AssemblyInfo.cs
  61. 0 75
      OxyPlot/OxyPlot.Wpf.Shared/Converters/OxyColorConverter.cs
  62. 0 55
      OxyPlot/OxyPlot.Wpf.Shared/Converters/ThicknessConverter.cs
  63. 0 31
      OxyPlot/OxyPlot.Wpf.Shared/ExporterExtensions.cs
  64. 0 29
      OxyPlot/OxyPlot.Wpf.Shared/MoreColors.cs
  65. 0 32
      OxyPlot/OxyPlot.Wpf.Shared/OxyPlot.Wpf.Shared.csproj
  66. 0 24
      OxyPlot/OxyPlot.Wpf.Shared/PlotCommands.cs
  67. 0 197
      OxyPlot/OxyPlot.Wpf.Shared/PlotViewBase.Events.cs
  68. 0 165
      OxyPlot/OxyPlot.Wpf.Shared/PlotViewBase.Properties.cs
  69. 0 489
      OxyPlot/OxyPlot.Wpf.Shared/PlotViewBase.cs
  70. 0 98
      OxyPlot/OxyPlot.Wpf.Shared/Themes/Generic.xaml
  71. 0 657
      OxyPlot/OxyPlot.Wpf.Shared/Tracker/TrackerControl.cs
  72. 0 57
      OxyPlot/OxyPlot.Wpf.Shared/Tracker/TrackerDefinition.cs
  73. 0 487
      OxyPlot/OxyPlot.Wpf.Shared/Utilities/ConverterExtensions.cs
  74. 0 49
      OxyPlot/OxyPlot.Wpf.Shared/Utilities/Keyboard.cs
  75. 3 0
      PLCConnect/NModbus/Data/FileRecordCollection.cs
  76. 1 0
      PLCConnect/NModbus/Data/PointSource.cs
  77. 2 2
      PLCConnect/NModbus/Device/ConcurrentModbusMaster.cs
  78. 22 7
      PLCConnect/NModbus/Device/ModbusMasterTcpConnection.cs
  79. 2 2
      PLCConnect/NModbus/Device/ModbusSlaveNetwork.cs
  80. 4 5
      PLCConnect/NModbus/Device/ModbusTcpSlaveNetwork.cs
  81. 2 2
      PLCConnect/NModbus/Extensions/DictionaryExtensions.cs
  82. 1 1
      PLCConnect/NModbus/Extensions/ModbusMasterEnhanced.cs
  83. 1 1
      PLCConnect/NModbus/IO/ModbusTransport.cs
  84. 1 1
      PLCConnect/NModbus/Logging/ConsoleModbusLogger.cs
  85. 1 1
      PLCConnect/NModbus/Logging/TraceModbusLogger.cs
  86. 2 1
      PLCConnect/NModbus/Message/ModbusMessageImpl.cs
  87. 3 0
      PLCConnect/NModbus/Message/ReadWriteMultipleRegistersRequest.cs
  88. 1 1
      PLCConnect/NModbus/Message/WriteFileRecordResponse.cs
  89. 3 3
      PLCConnect/NModbus/Message/WriteMultipleCoilsRequest.cs
  90. 2 2
      PLCConnect/NModbus/Message/WriteMultipleCoilsResponse.cs
  91. 3 3
      PLCConnect/NModbus/Message/WriteMultipleRegistersRequest.cs
  92. 1 1
      PLCConnect/NModbus/Message/WriteSingleRegisterRequestResponse.cs
  93. 4 4
      PLCConnect/NModbus/ModbusFactory.cs
  94. 1 1
      PLCConnect/NModbus/SlaveException.cs
  95. 1 1
      PLCConnect/NModbus/Unme.Common/DisposableUtility.cs
  96. 8 8
      PLCConnect/NModbus/Utility/DiscriminatedUnion.cs
  97. 1 1
      Shaker/Service.cs
  98. 1 2
      Shaker/ShakerService.csproj
  99. 1 1
      Shaker/ViewModel/ServiceRandomConfigViewModel.cs
  100. 1 1
      Shaker/ViewModel/ServiceRandomDataViewModel.cs

+ 0 - 1
Avalonia/Avalonia.Xaml.Behaviors/Avalonia.Xaml.Behaviors.csproj

@@ -17,7 +17,6 @@
     <PackageReference Include="Avalonia" Version="11.2.2" />
   </ItemGroup>
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Xaml.Interactions.Custom\Avalonia.Xaml.Interactions.Custom.csproj" />

+ 0 - 1
Avalonia/Avalonia.Xaml.Interactions.Custom/Avalonia.Xaml.Interactions.Custom.csproj

@@ -19,7 +19,6 @@
   </ItemGroup>
 
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
 
   <ItemGroup>

+ 1 - 2
Avalonia/Avalonia.Xaml.Interactions.DragAndDrop/Avalonia.Xaml.Interactions.DragAndDrop.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>net8.0</TargetFramework>
@@ -17,7 +17,6 @@
     <PackageReference Include="Avalonia" Version="11.2.2" />
   </ItemGroup>
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Xaml.Interactivity\Avalonia.Xaml.Interactivity.csproj" />

+ 0 - 1
Avalonia/Avalonia.Xaml.Interactions.Draggable/Avalonia.Xaml.Interactions.Draggable.csproj

@@ -18,7 +18,6 @@
   </ItemGroup>
 
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Xaml.Interactivity\Avalonia.Xaml.Interactivity.csproj" />

+ 0 - 1
Avalonia/Avalonia.Xaml.Interactions.Events/Avalonia.Xaml.Interactions.Events.csproj

@@ -17,7 +17,6 @@
     <PackageReference Include="Avalonia" Version="11.2.2" />
   </ItemGroup>
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
 
   <ItemGroup>

+ 0 - 1
Avalonia/Avalonia.Xaml.Interactions.Responsive/Avalonia.Xaml.Interactions.Responsive.csproj

@@ -18,6 +18,5 @@
     <ProjectReference Include="..\Avalonia.Xaml.Interactivity\Avalonia.Xaml.Interactivity.csproj" />
   </ItemGroup>
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
 </Project>

+ 0 - 1
Avalonia/Avalonia.Xaml.Interactions/Avalonia.Xaml.Interactions.csproj

@@ -17,7 +17,6 @@
     <PackageReference Include="Avalonia" Version="11.2.2" />
   </ItemGroup>
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
 
   <ItemGroup>

+ 0 - 1
Avalonia/Avalonia.Xaml.Interactivity/Avalonia.Xaml.Interactivity.csproj

@@ -17,7 +17,6 @@
     <PackageReference Include="Avalonia" Version="11.2.2" />
   </ItemGroup>
   <Import Project="..\build\SignAssembly.props" />
-  <Import Project="..\build\SourceLink.props" />
   <Import Project="..\build\TrimmingEnable.targets" />
 
 

+ 1 - 1
Avalonia/ShakerApp/Tools/DispatherInovke.cs

@@ -29,7 +29,7 @@ namespace ShakerApp.Tools
 
             }
         }
-        public static T Inovke<T>(Func<T> action)
+        public static T? Inovke<T>(Func<T> action)
         {
             if (action == null) return default;
             try

+ 0 - 2
Avalonia/ShakerApp/Tools/ResourceBinding.cs

@@ -45,8 +45,6 @@ namespace ShakerApp
             };
             targetObject.Bind(ResourceBindingExtensions.BindingExtensionProperty, binding);
 
-
-
             return null;
         }
 

+ 1 - 1
Avalonia/ShakerApp/ViewModels/Menu/MenuItemViewModel.cs

@@ -19,7 +19,7 @@ namespace ShakerApp.ViewModels
     public class MenuItemViewModel:ObservableObject
     {
         private string header = string.Empty;
-        private string iconKey = null;
+        private string iconKey = string.Empty;
         private bool isEnabled = true;
         private bool isVisible = true;
         private bool isSeparator = false;

+ 1 - 1
Avalonia/ShakerApp/ViewModels/ShakerConfig/RandomTransferFunctionViewModel.cs

@@ -90,7 +90,7 @@ namespace ShakerApp.ViewModels
                 ShowError(App.Current?.FindResource("RandomPlanTimeIsZero") + "");
                 return;
             }
-            CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.STARTRANDOMTEST).Publish(this, null);
+            CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.STARTRANDOMTEST)?.Publish(this, null);
             CloseWindowAction?.Invoke();
         }
         protected override void Cancel()

+ 0 - 1
Avalonia/ShakerApp/ViewModels/ShakerConfig/ShakerConfigViewModel.cs

@@ -142,7 +142,6 @@ namespace ShakerApp.ViewModels
                 {
                     if(x.Item2 ==null)
                     {
-                        group.Properties[x.x.Name] = null;
                         return;
                     }
                     if(x.x.FieldType.IsAssignableTo(typeof(IList)))

+ 1 - 1
Avalonia/ShakerApp/ViewModels/SignalPreview/SignalPreviewViewModel.cs

@@ -70,7 +70,7 @@ namespace ShakerApp.ViewModels
             ShowLayout = false;
         }
         public bool ShowLayout { get => showLayout; set =>SetProperty(ref showLayout , value); }
-        private bool lastShowLayout = false;
+
         private System.Timers.Timer timer = new System.Timers.Timer(1000);
         private bool buttonPointerOver;
         private bool panelPointerOver;

+ 0 - 21
Avalonia/build/SourceLink.props

@@ -1,21 +0,0 @@
-<Project>
-  <PropertyGroup>
-    <PublishRepositoryUrl>true</PublishRepositoryUrl>
-    <IncludeSymbols>false</IncludeSymbols>
-    <EmbedUntrackedSources>true</EmbedUntrackedSources>
-    <DebugType>embedded</DebugType>
-    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
-    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
-    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
-  </PropertyGroup>
-  <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All"/>
-  </ItemGroup>
-  <ItemGroup>
-    <SourceRoot Include="$([MSBuild]::EnsureTrailingSlash($(NuGetPackageRoot)))" Condition="'$(NuGetPackageRoot)' != ''" />
-  </ItemGroup>
-</Project>

+ 0 - 14
Avalonia/build/XUnit.props

@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <PackageReference Include="xunit" />
-    <PackageReference Include="xunit.abstractions" />
-    <PackageReference Include="xunit.assert" />
-    <PackageReference Include="xunit.core" />
-    <PackageReference Include="xunit.extensibility.core" />
-    <PackageReference Include="xunit.extensibility.execution" />
-    <PackageReference Include="xunit.runner.console" />
-    <PackageReference Include="xunit.runner.visualstudio" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" />
-  </ItemGroup>
-</Project>

+ 3 - 3
Calc/FFTW/BufferPool.cs

@@ -58,10 +58,10 @@ namespace FFTW.NET
 
 		public struct Container : IDisposable
 		{
-			T[] _buffer;
+			T[]? _buffer;
 			readonly BufferPool<T> _bufferPool;
 
-			public T[] Buffer => _buffer;
+			public T[]? Buffer => _buffer;
 
 			private Container(BufferPool<T> bufferPool, T[] buffer)
 			{
@@ -74,7 +74,7 @@ namespace FFTW.NET
 				if (minSize < bufferPool.MinSizeToPool)
 					return new Container(bufferPool, new T[minSize]);
 
-				T[] buffer = null;
+				T[]? buffer = null;
 				lock (bufferPool._buffers)
 				{
 					for (int i = 0; i < bufferPool._buffers.Count; i++)

+ 3 - 3
Calc/FFTW/DFT.cs

@@ -91,7 +91,7 @@ namespace FFTW.NET
 			else
 			{
 				using (var bufferContainer = _bufferPool.RequestBuffer(input.Length * Marshal.SizeOf<Complex>() + MemoryAlignment))
-				using (var buffer = new AlignedArrayComplex(bufferContainer.Buffer, MemoryAlignment, input.GetSize()))
+				using (var buffer = new AlignedArrayComplex(bufferContainer.Buffer!, MemoryAlignment, input.GetSize()))
 				using (var plan = FftwPlanC2C.Create(buffer, buffer, input.Rank, input.GetSize(), direction, plannerFlags, nThreads))
 				{
 					input.CopyTo(plan.Input);
@@ -130,7 +130,7 @@ namespace FFTW.NET
 			/// and <see cref="PlannerFlags.Estimate"/> is not specified, we use
 			/// a different buffer to avoid overwriting the input
 			using (var bufferContainer = _bufferPool.RequestBuffer(input.Length * sizeof(double) + MemoryAlignment))
-			using (var buffer = new AlignedArrayDouble(bufferContainer.Buffer, MemoryAlignment, input.GetSize()))
+			using (var buffer = new AlignedArrayDouble(bufferContainer.Buffer!, MemoryAlignment, input.GetSize()))
 			using (var plan = FftwPlanRC.Create(buffer, output, DftDirection.Forwards, plannerFlags, nThreads))
 			{
 				input.CopyTo(plan.BufferReal);
@@ -188,7 +188,7 @@ namespace FFTW.NET
 			/// and <see cref="PlannerFlags.Estimate"/> is not specified, we use
 			/// a different buffer to avoid overwriting the input
 			using (var bufferContainer = _bufferPool.RequestBuffer(input.Length * Marshal.SizeOf<Complex>() + MemoryAlignment))
-			using (var buffer = new AlignedArrayComplex(bufferContainer.Buffer, MemoryAlignment, input.GetSize()))
+			using (var buffer = new AlignedArrayComplex(bufferContainer.Buffer!, MemoryAlignment, input.GetSize()))
 			using (var plan = FftwPlanRC.Create(output, buffer, DftDirection.Backwards, plannerFlags, nThreads))
 			{
 				input.CopyTo(plan.BufferComplex);

+ 4 - 2
Calc/FFTW/FftwInterop.cs

@@ -17,6 +17,7 @@ GNU General Public License for more details.
 #endregion
 
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.Runtime.InteropServices;
 using System.Text;
 using NativeLibraryLoader;
@@ -106,8 +107,9 @@ namespace FFTW.NET
             _NativeLoader.Init();
 			_version = GetVersionAndInitialize();
         }
+		[AllowNull]
 		private static NativeLibraryLoader.NativeLoader _NativeLoader;
-		static Version _version;
+		private static Version _version = new Version();
 
 		public static Version Version => _version;
 
@@ -135,7 +137,7 @@ namespace FFTW.NET
 			{ 
 				//GetDelegate<fftw_init_threads>()();
 			}
-			catch (DllNotFoundException) { return null; }
+			catch (DllNotFoundException) { return new Version(); }
 
 			string version = GetVersion();
 			return new Version(version);

+ 4 - 4
Calc/FFTW/PinnedArray.cs

@@ -53,25 +53,25 @@ namespace FFTW.NET
 
 		public T this[params int[] indices]
 		{
-			get { return (T)_buffer.GetValue(indices); }
+			get { return (T)_buffer.GetValue(indices)!; }
 			set { _buffer.SetValue(value, indices); }
 		}
 
 		public T this[int index]
 		{
-			get { return (T)_buffer.GetValue(index); }
+			get { return (T)_buffer.GetValue(index)!; }
 			set { _buffer.SetValue(value, index); }
 		}
 
 		public T this[int i1, int i2]
 		{
-			get { return (T)_buffer.GetValue(i1, i2); }
+			get { return (T)_buffer.GetValue(i1, i2)!; }
 			set { _buffer.SetValue(value, i1, i2); }
 		}
 
 		public T this[int i1, int i2, int i3]
 		{
-			get { return (T)_buffer.GetValue(i1, i2, i3); }
+			get { return (T)_buffer.GetValue(i1, i2, i3)!; }
 			set { _buffer.SetValue(value, i1, i2, i3); }
 		}
 

+ 2 - 2
Calc/FFTW/PinnedGCHandle.cs

@@ -30,10 +30,10 @@ namespace FFTW.NET
 				_handle.Free();
 		}
 
-		public override string ToString() => _handle.ToString();
+		public override string ToString() => _handle.ToString() ?? string.Empty;
 
 		public IntPtr Pointer => _handle.AddrOfPinnedObject();
 		public bool IsAllocated => _handle.IsAllocated;
-		public object Target => _handle.Target;
+		public object? Target => _handle.Target;
 	}
 }

+ 3 - 1
Calc/SIMDFxpConvert/SIMDFxpConvert.csproj

@@ -11,7 +11,9 @@
 
   <Import Project="..\FFTW\FFTW.projitems" Label="Shared" />
 
-  <Import Project="..\..\NativeLoader\NativeLoader.projitems" Label="Shared" />
+  <ItemGroup>
+    <ProjectReference Include="..\..\NativeLibraryLoader\NativeLibraryLoader.csproj" />
+  </ItemGroup>
 
   <ItemGroup>
     <None Update="libs\libfftw3-3-x64.dll">

+ 2 - 2
Language/Zh-CN/Language.cs

@@ -11,8 +11,8 @@ namespace Zh_CN
         public Language()
         {
             var Resource = (ResourceDictionary)AvaloniaXamlLoader.Load(new Uri(ResourcePath, UriKind.Absolute));
-            Name = (string)Resource["Name"];
-            Key = (string)Resource["Key"];
+            Name = (string)Resource["Name"]!;
+            Key = (string)Resource["Key"]!;
         }
         public string Name { get; }
 

+ 2 - 2
Language/en-us/Language.cs

@@ -12,8 +12,8 @@ namespace en_us
         public Language()
         {
             var Resource = (ResourceDictionary)AvaloniaXamlLoader.Load(new Uri(ResourcePath, UriKind.Absolute));
-            Name = (string)Resource["Name"];
-            Key = (string)Resource["Key"];
+            Name = (string)Resource["Name"]!;
+            Key = (string)Resource["Key"]!;
         }
         public string Name { get; }
 

+ 5 - 5
NIFPGA/FPGA.cs

@@ -12,11 +12,11 @@ namespace NIFPGA
 {
     public sealed class FPGA
     {
-        public string BitstreamMD5 { get; private set; }
-        public string BitfileVersion { get;private set; }
-        public string SignatureRegister { get; private set; }
-        public string BitstreamVersion { get;private set; }
-        public string SignatureNames { get; private set; }
+        public string BitstreamMD5 { get; private set; } = string.Empty;
+        public string BitfileVersion { get; private set; } = string.Empty;
+        public string SignatureRegister { get; private set; } = string.Empty;
+        public string BitstreamVersion { get; private set; } = string.Empty;
+        public string SignatureNames { get; private set; } = string.Empty;
         private List<Fifo> fifos= new List<Fifo>();
         private IFxpConvert _FXPConvert;
         private List<FPGABaseProperty> properties= new List<FPGABaseProperty>();

+ 1 - 1
NIFPGA/FPGABaseProperty.cs

@@ -16,7 +16,7 @@ namespace NIFPGA
         public uint SizeInBits { get; init; }
         public Boolean IsIndicator { get; }
         public uint Indicator { get; }
-        public string Name { get; init; }
+        public string Name { get; init; } = string.Empty;
         public override string ToString()
         {
             return Name;

+ 0 - 0
NativeLoader/IFileCheck.cs → NativeLibraryLoader/IFileCheck.cs


+ 0 - 0
NativeLoader/INativeLoader.cs → NativeLibraryLoader/INativeLoader.cs


+ 0 - 0
NativeLoader/Linux/ELFFileCheck.cs → NativeLibraryLoader/Linux/ELFFileCheck.cs


+ 0 - 0
NativeLoader/Linux/UnixNativeLoader.cs → NativeLibraryLoader/Linux/UnixNativeLoader.cs


+ 0 - 0
NativeLoader/MAC/BSDNativeLoader.cs → NativeLibraryLoader/MAC/BSDNativeLoader.cs


+ 0 - 0
NativeLoader/MAC/MachOFileCheck.cs → NativeLibraryLoader/MAC/MachOFileCheck.cs


+ 0 - 0
NativeLoader/MachineType.cs → NativeLibraryLoader/MachineType.cs


+ 10 - 0
NativeLibraryLoader/NativeLibraryLoader.csproj

@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+</Project>

+ 6 - 6
NativeLoader/NativeLoader.cs → NativeLibraryLoader/NativeLoader.cs

@@ -11,12 +11,12 @@ namespace NativeLibraryLoader
     {
         private ConcurrentDictionary<IntPtr, Delegate> _Cache = new ConcurrentDictionary<IntPtr, Delegate>();
         private IntPtr intPtr;
-        public string DLLName { get; }
-        public string Extension { get; }
+        public string DLLName { get; } = string.Empty;
+        public string Extension { get; } = string.Empty;    
         public Boolean Loaded => intPtr != IntPtr.Zero;
-        public string SearchPattern { get; set; }
+        public string SearchPattern { get; set; } = string.Empty;
         public string LoadedFile =>loadedFile;
-        private string loadedFile;
+        private string loadedFile=string.Empty;
         public List<String> SearchDirectories { get; } = new List<string>();
         private IFileCheck fileCheck;
         private INativeLoader nativeLoader;
@@ -68,7 +68,7 @@ namespace NativeLibraryLoader
         }
         public T LoadFunction<T>(string enterpoint)where T :Delegate
         {
-            if (intPtr == IntPtr.Zero) return default;
+            if (intPtr == IntPtr.Zero) throw new EntryPointNotFoundException(enterpoint);
             var intptr = typeof(T).TypeHandle.Value;
             if(_Cache.TryGetValue(intptr,out var del))
             {
@@ -85,7 +85,7 @@ namespace NativeLibraryLoader
             {
                 string s = nativeLoader.CoreGetLastError();
             }
-            return default;
+            throw new EntryPointNotFoundException(enterpoint);
         }
         public IntPtr LoadFunction(string enterpoint)
         {

+ 0 - 0
NativeLoader/Windows/PEFileCheck.cs → NativeLibraryLoader/Windows/PEFileCheck.cs


+ 0 - 0
NativeLoader/Windows/WindowNativeLoader.cs → NativeLibraryLoader/Windows/WindowNativeLoader.cs


+ 0 - 23
NativeLoader/NativeLoader.projitems

@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
-    <HasSharedItems>true</HasSharedItems>
-    <SharedGUID>2b1dd602-d589-4709-965b-2a3ae83257d9</SharedGUID>
-  </PropertyGroup>
-  <PropertyGroup Label="Configuration">
-    <Import_RootNamespace>SharedProject1</Import_RootNamespace>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildThisFileDirectory)IFileCheck.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)INativeLoader.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Linux\ELFFileCheck.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Linux\UnixNativeLoader.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)MachineType.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)MAC\BSDNativeLoader.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)MAC\MachOFileCheck.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)NativeLoader.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Windows\PEFileCheck.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Windows\WindowNativeLoader.cs" />
-  </ItemGroup>
-</Project>

+ 0 - 13
NativeLoader/NativeLoader.shproj

@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>2b1dd602-d589-4709-965b-2a3ae83257d9</ProjectGuid>
-    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
-  </PropertyGroup>
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
-  <PropertyGroup />
-  <Import Project="NativeLoader.projitems" Label="Shared" />
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
-</Project>

+ 0 - 11
OxyPlot/OxyPlot.SkiaSharp.Wpf/AssemblyInfo.cs

@@ -1,11 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="AssemblyInfo.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-using System.Windows;
-using System.Windows.Markup;
-
-[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
-[assembly: XmlnsDefinition("http://oxyplot.org/skiawpf", "OxyPlot.SkiaSharp.Wpf")]

+ 0 - 95
OxyPlot/OxyPlot.SkiaSharp.Wpf/JpegExporter.cs

@@ -1,95 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="JpegExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to jpeg using the SkiaSharp renderer.
-    /// </summary>
-    public class JpegExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the DPI.
-        /// </summary>
-        public float Dpi { get; set; } = 96;
-
-        /// <summary>
-        /// Gets or sets the export height (in pixels).
-        /// </summary>
-        public int Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export width (in pixels).
-        /// </summary>
-        public int Width { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export quality (0-100).
-        /// </summary>
-        public int Quality { get; set; } = 90;
-
-        /// <summary>
-        /// Exports the specified model to a file.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="quality">The export quality (0-100).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, string path, int width, int height, int quality, float dpi = 96)
-        {
-            using var stream = File.OpenWrite(path);
-            Export(model, stream, width, height, quality, dpi);
-        }
-
-        /// <summary>
-        /// Exports the specified model to a stream.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="stream">The output stream.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="quality">The export quality (0-100).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, Stream stream, int width, int height, int quality, float dpi = 96)
-        {
-            var exporter = new JpegExporter { Width = width, Height = height, Quality = quality, Dpi = dpi };
-            exporter.Export(model, stream);
-        }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var bitmap = new SKBitmap(this.Width, this.Height);
-
-            using (var canvas = new SKCanvas(bitmap))
-            using (var context = new SkiaRenderContext { RenderTarget = RenderTarget.PixelGraphic, SkCanvas = canvas })
-            {
-                canvas.Clear(SKColors.White);
-                var dpiScale = this.Dpi / 96;
-                context.DpiScale = dpiScale;
-                model.Update(true);
-                var backgroundColor = model.Background;
-
-                // jpg doesn't support transparency
-                if (!backgroundColor.IsVisible())
-                {
-                    backgroundColor = OxyColors.White;
-                }
-
-                canvas.Clear(backgroundColor.ToSKColor());
-                model.Render(context, new OxyRect(0, 0, this.Width / dpiScale, this.Height / dpiScale));
-            }
-
-            using var skStream = new SKManagedWStream(stream);
-            bitmap.Encode(skStream, SKEncodedImageFormat.Jpeg, this.Quality);
-        }
-    }
-}

+ 0 - 40
OxyPlot/OxyPlot.SkiaSharp.Wpf/OxyPlot.SkiaSharp.Wpf.csproj

@@ -1,40 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
-    <UseWPF>true</UseWPF>
-    <Description>OxyPlot is a plotting library for .NET. This package targets WPF applications and uses the SkiaSharp renderer.</Description>
-    <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
-    <GenerateDocumentationFile>False</GenerateDocumentationFile>
-    <PackageTags>plotting plot charting chart wpf</PackageTags>
-    <LangVersion>8</LangVersion>
-    <SignAssembly>False</SignAssembly>
-    <AssemblyOriginatorKeyFile>OxyPlot.SkiaSharp.Wpf.snk</AssemblyOriginatorKeyFile>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net462|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net462|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <ItemGroup>
-    <PackageReference Include="SkiaSharp" Version="2.88.9" />
-    <PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.9" />
-    <PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.88.9" />
-    <None Include="VisualStudioToolsManifest.xml" Pack="true" PackagePath="tools" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\OxyPlot.Wpf.Shared\OxyPlot.Wpf.Shared.csproj" />
-  </ItemGroup>
-</Project>

+ 0 - 247
OxyPlot/OxyPlot.SkiaSharp.Wpf/OxySKElement.cs

@@ -1,247 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="OxySKElement.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-/*
-
-This is a modified copy of https://github.com/mono/SkiaSharp/blob/2550d14410839ebba2d541ec5b423261b9236197/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKElement.cs.
-License of the original file:
-
-------------------------------------------
-
-Copyright (c) 2015-2016 Xamarin, Inc.
-Copyright (c) 2017-2018 Microsoft Corporation.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-------------------------------------------
-
-Mmodifications include
- - A workaround for https://github.com/mono/SkiaSharp/issues/1236. Once the issue is fixed on their side, we should remove this file and replace usages by SKElement from the SkiaSharp.Views.WPF nuget package.
- - Simple RenderTransform detection to allow for non-unity scaling per https://github.com/oxyplot/oxyplot/issues/1785.
-
-*/
-
-namespace OxyPlot.SkiaSharp.Wpf
-{
-    using global::SkiaSharp;
-    using global::SkiaSharp.Views.Desktop;
-    using System;
-    using System.ComponentModel;
-    using System.Windows;
-    using System.Windows.Media;
-    using System.Windows.Media.Imaging;
-
-    /// <summary>
-    /// Provides a surface on which to render with the SkiaSharp graphics APIs.
-    /// </summary>
-    public class OxySKElement : FrameworkElement
-    {
-        /// <summary>
-        /// A value indicating whether the element is being presented in design mode. 
-        /// </summary>
-        private readonly bool designMode;
-
-        /// <summary>
-        /// The bitmap to which to render.
-        /// </summary>
-        private WriteableBitmap bitmap;
-
-        /// <summary>
-        /// A value indicating whether to ignore pixel scaling when determining the render buffer bitmap dimensions.
-        /// </summary>
-        private bool ignorePixelScaling;
-
-        /// <summary>
-        /// Initialises an instance of the <see cref="OxySKElement"/> class.
-        /// </summary>
-        public OxySKElement()
-        {
-            this.designMode = DesignerProperties.GetIsInDesignMode(this);
-            RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.NearestNeighbor);
-        }
-
-        /// <summary>
-        /// Invoked when the surface is painting.
-        /// </summary>
-        [Category("Appearance")]
-        public event EventHandler<SKPaintSurfaceEventArgs> PaintSurface;
-
-        /// <summary>
-        /// Gets the size of the render buffer bitmap, or <c>SKSize.Empty</c> if there is no current render buffer bitmap.
-        /// </summary>
-        [Bindable(false)]
-        [Browsable(false)]
-        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public SKSize CanvasSize => this.bitmap == null ? SKSize.Empty : new SKSize(this.bitmap.PixelWidth, this.bitmap.PixelHeight);
-
-        /// <summary>
-        /// Gets or sets a value indicating whether to ignore pixel scaling when determining the render buffer bitmap dimensions.
-        /// </summary>
-        public bool IgnorePixelScaling
-        {
-            get { return this.ignorePixelScaling; }
-            set
-            {
-                this.ignorePixelScaling = value;
-                this.InvalidateVisual();
-            }
-        }
-
-        /// <summary>
-        /// Raises the <see cref="PaintSurface"/> event with the given <see cref="SKPaintSurfaceEventArgs"/>.
-        /// </summary>
-        /// <param name="e">The skia surface and associated information ready for drawing.</param>
-        protected virtual void OnPaintSurface(SKPaintSurfaceEventArgs e)
-        {
-            // invoke the event
-            PaintSurface?.Invoke(this, e);
-        }
-
-        /// <inheritdoc/>
-        protected override void OnRender(DrawingContext drawingContext)
-        {
-            if (this.designMode)
-            {
-                return;
-            }
-
-            if (this.Visibility != Visibility.Visible)
-            {
-                return;
-            }
-
-            var size = this.CreateSize(out var scaleX, out var scaleY);
-            var renderScale = this.GetRenderScale();
-
-            // scale bitmap according to the renderScale
-            var bitmapPixelWidth = (int)(size.Width * renderScale);
-            var bitmapPixelHeight = (int)(size.Height * renderScale);
-
-            if (size.Width <= 0 || size.Height <= 0)
-            {
-                return;
-            }
-
-            var info = new SKImageInfo(bitmapPixelWidth, bitmapPixelHeight, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
-
-            // reset the bitmap if the size has changed
-            if (this.bitmap == null || info.Width != this.bitmap.PixelWidth || info.Height != this.bitmap.PixelHeight)
-            {
-                this.bitmap = new WriteableBitmap(bitmapPixelWidth, bitmapPixelHeight, 96 * scaleX, 96 * scaleY, PixelFormats.Pbgra32, null);
-            }
-
-            // draw on the bitmap
-            this.bitmap.Lock();
-            using (var surface = SKSurface.Create(info, this.bitmap.BackBuffer, this.bitmap.BackBufferStride))
-            {
-                this.OnPaintSurface(new SKPaintSurfaceEventArgs(surface, info));
-            }
-
-            // draw the bitmap to the screen
-            this.bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmapPixelWidth, bitmapPixelHeight));
-            this.bitmap.Unlock();
-
-            // get window to screen offset
-            var ancestor = GetAncestorVisualFromVisualTree(this);
-            var visualOffset = ancestor != null ? this.TransformToAncestor(ancestor).Transform(default) : default;
-
-            // calculate offset to physical pixels
-            var offsetX = ((visualOffset.X * scaleX) % 1) / scaleX;
-            var offsetY = ((visualOffset.Y * scaleY) % 1) / scaleY;
-
-            // draw, scaling back down from the (rounded) bitmap dimensions
-            drawingContext.DrawImage(this.bitmap, new Rect(-offsetX, -offsetY, this.bitmap.Width / renderScale, this.bitmap.Height / renderScale));
-        }
-
-        /// <inheritdoc/>
-        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
-        {
-            base.OnRenderSizeChanged(sizeInfo);
-
-            this.InvalidateVisual();
-        }
-
-        /// <summary>
-        /// Determines the size of the render buffer bitmap, and the scale at which to draw.
-        /// </summary>
-        /// <param name="scaleX">The horizontal scale.</param>
-        /// <param name="scaleY">The vertical scale.</param>
-        /// <returns>The size in pixels of the bitmap.</returns>
-        private SKSizeI CreateSize(out double scaleX, out double scaleY)
-        {
-            scaleX = 1.0;
-            scaleY = 1.0;
-
-            var w = this.ActualWidth;
-            var h = this.ActualHeight;
-
-            if (!IsPositive(w) || !IsPositive(h))
-            {
-                return SKSizeI.Empty;
-            }
-
-            if (this.IgnorePixelScaling)
-            {
-                return new SKSizeI((int)w, (int)h);
-            }
-
-            var compositionTarget = PresentationSource.FromVisual(this)?.CompositionTarget;
-            if (compositionTarget != null)
-            {
-                var m = compositionTarget.TransformToDevice;
-                scaleX = m.M11;
-                scaleY = m.M22;
-            }
-            return new SKSizeI((int)(w * scaleX), (int)(h * scaleY));
-
-            static bool IsPositive(double value)
-            {
-                return !double.IsNaN(value) && !double.IsInfinity(value) && value > 0;
-            }
-        }
-
-        /// <summary>
-        /// Returns a reference to the visual object that hosts the dependency object in the visual tree.
-        /// </summary>
-        /// <returns> The host visual from the visual tree.</returns>
-        private Visual GetAncestorVisualFromVisualTree(DependencyObject startElement)
-        {
-            DependencyObject child = startElement;
-            DependencyObject parent = VisualTreeHelper.GetParent(child);
-            while (parent != null)
-            {
-                child = parent;
-                parent = VisualTreeHelper.GetParent(child);
-            }
-            return child is Visual visualChild ? visualChild : Window.GetWindow(this);
-        }
-
-        /// <summary>
-        /// Determines the scaling transform applied to the control.
-        /// </summary>
-        /// <returns>The scale factor.</returns>
-        public virtual double GetRenderScale()
-        {
-            var transform = VisualTreeHelper.GetTransform(this)?.Value ?? Matrix.Identity;
-            DependencyObject control = VisualTreeHelper.GetParent(this);
-            while (control != null)
-            {
-                if (control is Visual v && VisualTreeHelper.GetTransform(v) is Transform vt)
-                {
-                    transform *= vt.Value;
-                }
-                control = VisualTreeHelper.GetParent(control);
-            }
-
-            return Math.Max(transform.M11, transform.M22);
-        }
-    }
-}

+ 0 - 71
OxyPlot/OxyPlot.SkiaSharp.Wpf/PdfExporter.cs

@@ -1,71 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PdfExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to pdf using the SkiaSharp renderer.
-    /// </summary>
-    public class PdfExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the export height (in points, where 1 point equals 1/72 inch).
-        /// </summary>
-        public float Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export width (in points, where 1 point equals 1/72 inch).
-        /// </summary>
-        public float Width { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether text shaping should be used when rendering text.
-        /// </summary>
-        public bool UseTextShaping { get; set; } = true;
-
-        /// <summary>
-        /// Exports the specified model to a file.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        public static void Export(IPlotModel model, string path, float width, float height)
-        {
-            using var stream = File.OpenWrite(path);
-            Export(model, stream, width, height);
-        }
-
-        /// <summary>
-        /// Exports the specified model to a stream.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="stream">The output stream.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        public static void Export(IPlotModel model, Stream stream, float width, float height)
-        {
-            var exporter = new PdfExporter { Width = width, Height = height };
-            exporter.Export(model, stream);
-        }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var document = SKDocument.CreatePdf(stream);
-            using var pdfCanvas = document.BeginPage(this.Width, this.Height);
-            using var context = new SkiaRenderContext { RenderTarget = RenderTarget.VectorGraphic, SkCanvas = pdfCanvas, UseTextShaping = this.UseTextShaping };
-            const float dpiScale = 72f / 96;
-            context.DpiScale = dpiScale;
-            model.Update(true);
-            pdfCanvas.Clear(model.Background.ToSKColor());
-            model.Render(context, new OxyRect(0, 0, this.Width / dpiScale, this.Height / dpiScale));
-        }
-    }
-}

+ 0 - 91
OxyPlot/OxyPlot.SkiaSharp.Wpf/PlotView.cs

@@ -1,91 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PlotView.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp.Wpf
-{
-    using global::SkiaSharp;
-    using global::SkiaSharp.Views.Desktop;
-    using OxyPlot;
-    using OxyPlot.SkiaSharp;
-    using OxyPlot.Wpf;
-    using System.Windows;
-
-    /// <summary>
-    /// Represents a control that displays a <see cref="PlotModel" />. This <see cref="IPlotView"/> is based on <see cref="SkiaSharp.SkiaRenderContext"/>.
-    /// </summary>
-    public partial class PlotView : PlotViewBase
-    {
-        /// <summary>
-        /// Gets the SkiaRenderContext.
-        /// </summary>
-        private SkiaRenderContext SkiaRenderContext => (SkiaRenderContext)this.renderContext;
-
-        /// <summary>
-        /// Gets the OxySKElement.
-        /// </summary>
-        private OxySKElement OxySKElement => (OxySKElement)this.plotPresenter;
-
-        /// <inheritdoc/>
-        protected override void ClearBackground()
-        {
-            var color = this.ActualModel?.Background.IsVisible() == true
-                ? this.ActualModel.Background.ToSKColor()
-                : SKColors.Empty;
-
-            this.SkiaRenderContext.SkCanvas.Clear(color);
-        }
-
-        /// <inheritdoc/>
-        protected override FrameworkElement CreatePlotPresenter()
-        {
-            var skElement = new OxySKElement();
-            skElement.PaintSurface += this.SkElement_PaintSurface;
-            return skElement;
-        }
-
-        /// <inheritdoc/>
-        protected override IRenderContext CreateRenderContext()
-        {
-            return new SkiaRenderContext();
-        }
-
-        /// <inheritdoc/>
-        protected override void RenderOverride()
-        {
-            // Instead of rendering directly, invalidate the plot presenter.
-            // Actual rendering is done in SkElement_PaintSurface.
-            this.plotPresenter.InvalidateVisual();
-        }
-
-        /// <inheritdoc/>
-        protected override double UpdateDpi()
-        {
-            var dpiScale = base.UpdateDpi();
-            var renderScale = this.OxySKElement.GetRenderScale();
-            var skiaScale = (float)(dpiScale * renderScale);
-
-            this.SkiaRenderContext.DpiScale = skiaScale;
-
-            return dpiScale;
-        }
-
-        /// <summary>
-        /// This is called when the SKElement paints its surface.
-        /// </summary>
-        /// <param name="sender">The sender.</param>
-        /// <param name="e">The surface paint event args.</param>
-        private void SkElement_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
-        {
-            if (this.plotPresenter == null || this.renderContext == null)
-            {
-                return;
-            }
-            this.SkiaRenderContext.SkCanvas = e.Surface.Canvas;
-            base.RenderOverride();
-            this.SkiaRenderContext.SkCanvas = null;
-        }
-    }
-}

+ 0 - 84
OxyPlot/OxyPlot.SkiaSharp.Wpf/PngExporter.cs

@@ -1,84 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PngExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to png using the SkiaSharp renderer.
-    /// </summary>
-    public class PngExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the DPI.
-        /// </summary>
-        public float Dpi { get; set; } = 96;
-
-        /// <summary>
-        /// Gets or sets the export height (in pixels).
-        /// </summary>
-        public int Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export width (in pixels).
-        /// </summary>
-        public int Width { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether text shaping should be used when rendering text.
-        /// </summary>
-        public bool UseTextShaping { get; set; } = true;
-
-        /// <summary>
-        /// Exports the specified model to a file.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, string path, int width, int height, float dpi = 96)
-        {
-            using var stream = File.OpenWrite(path);
-            Export(model, stream, width, height, dpi);
-        }
-
-        /// <summary>
-        /// Exports the specified model to a stream.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="stream">The output stream.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, Stream stream, int width, int height, float dpi = 96)
-        {
-            var exporter = new PngExporter { Width = width, Height = height, Dpi = dpi };
-            exporter.Export(model, stream);
-        }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var bitmap = new SKBitmap(this.Width, this.Height);
-
-            using (var canvas = new SKCanvas(bitmap))
-            using (var context = new SkiaRenderContext { RenderTarget = RenderTarget.PixelGraphic, SkCanvas = canvas, UseTextShaping = this.UseTextShaping })
-            {
-                var dpiScale = this.Dpi / 96;
-                context.DpiScale = dpiScale;
-                model.Update(true);
-                canvas.Clear(model.Background.ToSKColor());
-                model.Render(context, new OxyRect(0, 0, this.Width / dpiScale, this.Height / dpiScale));
-            }
-
-            using var skStream = new SKManagedWStream(stream);
-            bitmap.Encode(skStream, SKEncodedImageFormat.Png, 0);
-        }
-    }
-}

+ 0 - 38
OxyPlot/OxyPlot.SkiaSharp.Wpf/RenderTarget.cs

@@ -1,38 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="RenderTarget.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    /// <summary>
-    /// Defines a render target for <see cref="SkiaRenderContext"/>.
-    /// </summary>
-    public enum RenderTarget
-    {
-        /// <summary>
-        /// Indicates that the <see cref="SkiaRenderContext"/> renders to a screen.
-        /// </summary>
-        /// <remarks>
-        /// The render context may try to snap shapes to device pixels and will use sub-pixel text rendering.
-        /// </remarks>
-        Screen,
-
-        /// <summary>
-        /// Indicates that the <see cref="SkiaRenderContext"/> renders to a pixel graphic.
-        /// </summary>
-        /// <remarks>
-        /// The render context may try to snap shapes to pixels, but will not use sub-pixel text rendering.
-        /// </remarks>
-        PixelGraphic,
-
-        /// <summary>
-        /// Indicates that the <see cref="SkiaRenderContext"/> renders to a vector graphic.
-        /// </summary>
-        /// <remarks>
-        /// The render context will not use any rendering enhancements that are specific to pixel graphics.
-        /// </remarks>
-        VectorGraphic
-    }
-}

+ 0 - 36
OxyPlot/OxyPlot.SkiaSharp.Wpf/SkiaExtensions.cs

@@ -1,36 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="SkiaExtensions.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-
-    /// <summary>
-    /// Provides extension methods for conversion between SkiaSharp and oxyplot objects.
-    /// </summary>
-    public static class SkiaExtensions
-    {
-        /// <summary>
-        /// Converts a <see cref="OxyColor"/> to a <see cref="SKColor"/>;
-        /// </summary>
-        /// <param name="color">The <see cref="OxyColor"/>.</param>
-        /// <returns>The <see cref="SKColor"/>.</returns>
-        public static OxyColor ToOxyColor(this SKColor color)
-        {
-            return OxyColor.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="SKColor"/> to a <see cref="OxyColor"/>;
-        /// </summary>
-        /// <param name="color">The <see cref="SKColor"/>.</param>
-        /// <returns>The <see cref="OxyColor"/>.</returns>
-        public static SKColor ToSKColor(this OxyColor color)
-        {
-            return new SKColor(color.R, color.G, color.B, color.A);
-        }
-    }
-}

+ 0 - 1008
OxyPlot/OxyPlot.SkiaSharp.Wpf/SkiaRenderContext.cs

@@ -1,1008 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="SkiaRenderContext.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using global::SkiaSharp.HarfBuzz;
-    using System;
-    using System.Collections.Generic;
-    using System.Diagnostics;
-    using System.Linq;
-    using System.Reflection;
-
-    /// <summary>
-    /// Implements <see cref="IRenderContext" /> based on SkiaSharp.
-    /// </summary>
-    public class SkiaRenderContext : IRenderContext, IDisposable
-    {
-        private readonly Dictionary<FontDescriptor, SKShaper> shaperCache = new Dictionary<FontDescriptor, SKShaper>();
-        private readonly Dictionary<FontDescriptor, SKTypeface> typefaceCache = new Dictionary<FontDescriptor, SKTypeface>();
-        private SKPaint paint = new SKPaint();
-        private SKPath path = new SKPath();
-
-        private readonly Dictionary<int, string> _fontWeights = new Dictionary<int, string>()
-        {
-            [100] = "Thin",
-            [200] = "ExtraLight",
-            [300] = "Light",
-            [400] = "Regular",
-            [500] = "Medium",
-            [600] = "SemiBold",
-            [700] = "Bold",
-            [800] = "ExtraBold",
-            [900] = "Black"
-        };
-
-        /// <summary>
-        /// Gets or sets the DPI scaling factor. A value of 1 corresponds to 96 DPI (dots per inch).
-        /// </summary>
-        public float DpiScale { get; set; } = 1;
-
-        /// <inheritdoc />
-        public bool RendersToScreen => this.RenderTarget == RenderTarget.Screen;
-
-        /// <summary>
-        /// Gets or sets the render target.
-        /// </summary>
-        public RenderTarget RenderTarget { get; set; } = RenderTarget.Screen;
-
-        /// <summary>
-        /// Gets or sets the <see cref="SKCanvas"/> the <see cref="SkiaRenderContext"/> renders to. This must be set before any draw calls.
-        /// </summary>
-        public SKCanvas SkCanvas { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether text shaping should be used when rendering text.
-        /// </summary>
-        public bool UseTextShaping { get; set; } = true;
-
-        /// <summary>
-        /// Gets or sets the Miter limit. This is the maximum ratio between Miter length and stroke thickness. When this ration is exceeded, the join falls back to a Bevel. The default value is 10.
-        /// </summary>
-        public float MiterLimit { get; set; } = 10;
-
-        /// <summary>
-        /// Gets a value indicating whether the context renders to pixels.
-        /// </summary>
-        /// <value><c>true</c> if the context renders to pixels; otherwise, <c>false</c>.</value>
-        private bool RendersToPixels => this.RenderTarget != RenderTarget.VectorGraphic;
-
-        /// <inheritdoc/>
-        public int ClipCount => this.SkCanvas?.SaveCount - 1 ?? 0;
-
-        /// <inheritdoc/>
-        public void CleanUp()
-        {
-        }
-
-        /// <inheritdoc />
-        public void Dispose()
-        {
-            this.Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        /// <inheritdoc/>
-        public void DrawEllipse(OxyRect extents, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0))
-            {
-                return;
-            }
-
-            var actualRect = this.Convert(extents);
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawOval(actualRect, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawOval(actualRect, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawEllipses(IList<OxyRect> extents, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && (!stroke.IsVisible() || thickness <= 0))
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            foreach (var extent in extents)
-            {
-                path.AddOval(this.Convert(extent));
-            }
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawImage(
-            OxyImage source,
-            double srcX,
-            double srcY,
-            double srcWidth,
-            double srcHeight,
-            double destX,
-            double destY,
-            double destWidth,
-            double destHeight,
-            double opacity,
-            bool interpolate)
-        {
-            if (source == null)
-            {
-                return;
-            }
-
-            var bytes = source.GetData();
-            var image = SKBitmap.Decode(bytes);
-
-            var src = new SKRect((float)srcX, (float)srcY, (float)(srcX + srcWidth), (float)(srcY + srcHeight));
-            var dest = new SKRect(this.Convert(destX), this.Convert(destY), this.Convert(destX + destWidth), this.Convert(destY + destHeight));
-
-            var paint = this.GetImagePaint(opacity, interpolate);
-            this.SkCanvas.DrawBitmap(image, src, dest, paint);
-        }
-
-        /// <inheritdoc/>
-        public void DrawLine(
-            IList<ScreenPoint> points,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (points.Count < 2 || !stroke.IsVisible() || thickness <= 0)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-            var actualPoints = this.GetActualPoints(points, thickness, edgeRenderingMode);
-            AddPoints(actualPoints, path);
-
-            this.SkCanvas.DrawPath(path, paint);
-        }
-
-        /// <inheritdoc/>
-        public void DrawLineSegments(
-            IList<ScreenPoint> points,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (points.Count < 2 || !stroke.IsVisible() || thickness <= 0)
-            {
-                return;
-            }
-
-            var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-
-            var skPoints = new SKPoint[points.Count];
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Automatic when this.RendersToPixels:
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels:
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var snapOffset = this.GetSnapOffset(thickness, edgeRenderingMode);
-                    for (var i = 0; i < points.Count - 1; i += 2)
-                    {
-                        var p1 = points[i];
-                        var p2 = points[i + 1];
-                        if (RenderContextBase.IsStraightLine(p1, p2))
-                        {
-                            skPoints[i] = this.ConvertSnap(p1, snapOffset);
-                            skPoints[i + 1] = this.ConvertSnap(p2, snapOffset);
-                        }
-                        else
-                        {
-                            skPoints[i] = this.Convert(p1);
-                            skPoints[i + 1] = this.Convert(p2);
-                        }
-                    }
-
-                    break;
-                default:
-                    for (var i = 0; i < points.Count; i += 2)
-                    {
-                        skPoints[i] = this.Convert(points[i]);
-                        skPoints[i + 1] = this.Convert(points[i + 1]);
-                    }
-
-                    break;
-            }
-
-            this.SkCanvas.DrawPoints(SKPointMode.Lines, skPoints, paint);
-        }
-
-        /// <inheritdoc/>
-        public void DrawPolygon(
-            IList<ScreenPoint> points,
-            OxyColor fill,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0) || points.Count < 2)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            var actualPoints = this.GetActualPoints(points, thickness, edgeRenderingMode);
-            AddPoints(actualPoints, path);
-            path.Close();
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawPolygons(
-            IList<IList<ScreenPoint>> polygons,
-            OxyColor fill,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0) || polygons.Count == 0)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            foreach (var polygon in polygons)
-            {
-                if (polygon.Count < 2)
-                {
-                    continue;
-                }
-
-                var actualPoints = this.GetActualPoints(polygon, thickness, edgeRenderingMode);
-                AddPoints(actualPoints, path);
-                path.Close();
-            }
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawRectangle(OxyRect rectangle, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0))
-            {
-                return;
-            }
-
-            var actualRectangle = this.GetActualRect(rectangle, thickness, edgeRenderingMode);
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawRect(actualRectangle, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawRect(actualRectangle, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawRectangles(IList<OxyRect> rectangles, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0) || rectangles.Count == 0)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            foreach (var rectangle in this.GetActualRects(rectangles, thickness, edgeRenderingMode))
-            {
-                path.AddRect(rectangle);
-            }
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawText(
-            ScreenPoint p,
-            string text,
-            OxyColor fill,
-            string fontFamily = null,
-            double fontSize = 10,
-            double fontWeight = 400,
-            double rotation = 0,
-            HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left,
-            VerticalAlignment verticalAlignment = VerticalAlignment.Top,
-            OxySize? maxSize = null)
-        {
-            if (text == null || !fill.IsVisible())
-            {
-                return;
-            }
-
-            var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper);
-            paint.Color = fill.ToSKColor();
-
-            var x = this.Convert(p.X);
-            var y = this.Convert(p.Y);
-
-            var lines = StringHelper.SplitLines(text);
-            var lineHeight = paint.GetFontMetrics(out var metrics);
-
-            var deltaY = verticalAlignment switch
-            {
-                VerticalAlignment.Top => -metrics.Ascent,
-                VerticalAlignment.Middle => -(metrics.Ascent + metrics.Descent + lineHeight * (lines.Length - 1)) / 2,
-                VerticalAlignment.Bottom => -metrics.Descent - lineHeight * (lines.Length - 1),
-                _ => throw new ArgumentOutOfRangeException(nameof(verticalAlignment))
-            };
-
-            using var _ = new SKAutoCanvasRestore(this.SkCanvas);
-            this.SkCanvas.Translate(x, y);
-            this.SkCanvas.RotateDegrees((float)rotation);
-
-            foreach (var line in lines)
-            {
-                if (this.UseTextShaping)
-                {
-                    var width = this.MeasureText(line, shaper, paint);
-                    var deltaX = horizontalAlignment switch
-                    {
-                        HorizontalAlignment.Left => 0,
-                        HorizontalAlignment.Center => -width / 2,
-                        HorizontalAlignment.Right => -width,
-                        _ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
-                    };
-
-                    this.paint.TextAlign = SKTextAlign.Left;
-                    this.SkCanvas.DrawShapedText(shaper, line, deltaX, deltaY, paint);
-                }
-                else
-                {
-                    paint.TextAlign = horizontalAlignment switch
-                    {
-                        HorizontalAlignment.Left => SKTextAlign.Left,
-                        HorizontalAlignment.Center => SKTextAlign.Center,
-                        HorizontalAlignment.Right => SKTextAlign.Right,
-                        _ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
-                    };
-
-                    this.SkCanvas.DrawText(line, 0, deltaY, paint);
-                }
-
-                deltaY += lineHeight;
-            }
-        }
-
-        /// <inheritdoc/>
-        public OxySize MeasureText(string text, string fontFamily = null, double fontSize = 10, double fontWeight = 500)
-        {
-            if (text == null)
-            {
-                return new OxySize(0, 0);
-            }
-
-            var lines = StringHelper.SplitLines(text);
-            var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper);
-            var height = paint.GetFontMetrics(out _) * lines.Length;
-            var width = lines.Max(line => this.MeasureText(line, shaper, paint)); 
-
-            return new OxySize(this.ConvertBack(width), this.ConvertBack(height));
-        }
-
-        /// <inheritdoc/>
-        public void PopClip()
-        {
-            if (this.SkCanvas.SaveCount == 1)
-            {
-                throw new InvalidOperationException("Unbalanced call to PopClip.");
-            }
-
-            this.SkCanvas.Restore();
-        }
-
-        /// <inheritdoc/>
-        public void PushClip(OxyRect clippingRectangle)
-        {
-            this.SkCanvas.Save();
-            this.SkCanvas.ClipRect(this.Convert(clippingRectangle));
-        }
-
-        /// <inheritdoc/>
-        public void SetToolTip(string text)
-        {
-        }
-
-        /// <summary>
-        /// Disposes managed resources.
-        /// </summary>
-        /// <param name="disposing">A value indicating whether this method is called from the Dispose method.</param>
-        protected virtual void Dispose(bool disposing)
-        {
-            if (!disposing)
-            {
-                return;
-            }
-
-            this.paint?.Dispose();
-            this.paint = null;
-            this.path?.Dispose();
-            this.path = null;
-
-            foreach (var typeface in this.typefaceCache.Values)
-            {
-                typeface.Dispose();
-            }
-
-            this.typefaceCache.Clear();
-
-            foreach (var shaper in this.shaperCache.Values)
-            {
-                shaper.Dispose();
-            }
-
-            this.shaperCache.Clear();
-        }
-
-        /// <summary>
-        /// Adds the <see cref="SKPoint"/>s to the <see cref="SKPath"/> as a series of connected lines.
-        /// </summary>
-        /// <param name="points">The points.</param>
-        /// <param name="path">The path.</param>
-        private static void AddPoints(IEnumerable<SKPoint> points, SKPath path)
-        {
-            using var e = points.GetEnumerator();
-            if (!e.MoveNext())
-            {
-                return;
-            }
-
-            path.MoveTo(e.Current);
-            while (e.MoveNext())
-            {
-                path.LineTo(e.Current);
-            }
-        }
-
-        /// <summary>
-        /// Gets the pixel offset that a line with the specified thickness should snap to.
-        /// </summary>
-        /// <remarks>
-        /// This takes into account that lines with even stroke thickness should be snapped to the border between two pixels while lines with odd stroke thickness should be snapped to the middle of a pixel.
-        /// </remarks>
-        /// <param name="thickness">The line thickness.</param>
-        /// <returns>The snap offset.</returns>
-        private static float GetSnapOffset(float thickness)
-        {
-            var mod = thickness % 2;
-            var isOdd = mod >= 0.5 && mod < 1.5;
-            return isOdd ? 0.5f : 0;
-        }
-
-        /// <summary>
-        /// Snaps a value to a pixel with the specified offset.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <param name="offset">The offset.</param>
-        /// <returns>The snapped value.</returns>
-        private static float Snap(float value, float offset)
-        {
-            return (float)Math.Round(value + offset, MidpointRounding.AwayFromZero) - offset;
-        }
-
-        /// <summary>
-        /// Converts a <see cref="OxyRect"/> to a <see cref="SKRect"/>, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="rect">The rectangle.</param>
-        /// <returns>The converted rectangle.</returns>
-        private SKRect Convert(OxyRect rect)
-        {
-            var left = this.Convert(rect.Left);
-            var right = this.Convert(rect.Right);
-            var top = this.Convert(rect.Top);
-            var bottom = this.Convert(rect.Bottom);
-            return new SKRect(left, top, right, bottom);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="double"/> to a <see cref="float"/>, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>The converted value.</returns>
-        private float Convert(double value)
-        {
-            return (float)value * this.DpiScale;
-        }
-
-        /// <summary>
-        /// Converts <see cref="ScreenPoint"/> to a <see cref="SKPoint"/>, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="point">The point.</param>
-        /// <returns>The converted point.</returns>
-        private SKPoint Convert(ScreenPoint point)
-        {
-            return new SKPoint(this.Convert(point.X), this.Convert(point.Y));
-        }
-
-        /// <summary>
-        /// Converts a <see cref="float"/> to a <see cref="double"/>, applying reversed DPI scaling.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>The converted value.</returns>
-        private double ConvertBack(float value)
-        {
-            return value / this.DpiScale;
-        }
-
-        /// <summary>
-        /// Converts <see cref="double"/> dash array to a <see cref="float"/> array, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="values">The array of values.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <returns>The array of converted values.</returns>
-        private float[] ConvertDashArray(double[] values, float strokeThickness)
-        {
-            var ret = new float[values.Length];
-            for (var i = 0; i < values.Length; i++)
-            {
-                ret[i] = this.Convert(values[i]) * strokeThickness;
-            }
-
-            return ret;
-        }
-
-        /// <summary>
-        /// Converts a <see cref="OxyRect"/> to a <see cref="SKRect"/>, taking into account DPI scaling and snapping the corners to pixels.
-        /// </summary>
-        /// <param name="rect">The rectangle.</param>
-        /// <param name="snapOffset">The snapping offset.</param>
-        /// <returns>The converted rectangle.</returns>
-        private SKRect ConvertSnap(OxyRect rect, float snapOffset)
-        {
-            var left = this.ConvertSnap(rect.Left, snapOffset);
-            var right = this.ConvertSnap(rect.Right, snapOffset);
-            var top = this.ConvertSnap(rect.Top, snapOffset);
-            var bottom = this.ConvertSnap(rect.Bottom, snapOffset);
-            return new SKRect(left, top, right, bottom);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="double"/> to a <see cref="float"/>, taking into account DPI scaling and snapping the value to a pixel.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <param name="snapOffset">The snapping offset.</param>
-        /// <returns>The converted value.</returns>
-        private float ConvertSnap(double value, float snapOffset)
-        {
-            return Snap(this.Convert(value), snapOffset);
-        }
-
-        /// <summary>
-        /// Converts <see cref="ScreenPoint"/> to a <see cref="SKPoint"/>, taking into account DPI scaling and snapping the point to a pixel.
-        /// </summary>
-        /// <param name="point">The point.</param>
-        /// <param name="snapOffset">The snapping offset.</param>
-        /// <returns>The converted point.</returns>
-        private SKPoint ConvertSnap(ScreenPoint point, float snapOffset)
-        {
-            return new SKPoint(this.ConvertSnap(point.X, snapOffset), this.ConvertSnap(point.Y, snapOffset));
-        }
-
-        /// <summary>
-        /// Gets the <see cref="SKPoint"/>s that should actually be rendered from the list of <see cref="ScreenPoint"/>s, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="screenPoints">The points.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual points.</returns>
-        private IEnumerable<SKPoint> GetActualPoints(IList<ScreenPoint> screenPoints, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Automatic when this.RendersToPixels && RenderContextBase.IsStraightLine(screenPoints):
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels && RenderContextBase.IsStraightLine(screenPoints):
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var snapOffset = this.GetSnapOffset(strokeThickness, edgeRenderingMode);
-                    return screenPoints.Select(p => this.ConvertSnap(p, snapOffset));
-                default:
-                    return screenPoints.Select(this.Convert);
-            }
-        }
-
-        /// <summary>
-        /// Gets the <see cref="SKRect"/> that should actually be rendered from the <see cref="OxyRect"/>, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="rect">The rectangle.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual rectangle.</returns>
-        private SKRect GetActualRect(OxyRect rect, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels:
-                case EdgeRenderingMode.Automatic when this.RendersToPixels:
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var actualThickness = this.GetActualThickness(strokeThickness, edgeRenderingMode);
-                    var snapOffset = GetSnapOffset(actualThickness);
-                    return this.ConvertSnap(rect, snapOffset);
-                default:
-                    return this.Convert(rect);
-            }
-        }
-
-        /// <summary>
-        /// Gets the <see cref="SKRect"/>s that should actually be rendered from the list of <see cref="OxyRect"/>s, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="rects">The rectangles.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual rectangles.</returns>
-        private IEnumerable<SKRect> GetActualRects(IEnumerable<OxyRect> rects, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels:
-                case EdgeRenderingMode.Automatic when this.RendersToPixels:
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var actualThickness = this.GetActualThickness(strokeThickness, edgeRenderingMode);
-                    var snapOffset = GetSnapOffset(actualThickness);
-                    return rects.Select(rect => this.ConvertSnap(rect, snapOffset));
-                default:
-                    return rects.Select(this.Convert);
-            }
-        }
-
-        /// <summary>
-        /// Gets the stroke thickness that should actually be used for rendering, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual stroke thickness.</returns>
-        private float GetActualThickness(double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            var scaledThickness = this.Convert(strokeThickness);
-            if (edgeRenderingMode == EdgeRenderingMode.PreferSharpness && this.RendersToPixels)
-            {
-                scaledThickness = Snap(scaledThickness, 0);
-            }
-
-            return scaledThickness;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render the fill of a shape.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="fillColor">The fill color.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetFillPaint(OxyColor fillColor, EdgeRenderingMode edgeRenderingMode)
-        {
-            this.paint.Color = fillColor.ToSKColor();
-            this.paint.Style = SKPaintStyle.Fill;
-            this.paint.IsAntialias = this.ShouldUseAntiAliasing(edgeRenderingMode);
-            this.paint.PathEffect = null;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render an image.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="opacity">The opacity.</param>
-        /// <param name="interpolate">A value indicating whether interpolation should be used.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetImagePaint(double opacity, bool interpolate)
-        {
-            this.paint.Color = new SKColor(0, 0, 0, (byte)(255 * opacity));
-            this.paint.FilterQuality = interpolate ? SKFilterQuality.High : SKFilterQuality.None;
-            this.paint.IsAntialias = true;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render a line.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="strokeColor">The stroke color.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <param name="dashArray">The dash array.</param>
-        /// <param name="lineJoin">The line join.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetLinePaint(OxyColor strokeColor, double strokeThickness, EdgeRenderingMode edgeRenderingMode, double[] dashArray, LineJoin lineJoin)
-        {
-            var paint = this.GetStrokePaint(strokeColor, strokeThickness, edgeRenderingMode);
-
-            if (dashArray != null)
-            {
-                var actualDashArray = this.ConvertDashArray(dashArray, paint.StrokeWidth);
-                paint.PathEffect = SKPathEffect.CreateDash(actualDashArray, 0);
-            }
-
-            paint.StrokeJoin = lineJoin switch
-            {
-                LineJoin.Miter => SKStrokeJoin.Miter,
-                LineJoin.Round => SKStrokeJoin.Round,
-                LineJoin.Bevel => SKStrokeJoin.Bevel,
-                _ => throw new ArgumentOutOfRangeException(nameof(lineJoin))
-            };
-
-            return paint;
-        }
-
-        /// <summary>
-        /// Gets an empty <see cref="SKPath"/>.
-        /// </summary>
-        /// <remarks>
-        /// This clears and returns the local <see cref="path"/> instance.
-        /// </remarks>
-        /// <returns>The path.</returns>
-        private SKPath GetPath()
-        {
-            this.path.Reset();
-            return this.path;
-        }
-
-        /// <summary>
-        /// Gets the snapping offset for the specified stroke thickness.
-        /// </summary>
-        /// <remarks>
-        /// This takes into account that lines with even stroke thickness should be snapped to the border between two pixels while lines with odd stroke thickness should be snapped to the middle of a pixel.
-        /// </remarks>
-        /// <param name="thickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The snap offset.</returns>
-        private float GetSnapOffset(double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            var actualThickness = this.GetActualThickness(thickness, edgeRenderingMode);
-            return GetSnapOffset(actualThickness);
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render a stroke.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="strokeColor">The stroke color.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetStrokePaint(OxyColor strokeColor, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            this.paint.Color = strokeColor.ToSKColor();
-            this.paint.Style = SKPaintStyle.Stroke;
-            this.paint.IsAntialias = this.ShouldUseAntiAliasing(edgeRenderingMode);
-            this.paint.StrokeWidth = this.GetActualThickness(strokeThickness, edgeRenderingMode);
-            this.paint.PathEffect = null;
-            this.paint.StrokeJoin = SKStrokeJoin.Miter;
-            this.paint.StrokeMiter = this.MiterLimit;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render text.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="fontFamily">The font family.</param>
-        /// <param name="fontSize">The font size.</param>
-        /// <param name="fontWeight">The font weight.</param>
-        /// <param name="shaper">The font shaper.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetTextPaint(string fontFamily, double fontSize, double fontWeight, out SKShaper shaper)
-        {
-            var fontDescriptor = new FontDescriptor(fontFamily, fontWeight);
-            if (!this.typefaceCache.TryGetValue(fontDescriptor, out var typeface))
-            {
-                typeface = SKTypeface.FromFamilyName(fontFamily, new SKFontStyle((int)fontWeight, (int)SKFontStyleWidth.Normal, SKFontStyleSlant.Upright));
-#if NETSTANDARD2_0_OR_GREATER
-                if (typeface.FamilyName != fontFamily) // requested font not found or is WASM
-                {
-                    try
-                    {
-                        var assembly = Assembly.GetEntryAssembly(); // the executing program (the GUI Project (WPF, WASM, ...))
-                        var weight = (_fontWeights.ContainsKey((int)fontWeight) ? _fontWeights[(int)fontWeight] : "Regular");
-                        var filename = $"{fontFamily}-{weight}.ttf".ToLower();
-                        Debug.WriteLine($"Load Font {filename}");
-
-                        var matches = assembly!.GetManifestResourceNames().Where(item => item.ToLower().EndsWith(filename));
-                        if (!matches.Any()) matches = assembly!.GetManifestResourceNames().Where(item => item.ToLower().EndsWith(fontFamily + ".ttf"));
-                        foreach (var item in matches)
-                        {
-                            var s = assembly.GetManifestResourceStream(item);
-                            typeface = SKTypeface.FromStream(s);
-                        }
-                    }
-                    catch
-                    {
-                        Debug.WriteLine($"Requested Font {fontFamily} could not be found, falling back to {typeface.FamilyName}");
-                    }
-                }
-#endif
-                this.typefaceCache.Add(fontDescriptor, typeface);
-            }
-
-            if (this.UseTextShaping)
-            {
-                if (!this.shaperCache.TryGetValue(fontDescriptor, out shaper))
-                {
-                    shaper = new SKShaper(typeface);
-                    this.shaperCache.Add(fontDescriptor, shaper);
-                }
-            }
-            else
-            {
-                shaper = null;
-            }
-
-            this.paint.Typeface = typeface;
-            this.paint.TextSize = this.Convert(fontSize);
-            this.paint.IsAntialias = true;
-            this.paint.Style = SKPaintStyle.Fill;
-            this.paint.HintingLevel = this.RendersToScreen ? SKPaintHinting.Full : SKPaintHinting.NoHinting;
-            this.paint.SubpixelText = this.RendersToScreen;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Measures text using the specified <see cref="SKShaper"/> and <see cref="SKPaint"/>.
-        /// </summary>
-        /// <param name="text">The text to measure.</param>
-        /// <param name="shaper">The text shaper.</param>
-        /// <param name="paint">The paint.</param>
-        /// <returns>The width of the text when rendered using the specified shaper and paint.</returns>
-        private float MeasureText(string text, SKShaper shaper, SKPaint paint)
-        {
-            if (!this.UseTextShaping)
-            {
-                return paint.MeasureText(text);
-            }
-
-            // we have to get a bit creative here as SKShaper does not offer a direct overload for this.
-            // see also https://github.com/mono/SkiaSharp/blob/master/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz.Shared/SKShaper.cs
-            using var buffer = new HarfBuzzSharp.Buffer();
-            switch (paint.TextEncoding)
-            {
-                case SKTextEncoding.Utf8:
-                    buffer.AddUtf8(text);
-                    break;
-                case SKTextEncoding.Utf16:
-                    buffer.AddUtf16(text);
-                    break;
-                case SKTextEncoding.Utf32:
-                    buffer.AddUtf32(text);
-                    break;
-                default:
-                    throw new NotSupportedException("TextEncoding is not supported.");
-            }
-
-            buffer.GuessSegmentProperties();
-            shaper.Shape(buffer, paint);
-            return buffer.GlyphPositions.Sum(gp => gp.XAdvance) * paint.TextSize / 512;
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether anti-aliasing should be used taking in account the specified edge rendering mode.
-        /// </summary>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns><c>true</c> if anti-aliasing should be used; <c>false</c> otherwise.</returns>
-        private bool ShouldUseAntiAliasing(EdgeRenderingMode edgeRenderingMode)
-        {
-            return edgeRenderingMode != EdgeRenderingMode.PreferSpeed;
-        }
-
-        /// <summary>
-        /// Represents a font description.
-        /// </summary>
-        private struct FontDescriptor
-        {
-            /// <summary>
-            /// Initializes a new instance of the <see cref="FontDescriptor"/> struct.
-            /// </summary>
-            /// <param name="fontFamily">The font family.</param>
-            /// <param name="fontWeight">The font weight.</param>
-            public FontDescriptor(string fontFamily, double fontWeight)
-            {
-                this.FontFamily = fontFamily;
-                this.FontWeight = fontWeight;
-            }
-
-            /// <summary>
-            /// The font family.
-            /// </summary>
-            public string FontFamily { get; }
-
-            /// <summary>
-            /// The font weight.
-            /// </summary>
-            public double FontWeight { get; }
-
-            /// <inheritdoc/>
-            public override bool Equals(object obj)
-            {
-                return obj is FontDescriptor other && this.FontFamily == other.FontFamily && this.FontWeight == other.FontWeight;
-            }
-
-            /// <inheritdoc/>
-            public override int GetHashCode()
-            {
-                var hashCode = -1030903623;
-                hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(this.FontFamily);
-                hashCode = hashCode * -1521134295 + this.FontWeight.GetHashCode();
-                return hashCode;
-            }
-        }
-    }
-}

+ 0 - 44
OxyPlot/OxyPlot.SkiaSharp.Wpf/SvgExporter.cs

@@ -1,44 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="SvgExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to scalable vector graphics using the SkiaSharp SVG canvas.
-    /// </summary>
-    public class SvgExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the height (in user units) of the output area.
-        /// </summary>
-        public float Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the width (in user units) of the output area.
-        /// </summary>
-        public float Width { get; set; }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var skStream = new SKManagedWStream(stream);
-            using var canvas = SKSvgCanvas.Create(new SKRect(0, 0, this.Width, this.Height), skStream);
-
-            if (!model.Background.IsInvisible())
-            {
-                canvas.Clear(model.Background.ToSKColor());
-            }
-
-            // SVG export does not work with UseTextShaping=true. However SVG does text shaping by itself anyway, so we can just disable it
-            using var context = new SkiaRenderContext { RenderTarget = RenderTarget.VectorGraphic, SkCanvas = canvas, UseTextShaping = false };
-            model.Update(true);
-            model.Render(context, new OxyRect(0, 0, this.Width, this.Height));
-        }
-    }
-}

+ 0 - 7
OxyPlot/OxyPlot.SkiaSharp.Wpf/VisualStudioToolsManifest.xml

@@ -1,7 +0,0 @@
-<FileList>
-  <File Reference="OxyPlot.SkiaSharp.Wpf">
-    <ToolboxItems UIFramework="WPF" VSCategory="OxyPlot.SkiaSharp.Wpf" BlendCategory="OxyPlot.SkiaSharp.Wpf">
-      <Item Type="OxyPlot.SkiaSharp.Wpf.PlotView" />
-    </ToolboxItems>
-  </File>
-</FileList>

+ 0 - 95
OxyPlot/OxyPlot.SkiaSharp/JpegExporter.cs

@@ -1,95 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="JpegExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to jpeg using the SkiaSharp renderer.
-    /// </summary>
-    public class JpegExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the DPI.
-        /// </summary>
-        public float Dpi { get; set; } = 96;
-
-        /// <summary>
-        /// Gets or sets the export height (in pixels).
-        /// </summary>
-        public int Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export width (in pixels).
-        /// </summary>
-        public int Width { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export quality (0-100).
-        /// </summary>
-        public int Quality { get; set; } = 90;
-
-        /// <summary>
-        /// Exports the specified model to a file.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="quality">The export quality (0-100).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, string path, int width, int height, int quality, float dpi = 96)
-        {
-            using var stream = File.OpenWrite(path);
-            Export(model, stream, width, height, quality, dpi);
-        }
-
-        /// <summary>
-        /// Exports the specified model to a stream.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="stream">The output stream.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="quality">The export quality (0-100).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, Stream stream, int width, int height, int quality, float dpi = 96)
-        {
-            var exporter = new JpegExporter { Width = width, Height = height, Quality = quality, Dpi = dpi };
-            exporter.Export(model, stream);
-        }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var bitmap = new SKBitmap(this.Width, this.Height);
-
-            using (var canvas = new SKCanvas(bitmap))
-            using (var context = new SkiaRenderContext { RenderTarget = RenderTarget.PixelGraphic, SkCanvas = canvas })
-            {
-                canvas.Clear(SKColors.White);
-                var dpiScale = this.Dpi / 96;
-                context.DpiScale = dpiScale;
-                model.Update(true);
-                var backgroundColor = model.Background;
-
-                // jpg doesn't support transparency
-                if (!backgroundColor.IsVisible())
-                {
-                    backgroundColor = OxyColors.White;
-                }
-
-                canvas.Clear(backgroundColor.ToSKColor());
-                model.Render(context, new OxyRect(0, 0, this.Width / dpiScale, this.Height / dpiScale));
-            }
-
-            using var skStream = new SKManagedWStream(stream);
-            bitmap.Encode(skStream, SKEncodedImageFormat.Jpeg, this.Quality);
-        }
-    }
-}

+ 0 - 31
OxyPlot/OxyPlot.SkiaSharp/OxyPlot.SkiaSharp.csproj

@@ -1,31 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <LangVersion>8</LangVersion>
-    <Copyright>Copyright (c) 2020 OxyPlot contributors</Copyright>
-    <TargetFrameworks>netstandard2.0</TargetFrameworks>
-    <Authors>OxyPlot contributors</Authors>
-    <Description>OxyPlot is a plotting library for .NET. This package provides rendering based on SkiaSharp.</Description>
-    <PackageTags>plotting plot charting chart skiasharp skia pdf</PackageTags>
-    <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
-    <GenerateDocumentationFile>False</GenerateDocumentationFile>
-    <SignAssembly>False</SignAssembly>
-    <AssemblyOriginatorKeyFile>OxyPlot.SkiaSharp.snk</AssemblyOriginatorKeyFile>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net462|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net462|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <ItemGroup>
-    <PackageReference Include="SkiaSharp" Version="2.88.9" />
-    <PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.9" />
-  </ItemGroup>
-  <Import Project="..\OxyPlot\OxyPlot.projitems" Label="Shared" />
-</Project>

+ 0 - 71
OxyPlot/OxyPlot.SkiaSharp/PdfExporter.cs

@@ -1,71 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PdfExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to pdf using the SkiaSharp renderer.
-    /// </summary>
-    public class PdfExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the export height (in points, where 1 point equals 1/72 inch).
-        /// </summary>
-        public float Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export width (in points, where 1 point equals 1/72 inch).
-        /// </summary>
-        public float Width { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether text shaping should be used when rendering text.
-        /// </summary>
-        public bool UseTextShaping { get; set; } = true;
-
-        /// <summary>
-        /// Exports the specified model to a file.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        public static void Export(IPlotModel model, string path, float width, float height)
-        {
-            using var stream = File.OpenWrite(path);
-            Export(model, stream, width, height);
-        }
-
-        /// <summary>
-        /// Exports the specified model to a stream.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="stream">The output stream.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        public static void Export(IPlotModel model, Stream stream, float width, float height)
-        {
-            var exporter = new PdfExporter { Width = width, Height = height };
-            exporter.Export(model, stream);
-        }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var document = SKDocument.CreatePdf(stream);
-            using var pdfCanvas = document.BeginPage(this.Width, this.Height);
-            using var context = new SkiaRenderContext { RenderTarget = RenderTarget.VectorGraphic, SkCanvas = pdfCanvas, UseTextShaping = this.UseTextShaping };
-            const float dpiScale = 72f / 96;
-            context.DpiScale = dpiScale;
-            model.Update(true);
-            pdfCanvas.Clear(model.Background.ToSKColor());
-            model.Render(context, new OxyRect(0, 0, this.Width / dpiScale, this.Height / dpiScale));
-        }
-    }
-}

+ 0 - 84
OxyPlot/OxyPlot.SkiaSharp/PngExporter.cs

@@ -1,84 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PngExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to png using the SkiaSharp renderer.
-    /// </summary>
-    public class PngExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the DPI.
-        /// </summary>
-        public float Dpi { get; set; } = 96;
-
-        /// <summary>
-        /// Gets or sets the export height (in pixels).
-        /// </summary>
-        public int Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the export width (in pixels).
-        /// </summary>
-        public int Width { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether text shaping should be used when rendering text.
-        /// </summary>
-        public bool UseTextShaping { get; set; } = true;
-
-        /// <summary>
-        /// Exports the specified model to a file.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, string path, int width, int height, float dpi = 96)
-        {
-            using var stream = File.OpenWrite(path);
-            Export(model, stream, width, height, dpi);
-        }
-
-        /// <summary>
-        /// Exports the specified model to a stream.
-        /// </summary>
-        /// <param name="model">The model.</param>
-        /// <param name="stream">The output stream.</param>
-        /// <param name="width">The width (points).</param>
-        /// <param name="height">The height (points).</param>
-        /// <param name="dpi">The DPI (dots per inch).</param>
-        public static void Export(IPlotModel model, Stream stream, int width, int height, float dpi = 96)
-        {
-            var exporter = new PngExporter { Width = width, Height = height, Dpi = dpi };
-            exporter.Export(model, stream);
-        }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var bitmap = new SKBitmap(this.Width, this.Height);
-
-            using (var canvas = new SKCanvas(bitmap))
-            using (var context = new SkiaRenderContext { RenderTarget = RenderTarget.PixelGraphic, SkCanvas = canvas, UseTextShaping = this.UseTextShaping })
-            {
-                var dpiScale = this.Dpi / 96;
-                context.DpiScale = dpiScale;
-                model.Update(true);
-                canvas.Clear(model.Background.ToSKColor());
-                model.Render(context, new OxyRect(0, 0, this.Width / dpiScale, this.Height / dpiScale));
-            }
-
-            using var skStream = new SKManagedWStream(stream);
-            bitmap.Encode(skStream, SKEncodedImageFormat.Png, 0);
-        }
-    }
-}

+ 0 - 38
OxyPlot/OxyPlot.SkiaSharp/RenderTarget.cs

@@ -1,38 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="RenderTarget.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    /// <summary>
-    /// Defines a render target for <see cref="SkiaRenderContext"/>.
-    /// </summary>
-    public enum RenderTarget
-    {
-        /// <summary>
-        /// Indicates that the <see cref="SkiaRenderContext"/> renders to a screen.
-        /// </summary>
-        /// <remarks>
-        /// The render context may try to snap shapes to device pixels and will use sub-pixel text rendering.
-        /// </remarks>
-        Screen,
-
-        /// <summary>
-        /// Indicates that the <see cref="SkiaRenderContext"/> renders to a pixel graphic.
-        /// </summary>
-        /// <remarks>
-        /// The render context may try to snap shapes to pixels, but will not use sub-pixel text rendering.
-        /// </remarks>
-        PixelGraphic,
-
-        /// <summary>
-        /// Indicates that the <see cref="SkiaRenderContext"/> renders to a vector graphic.
-        /// </summary>
-        /// <remarks>
-        /// The render context will not use any rendering enhancements that are specific to pixel graphics.
-        /// </remarks>
-        VectorGraphic
-    }
-}

+ 0 - 36
OxyPlot/OxyPlot.SkiaSharp/SkiaExtensions.cs

@@ -1,36 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="SkiaExtensions.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-
-    /// <summary>
-    /// Provides extension methods for conversion between SkiaSharp and oxyplot objects.
-    /// </summary>
-    public static class SkiaExtensions
-    {
-        /// <summary>
-        /// Converts a <see cref="OxyColor"/> to a <see cref="SKColor"/>;
-        /// </summary>
-        /// <param name="color">The <see cref="OxyColor"/>.</param>
-        /// <returns>The <see cref="SKColor"/>.</returns>
-        public static OxyColor ToOxyColor(this SKColor color)
-        {
-            return OxyColor.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="SKColor"/> to a <see cref="OxyColor"/>;
-        /// </summary>
-        /// <param name="color">The <see cref="SKColor"/>.</param>
-        /// <returns>The <see cref="OxyColor"/>.</returns>
-        public static SKColor ToSKColor(this OxyColor color)
-        {
-            return new SKColor(color.R, color.G, color.B, color.A);
-        }
-    }
-}

+ 0 - 1008
OxyPlot/OxyPlot.SkiaSharp/SkiaRenderContext.cs

@@ -1,1008 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="SkiaRenderContext.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using global::SkiaSharp.HarfBuzz;
-    using System;
-    using System.Collections.Generic;
-    using System.Diagnostics;
-    using System.Linq;
-    using System.Reflection;
-
-    /// <summary>
-    /// Implements <see cref="IRenderContext" /> based on SkiaSharp.
-    /// </summary>
-    public class SkiaRenderContext : IRenderContext, IDisposable
-    {
-        private readonly Dictionary<FontDescriptor, SKShaper> shaperCache = new Dictionary<FontDescriptor, SKShaper>();
-        private readonly Dictionary<FontDescriptor, SKTypeface> typefaceCache = new Dictionary<FontDescriptor, SKTypeface>();
-        private SKPaint paint = new SKPaint();
-        private SKPath path = new SKPath();
-
-        private readonly Dictionary<int, string> _fontWeights = new Dictionary<int, string>()
-        {
-            [100] = "Thin",
-            [200] = "ExtraLight",
-            [300] = "Light",
-            [400] = "Regular",
-            [500] = "Medium",
-            [600] = "SemiBold",
-            [700] = "Bold",
-            [800] = "ExtraBold",
-            [900] = "Black"
-        };
-
-        /// <summary>
-        /// Gets or sets the DPI scaling factor. A value of 1 corresponds to 96 DPI (dots per inch).
-        /// </summary>
-        public float DpiScale { get; set; } = 1;
-
-        /// <inheritdoc />
-        public bool RendersToScreen => this.RenderTarget == RenderTarget.Screen;
-
-        /// <summary>
-        /// Gets or sets the render target.
-        /// </summary>
-        public RenderTarget RenderTarget { get; set; } = RenderTarget.Screen;
-
-        /// <summary>
-        /// Gets or sets the <see cref="SKCanvas"/> the <see cref="SkiaRenderContext"/> renders to. This must be set before any draw calls.
-        /// </summary>
-        public SKCanvas SkCanvas { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether text shaping should be used when rendering text.
-        /// </summary>
-        public bool UseTextShaping { get; set; } = true;
-
-        /// <summary>
-        /// Gets or sets the Miter limit. This is the maximum ratio between Miter length and stroke thickness. When this ration is exceeded, the join falls back to a Bevel. The default value is 10.
-        /// </summary>
-        public float MiterLimit { get; set; } = 10;
-
-        /// <summary>
-        /// Gets a value indicating whether the context renders to pixels.
-        /// </summary>
-        /// <value><c>true</c> if the context renders to pixels; otherwise, <c>false</c>.</value>
-        private bool RendersToPixels => this.RenderTarget != RenderTarget.VectorGraphic;
-
-        /// <inheritdoc/>
-        public int ClipCount => this.SkCanvas?.SaveCount - 1 ?? 0;
-
-        /// <inheritdoc/>
-        public void CleanUp()
-        {
-        }
-
-        /// <inheritdoc />
-        public void Dispose()
-        {
-            this.Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        /// <inheritdoc/>
-        public void DrawEllipse(OxyRect extents, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0))
-            {
-                return;
-            }
-
-            var actualRect = this.Convert(extents);
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawOval(actualRect, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawOval(actualRect, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawEllipses(IList<OxyRect> extents, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && (!stroke.IsVisible() || thickness <= 0))
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            foreach (var extent in extents)
-            {
-                path.AddOval(this.Convert(extent));
-            }
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawImage(
-            OxyImage source,
-            double srcX,
-            double srcY,
-            double srcWidth,
-            double srcHeight,
-            double destX,
-            double destY,
-            double destWidth,
-            double destHeight,
-            double opacity,
-            bool interpolate)
-        {
-            if (source == null)
-            {
-                return;
-            }
-
-            var bytes = source.GetData();
-            var image = SKBitmap.Decode(bytes);
-
-            var src = new SKRect((float)srcX, (float)srcY, (float)(srcX + srcWidth), (float)(srcY + srcHeight));
-            var dest = new SKRect(this.Convert(destX), this.Convert(destY), this.Convert(destX + destWidth), this.Convert(destY + destHeight));
-
-            var paint = this.GetImagePaint(opacity, interpolate);
-            this.SkCanvas.DrawBitmap(image, src, dest, paint);
-        }
-
-        /// <inheritdoc/>
-        public void DrawLine(
-            IList<ScreenPoint> points,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (points.Count < 2 || !stroke.IsVisible() || thickness <= 0)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-            var actualPoints = this.GetActualPoints(points, thickness, edgeRenderingMode);
-            AddPoints(actualPoints, path);
-
-            this.SkCanvas.DrawPath(path, paint);
-        }
-
-        /// <inheritdoc/>
-        public void DrawLineSegments(
-            IList<ScreenPoint> points,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (points.Count < 2 || !stroke.IsVisible() || thickness <= 0)
-            {
-                return;
-            }
-
-            var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-
-            var skPoints = new SKPoint[points.Count];
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Automatic when this.RendersToPixels:
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels:
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var snapOffset = this.GetSnapOffset(thickness, edgeRenderingMode);
-                    for (var i = 0; i < points.Count - 1; i += 2)
-                    {
-                        var p1 = points[i];
-                        var p2 = points[i + 1];
-                        if (RenderContextBase.IsStraightLine(p1, p2))
-                        {
-                            skPoints[i] = this.ConvertSnap(p1, snapOffset);
-                            skPoints[i + 1] = this.ConvertSnap(p2, snapOffset);
-                        }
-                        else
-                        {
-                            skPoints[i] = this.Convert(p1);
-                            skPoints[i + 1] = this.Convert(p2);
-                        }
-                    }
-
-                    break;
-                default:
-                    for (var i = 0; i < points.Count; i += 2)
-                    {
-                        skPoints[i] = this.Convert(points[i]);
-                        skPoints[i + 1] = this.Convert(points[i + 1]);
-                    }
-
-                    break;
-            }
-
-            this.SkCanvas.DrawPoints(SKPointMode.Lines, skPoints, paint);
-        }
-
-        /// <inheritdoc/>
-        public void DrawPolygon(
-            IList<ScreenPoint> points,
-            OxyColor fill,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0) || points.Count < 2)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            var actualPoints = this.GetActualPoints(points, thickness, edgeRenderingMode);
-            AddPoints(actualPoints, path);
-            path.Close();
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawPolygons(
-            IList<IList<ScreenPoint>> polygons,
-            OxyColor fill,
-            OxyColor stroke,
-            double thickness,
-            EdgeRenderingMode edgeRenderingMode,
-            double[] dashArray = null,
-            LineJoin lineJoin = LineJoin.Miter)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0) || polygons.Count == 0)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            foreach (var polygon in polygons)
-            {
-                if (polygon.Count < 2)
-                {
-                    continue;
-                }
-
-                var actualPoints = this.GetActualPoints(polygon, thickness, edgeRenderingMode);
-                AddPoints(actualPoints, path);
-                path.Close();
-            }
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetLinePaint(stroke, thickness, edgeRenderingMode, dashArray, lineJoin);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawRectangle(OxyRect rectangle, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0))
-            {
-                return;
-            }
-
-            var actualRectangle = this.GetActualRect(rectangle, thickness, edgeRenderingMode);
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawRect(actualRectangle, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawRect(actualRectangle, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawRectangles(IList<OxyRect> rectangles, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            if (!fill.IsVisible() && !(stroke.IsVisible() || thickness <= 0) || rectangles.Count == 0)
-            {
-                return;
-            }
-
-            var path = this.GetPath();
-            foreach (var rectangle in this.GetActualRects(rectangles, thickness, edgeRenderingMode))
-            {
-                path.AddRect(rectangle);
-            }
-
-            if (fill.IsVisible())
-            {
-                var paint = this.GetFillPaint(fill, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-
-            if (stroke.IsVisible() && thickness > 0)
-            {
-                var paint = this.GetStrokePaint(stroke, thickness, edgeRenderingMode);
-                this.SkCanvas.DrawPath(path, paint);
-            }
-        }
-
-        /// <inheritdoc/>
-        public void DrawText(
-            ScreenPoint p,
-            string text,
-            OxyColor fill,
-            string fontFamily = null,
-            double fontSize = 10,
-            double fontWeight = 400,
-            double rotation = 0,
-            HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left,
-            VerticalAlignment verticalAlignment = VerticalAlignment.Top,
-            OxySize? maxSize = null)
-        {
-            if (text == null || !fill.IsVisible())
-            {
-                return;
-            }
-
-            var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper);
-            paint.Color = fill.ToSKColor();
-
-            var x = this.Convert(p.X);
-            var y = this.Convert(p.Y);
-
-            var lines = StringHelper.SplitLines(text);
-            var lineHeight = paint.GetFontMetrics(out var metrics);
-
-            var deltaY = verticalAlignment switch
-            {
-                VerticalAlignment.Top => -metrics.Ascent,
-                VerticalAlignment.Middle => -(metrics.Ascent + metrics.Descent + lineHeight * (lines.Length - 1)) / 2,
-                VerticalAlignment.Bottom => -metrics.Descent - lineHeight * (lines.Length - 1),
-                _ => throw new ArgumentOutOfRangeException(nameof(verticalAlignment))
-            };
-
-            using var _ = new SKAutoCanvasRestore(this.SkCanvas);
-            this.SkCanvas.Translate(x, y);
-            this.SkCanvas.RotateDegrees((float)rotation);
-
-            foreach (var line in lines)
-            {
-                if (this.UseTextShaping)
-                {
-                    var width = this.MeasureText(line, shaper, paint);
-                    var deltaX = horizontalAlignment switch
-                    {
-                        HorizontalAlignment.Left => 0,
-                        HorizontalAlignment.Center => -width / 2,
-                        HorizontalAlignment.Right => -width,
-                        _ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
-                    };
-
-                    this.paint.TextAlign = SKTextAlign.Left;
-                    this.SkCanvas.DrawShapedText(shaper, line, deltaX, deltaY, paint);
-                }
-                else
-                {
-                    paint.TextAlign = horizontalAlignment switch
-                    {
-                        HorizontalAlignment.Left => SKTextAlign.Left,
-                        HorizontalAlignment.Center => SKTextAlign.Center,
-                        HorizontalAlignment.Right => SKTextAlign.Right,
-                        _ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
-                    };
-
-                    this.SkCanvas.DrawText(line, 0, deltaY, paint);
-                }
-
-                deltaY += lineHeight;
-            }
-        }
-
-        /// <inheritdoc/>
-        public OxySize MeasureText(string text, string fontFamily = null, double fontSize = 10, double fontWeight = 500)
-        {
-            if (text == null)
-            {
-                return new OxySize(0, 0);
-            }
-
-            var lines = StringHelper.SplitLines(text);
-            var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper);
-            var height = paint.GetFontMetrics(out _) * lines.Length;
-            var width = lines.Max(line => this.MeasureText(line, shaper, paint)); 
-
-            return new OxySize(this.ConvertBack(width), this.ConvertBack(height));
-        }
-
-        /// <inheritdoc/>
-        public void PopClip()
-        {
-            if (this.SkCanvas.SaveCount == 1)
-            {
-                throw new InvalidOperationException("Unbalanced call to PopClip.");
-            }
-
-            this.SkCanvas.Restore();
-        }
-
-        /// <inheritdoc/>
-        public void PushClip(OxyRect clippingRectangle)
-        {
-            this.SkCanvas.Save();
-            this.SkCanvas.ClipRect(this.Convert(clippingRectangle));
-        }
-
-        /// <inheritdoc/>
-        public void SetToolTip(string text)
-        {
-        }
-
-        /// <summary>
-        /// Disposes managed resources.
-        /// </summary>
-        /// <param name="disposing">A value indicating whether this method is called from the Dispose method.</param>
-        protected virtual void Dispose(bool disposing)
-        {
-            if (!disposing)
-            {
-                return;
-            }
-
-            this.paint?.Dispose();
-            this.paint = null;
-            this.path?.Dispose();
-            this.path = null;
-
-            foreach (var typeface in this.typefaceCache.Values)
-            {
-                typeface.Dispose();
-            }
-
-            this.typefaceCache.Clear();
-
-            foreach (var shaper in this.shaperCache.Values)
-            {
-                shaper.Dispose();
-            }
-
-            this.shaperCache.Clear();
-        }
-
-        /// <summary>
-        /// Adds the <see cref="SKPoint"/>s to the <see cref="SKPath"/> as a series of connected lines.
-        /// </summary>
-        /// <param name="points">The points.</param>
-        /// <param name="path">The path.</param>
-        private static void AddPoints(IEnumerable<SKPoint> points, SKPath path)
-        {
-            using var e = points.GetEnumerator();
-            if (!e.MoveNext())
-            {
-                return;
-            }
-
-            path.MoveTo(e.Current);
-            while (e.MoveNext())
-            {
-                path.LineTo(e.Current);
-            }
-        }
-
-        /// <summary>
-        /// Gets the pixel offset that a line with the specified thickness should snap to.
-        /// </summary>
-        /// <remarks>
-        /// This takes into account that lines with even stroke thickness should be snapped to the border between two pixels while lines with odd stroke thickness should be snapped to the middle of a pixel.
-        /// </remarks>
-        /// <param name="thickness">The line thickness.</param>
-        /// <returns>The snap offset.</returns>
-        private static float GetSnapOffset(float thickness)
-        {
-            var mod = thickness % 2;
-            var isOdd = mod >= 0.5 && mod < 1.5;
-            return isOdd ? 0.5f : 0;
-        }
-
-        /// <summary>
-        /// Snaps a value to a pixel with the specified offset.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <param name="offset">The offset.</param>
-        /// <returns>The snapped value.</returns>
-        private static float Snap(float value, float offset)
-        {
-            return (float)Math.Round(value + offset, MidpointRounding.AwayFromZero) - offset;
-        }
-
-        /// <summary>
-        /// Converts a <see cref="OxyRect"/> to a <see cref="SKRect"/>, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="rect">The rectangle.</param>
-        /// <returns>The converted rectangle.</returns>
-        private SKRect Convert(OxyRect rect)
-        {
-            var left = this.Convert(rect.Left);
-            var right = this.Convert(rect.Right);
-            var top = this.Convert(rect.Top);
-            var bottom = this.Convert(rect.Bottom);
-            return new SKRect(left, top, right, bottom);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="double"/> to a <see cref="float"/>, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>The converted value.</returns>
-        private float Convert(double value)
-        {
-            return (float)value * this.DpiScale;
-        }
-
-        /// <summary>
-        /// Converts <see cref="ScreenPoint"/> to a <see cref="SKPoint"/>, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="point">The point.</param>
-        /// <returns>The converted point.</returns>
-        private SKPoint Convert(ScreenPoint point)
-        {
-            return new SKPoint(this.Convert(point.X), this.Convert(point.Y));
-        }
-
-        /// <summary>
-        /// Converts a <see cref="float"/> to a <see cref="double"/>, applying reversed DPI scaling.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>The converted value.</returns>
-        private double ConvertBack(float value)
-        {
-            return value / this.DpiScale;
-        }
-
-        /// <summary>
-        /// Converts <see cref="double"/> dash array to a <see cref="float"/> array, taking into account DPI scaling.
-        /// </summary>
-        /// <param name="values">The array of values.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <returns>The array of converted values.</returns>
-        private float[] ConvertDashArray(double[] values, float strokeThickness)
-        {
-            var ret = new float[values.Length];
-            for (var i = 0; i < values.Length; i++)
-            {
-                ret[i] = this.Convert(values[i]) * strokeThickness;
-            }
-
-            return ret;
-        }
-
-        /// <summary>
-        /// Converts a <see cref="OxyRect"/> to a <see cref="SKRect"/>, taking into account DPI scaling and snapping the corners to pixels.
-        /// </summary>
-        /// <param name="rect">The rectangle.</param>
-        /// <param name="snapOffset">The snapping offset.</param>
-        /// <returns>The converted rectangle.</returns>
-        private SKRect ConvertSnap(OxyRect rect, float snapOffset)
-        {
-            var left = this.ConvertSnap(rect.Left, snapOffset);
-            var right = this.ConvertSnap(rect.Right, snapOffset);
-            var top = this.ConvertSnap(rect.Top, snapOffset);
-            var bottom = this.ConvertSnap(rect.Bottom, snapOffset);
-            return new SKRect(left, top, right, bottom);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="double"/> to a <see cref="float"/>, taking into account DPI scaling and snapping the value to a pixel.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <param name="snapOffset">The snapping offset.</param>
-        /// <returns>The converted value.</returns>
-        private float ConvertSnap(double value, float snapOffset)
-        {
-            return Snap(this.Convert(value), snapOffset);
-        }
-
-        /// <summary>
-        /// Converts <see cref="ScreenPoint"/> to a <see cref="SKPoint"/>, taking into account DPI scaling and snapping the point to a pixel.
-        /// </summary>
-        /// <param name="point">The point.</param>
-        /// <param name="snapOffset">The snapping offset.</param>
-        /// <returns>The converted point.</returns>
-        private SKPoint ConvertSnap(ScreenPoint point, float snapOffset)
-        {
-            return new SKPoint(this.ConvertSnap(point.X, snapOffset), this.ConvertSnap(point.Y, snapOffset));
-        }
-
-        /// <summary>
-        /// Gets the <see cref="SKPoint"/>s that should actually be rendered from the list of <see cref="ScreenPoint"/>s, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="screenPoints">The points.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual points.</returns>
-        private IEnumerable<SKPoint> GetActualPoints(IList<ScreenPoint> screenPoints, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Automatic when this.RendersToPixels && RenderContextBase.IsStraightLine(screenPoints):
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels && RenderContextBase.IsStraightLine(screenPoints):
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var snapOffset = this.GetSnapOffset(strokeThickness, edgeRenderingMode);
-                    return screenPoints.Select(p => this.ConvertSnap(p, snapOffset));
-                default:
-                    return screenPoints.Select(this.Convert);
-            }
-        }
-
-        /// <summary>
-        /// Gets the <see cref="SKRect"/> that should actually be rendered from the <see cref="OxyRect"/>, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="rect">The rectangle.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual rectangle.</returns>
-        private SKRect GetActualRect(OxyRect rect, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels:
-                case EdgeRenderingMode.Automatic when this.RendersToPixels:
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var actualThickness = this.GetActualThickness(strokeThickness, edgeRenderingMode);
-                    var snapOffset = GetSnapOffset(actualThickness);
-                    return this.ConvertSnap(rect, snapOffset);
-                default:
-                    return this.Convert(rect);
-            }
-        }
-
-        /// <summary>
-        /// Gets the <see cref="SKRect"/>s that should actually be rendered from the list of <see cref="OxyRect"/>s, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="rects">The rectangles.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual rectangles.</returns>
-        private IEnumerable<SKRect> GetActualRects(IEnumerable<OxyRect> rects, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            switch (edgeRenderingMode)
-            {
-                case EdgeRenderingMode.Adaptive when this.RendersToPixels:
-                case EdgeRenderingMode.Automatic when this.RendersToPixels:
-                case EdgeRenderingMode.PreferSharpness when this.RendersToPixels:
-                    var actualThickness = this.GetActualThickness(strokeThickness, edgeRenderingMode);
-                    var snapOffset = GetSnapOffset(actualThickness);
-                    return rects.Select(rect => this.ConvertSnap(rect, snapOffset));
-                default:
-                    return rects.Select(this.Convert);
-            }
-        }
-
-        /// <summary>
-        /// Gets the stroke thickness that should actually be used for rendering, taking into account DPI scaling and snapping if necessary.
-        /// </summary>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The actual stroke thickness.</returns>
-        private float GetActualThickness(double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            var scaledThickness = this.Convert(strokeThickness);
-            if (edgeRenderingMode == EdgeRenderingMode.PreferSharpness && this.RendersToPixels)
-            {
-                scaledThickness = Snap(scaledThickness, 0);
-            }
-
-            return scaledThickness;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render the fill of a shape.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="fillColor">The fill color.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetFillPaint(OxyColor fillColor, EdgeRenderingMode edgeRenderingMode)
-        {
-            this.paint.Color = fillColor.ToSKColor();
-            this.paint.Style = SKPaintStyle.Fill;
-            this.paint.IsAntialias = this.ShouldUseAntiAliasing(edgeRenderingMode);
-            this.paint.PathEffect = null;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render an image.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="opacity">The opacity.</param>
-        /// <param name="interpolate">A value indicating whether interpolation should be used.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetImagePaint(double opacity, bool interpolate)
-        {
-            this.paint.Color = new SKColor(0, 0, 0, (byte)(255 * opacity));
-            this.paint.FilterQuality = interpolate ? SKFilterQuality.High : SKFilterQuality.None;
-            this.paint.IsAntialias = true;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render a line.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="strokeColor">The stroke color.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <param name="dashArray">The dash array.</param>
-        /// <param name="lineJoin">The line join.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetLinePaint(OxyColor strokeColor, double strokeThickness, EdgeRenderingMode edgeRenderingMode, double[] dashArray, LineJoin lineJoin)
-        {
-            var paint = this.GetStrokePaint(strokeColor, strokeThickness, edgeRenderingMode);
-
-            if (dashArray != null)
-            {
-                var actualDashArray = this.ConvertDashArray(dashArray, paint.StrokeWidth);
-                paint.PathEffect = SKPathEffect.CreateDash(actualDashArray, 0);
-            }
-
-            paint.StrokeJoin = lineJoin switch
-            {
-                LineJoin.Miter => SKStrokeJoin.Miter,
-                LineJoin.Round => SKStrokeJoin.Round,
-                LineJoin.Bevel => SKStrokeJoin.Bevel,
-                _ => throw new ArgumentOutOfRangeException(nameof(lineJoin))
-            };
-
-            return paint;
-        }
-
-        /// <summary>
-        /// Gets an empty <see cref="SKPath"/>.
-        /// </summary>
-        /// <remarks>
-        /// This clears and returns the local <see cref="path"/> instance.
-        /// </remarks>
-        /// <returns>The path.</returns>
-        private SKPath GetPath()
-        {
-            this.path.Reset();
-            return this.path;
-        }
-
-        /// <summary>
-        /// Gets the snapping offset for the specified stroke thickness.
-        /// </summary>
-        /// <remarks>
-        /// This takes into account that lines with even stroke thickness should be snapped to the border between two pixels while lines with odd stroke thickness should be snapped to the middle of a pixel.
-        /// </remarks>
-        /// <param name="thickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The snap offset.</returns>
-        private float GetSnapOffset(double thickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            var actualThickness = this.GetActualThickness(thickness, edgeRenderingMode);
-            return GetSnapOffset(actualThickness);
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render a stroke.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="strokeColor">The stroke color.</param>
-        /// <param name="strokeThickness">The stroke thickness.</param>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetStrokePaint(OxyColor strokeColor, double strokeThickness, EdgeRenderingMode edgeRenderingMode)
-        {
-            this.paint.Color = strokeColor.ToSKColor();
-            this.paint.Style = SKPaintStyle.Stroke;
-            this.paint.IsAntialias = this.ShouldUseAntiAliasing(edgeRenderingMode);
-            this.paint.StrokeWidth = this.GetActualThickness(strokeThickness, edgeRenderingMode);
-            this.paint.PathEffect = null;
-            this.paint.StrokeJoin = SKStrokeJoin.Miter;
-            this.paint.StrokeMiter = this.MiterLimit;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Gets a <see cref="SKPaint"/> containing information needed to render text.
-        /// </summary>
-        /// <remarks>
-        /// This modifies and returns the local <see cref="paint"/> instance.
-        /// </remarks>
-        /// <param name="fontFamily">The font family.</param>
-        /// <param name="fontSize">The font size.</param>
-        /// <param name="fontWeight">The font weight.</param>
-        /// <param name="shaper">The font shaper.</param>
-        /// <returns>The paint.</returns>
-        private SKPaint GetTextPaint(string fontFamily, double fontSize, double fontWeight, out SKShaper shaper)
-        {
-            var fontDescriptor = new FontDescriptor(fontFamily, fontWeight);
-            if (!this.typefaceCache.TryGetValue(fontDescriptor, out var typeface))
-            {
-                typeface = SKTypeface.FromFamilyName(fontFamily, new SKFontStyle((int)fontWeight, (int)SKFontStyleWidth.Normal, SKFontStyleSlant.Upright));
-#if NETSTANDARD2_0_OR_GREATER
-                if (typeface.FamilyName != fontFamily) // requested font not found or is WASM
-                {
-                    try
-                    {
-                        var assembly = Assembly.GetEntryAssembly(); // the executing program (the GUI Project (WPF, WASM, ...))
-                        var weight = (_fontWeights.ContainsKey((int)fontWeight) ? _fontWeights[(int)fontWeight] : "Regular");
-                        var filename = $"{fontFamily}-{weight}.ttf".ToLower();
-                        Debug.WriteLine($"Load Font {filename}");
-
-                        var matches = assembly!.GetManifestResourceNames().Where(item => item.ToLower().EndsWith(filename));
-                        if (!matches.Any()) matches = assembly!.GetManifestResourceNames().Where(item => item.ToLower().EndsWith(fontFamily + ".ttf"));
-                        foreach (var item in matches)
-                        {
-                            var s = assembly.GetManifestResourceStream(item);
-                            typeface = SKTypeface.FromStream(s);
-                        }
-                    }
-                    catch
-                    {
-                        Debug.WriteLine($"Requested Font {fontFamily} could not be found, falling back to {typeface.FamilyName}");
-                    }
-                }
-#endif
-                this.typefaceCache.Add(fontDescriptor, typeface);
-            }
-
-            if (this.UseTextShaping)
-            {
-                if (!this.shaperCache.TryGetValue(fontDescriptor, out shaper))
-                {
-                    shaper = new SKShaper(typeface);
-                    this.shaperCache.Add(fontDescriptor, shaper);
-                }
-            }
-            else
-            {
-                shaper = null;
-            }
-
-            this.paint.Typeface = typeface;
-            this.paint.TextSize = this.Convert(fontSize);
-            this.paint.IsAntialias = true;
-            this.paint.Style = SKPaintStyle.Fill;
-            this.paint.HintingLevel = this.RendersToScreen ? SKPaintHinting.Full : SKPaintHinting.NoHinting;
-            this.paint.SubpixelText = this.RendersToScreen;
-            return this.paint;
-        }
-
-        /// <summary>
-        /// Measures text using the specified <see cref="SKShaper"/> and <see cref="SKPaint"/>.
-        /// </summary>
-        /// <param name="text">The text to measure.</param>
-        /// <param name="shaper">The text shaper.</param>
-        /// <param name="paint">The paint.</param>
-        /// <returns>The width of the text when rendered using the specified shaper and paint.</returns>
-        private float MeasureText(string text, SKShaper shaper, SKPaint paint)
-        {
-            if (!this.UseTextShaping)
-            {
-                return paint.MeasureText(text);
-            }
-
-            // we have to get a bit creative here as SKShaper does not offer a direct overload for this.
-            // see also https://github.com/mono/SkiaSharp/blob/master/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz.Shared/SKShaper.cs
-            using var buffer = new HarfBuzzSharp.Buffer();
-            switch (paint.TextEncoding)
-            {
-                case SKTextEncoding.Utf8:
-                    buffer.AddUtf8(text);
-                    break;
-                case SKTextEncoding.Utf16:
-                    buffer.AddUtf16(text);
-                    break;
-                case SKTextEncoding.Utf32:
-                    buffer.AddUtf32(text);
-                    break;
-                default:
-                    throw new NotSupportedException("TextEncoding is not supported.");
-            }
-
-            buffer.GuessSegmentProperties();
-            shaper.Shape(buffer, paint);
-            return buffer.GlyphPositions.Sum(gp => gp.XAdvance) * paint.TextSize / 512;
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether anti-aliasing should be used taking in account the specified edge rendering mode.
-        /// </summary>
-        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
-        /// <returns><c>true</c> if anti-aliasing should be used; <c>false</c> otherwise.</returns>
-        private bool ShouldUseAntiAliasing(EdgeRenderingMode edgeRenderingMode)
-        {
-            return edgeRenderingMode != EdgeRenderingMode.PreferSpeed;
-        }
-
-        /// <summary>
-        /// Represents a font description.
-        /// </summary>
-        private struct FontDescriptor
-        {
-            /// <summary>
-            /// Initializes a new instance of the <see cref="FontDescriptor"/> struct.
-            /// </summary>
-            /// <param name="fontFamily">The font family.</param>
-            /// <param name="fontWeight">The font weight.</param>
-            public FontDescriptor(string fontFamily, double fontWeight)
-            {
-                this.FontFamily = fontFamily;
-                this.FontWeight = fontWeight;
-            }
-
-            /// <summary>
-            /// The font family.
-            /// </summary>
-            public string FontFamily { get; }
-
-            /// <summary>
-            /// The font weight.
-            /// </summary>
-            public double FontWeight { get; }
-
-            /// <inheritdoc/>
-            public override bool Equals(object obj)
-            {
-                return obj is FontDescriptor other && this.FontFamily == other.FontFamily && this.FontWeight == other.FontWeight;
-            }
-
-            /// <inheritdoc/>
-            public override int GetHashCode()
-            {
-                var hashCode = -1030903623;
-                hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(this.FontFamily);
-                hashCode = hashCode * -1521134295 + this.FontWeight.GetHashCode();
-                return hashCode;
-            }
-        }
-    }
-}

+ 0 - 44
OxyPlot/OxyPlot.SkiaSharp/SvgExporter.cs

@@ -1,44 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="SvgExporter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.SkiaSharp
-{
-    using global::SkiaSharp;
-    using System.IO;
-
-    /// <summary>
-    /// Provides functionality to export plots to scalable vector graphics using the SkiaSharp SVG canvas.
-    /// </summary>
-    public class SvgExporter : IExporter
-    {
-        /// <summary>
-        /// Gets or sets the height (in user units) of the output area.
-        /// </summary>
-        public float Height { get; set; }
-
-        /// <summary>
-        /// Gets or sets the width (in user units) of the output area.
-        /// </summary>
-        public float Width { get; set; }
-
-        /// <inheritdoc/>
-        public void Export(IPlotModel model, Stream stream)
-        {
-            using var skStream = new SKManagedWStream(stream);
-            using var canvas = SKSvgCanvas.Create(new SKRect(0, 0, this.Width, this.Height), skStream);
-
-            if (!model.Background.IsInvisible())
-            {
-                canvas.Clear(model.Background.ToSKColor());
-            }
-
-            // SVG export does not work with UseTextShaping=true. However SVG does text shaping by itself anyway, so we can just disable it
-            using var context = new SkiaRenderContext { RenderTarget = RenderTarget.VectorGraphic, SkCanvas = canvas, UseTextShaping = false };
-            model.Update(true);
-            model.Render(context, new OxyRect(0, 0, this.Width, this.Height));
-        }
-    }
-}

+ 0 - 11
OxyPlot/OxyPlot.Wpf.Shared/AssemblyInfo.cs

@@ -1,11 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="AssemblyInfo.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-using System.Windows;
-using System.Windows.Markup;
-
-[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
-[assembly: XmlnsDefinition("http://oxyplot.org/wpf", "OxyPlot.Wpf")]

+ 0 - 75
OxyPlot/OxyPlot.Wpf.Shared/Converters/OxyColorConverter.cs

@@ -1,75 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="OxyColorConverter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Converts between <see cref="OxyColor" /> and <see cref="Color" />.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System;
-    using System.Globalization;
-    using System.Windows.Data;
-    using System.Windows.Media;
-
-    /// <summary>
-    /// Converts between <see cref="OxyColor" /> and <see cref="Color" />.
-    /// </summary>
-    [ValueConversion(typeof(OxyColor), typeof(Color))]
-    public class OxyColorConverter : IValueConverter
-    {
-        /// <summary>
-        /// Converts a value.
-        /// </summary>
-        /// <param name="value">The value produced by the binding source.</param>
-        /// <param name="targetType">The type of the binding target property.</param>
-        /// <param name="parameter">The converter parameter to use.</param>
-        /// <param name="culture">The culture to use in the converter.</param>
-        /// <returns>A converted value. If the method returns <c>null</c>, the valid <c>null</c> value is used.</returns>
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            if (value is OxyColor color)
-            {
-                if (targetType == typeof(Color))
-                {
-                    return color.ToColor();
-                }
-
-                if (targetType == typeof(Brush))
-                {
-                    return color.ToBrush();
-                }
-            }
-
-            return null;
-        }
-
-        /// <summary>
-        /// Converts a value.
-        /// </summary>
-        /// <param name="value">The value that is produced by the binding target.</param>
-        /// <param name="targetType">The type to convert to.</param>
-        /// <param name="parameter">The converter parameter to use.</param>
-        /// <param name="culture">The culture to use in the converter.</param>
-        /// <returns>A converted value. If the method returns <c>null</c>, the valid <c>null</c> value is used.</returns>
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            if (targetType == typeof(OxyColor))
-            {
-                if (value is Color color)
-                {
-                    return OxyColor.FromArgb(color.A, color.R, color.G, color.B);
-                }
-
-                if (value is SolidColorBrush brush)
-                {
-                    return OxyColor.FromArgb(brush.Color.A, brush.Color.R, brush.Color.G, brush.Color.B);
-                }
-            }
-
-            return null;
-        }
-    }
-}

+ 0 - 55
OxyPlot/OxyPlot.Wpf.Shared/Converters/ThicknessConverter.cs

@@ -1,55 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="ThicknessConverter.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Converts from <see cref="Thickness" /> to the maximum thicknesses.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System;
-    using System.Globalization;
-    using System.Windows;
-    using System.Windows.Data;
-
-    /// <summary>
-    /// Converts from <see cref="Thickness" /> to the maximum thicknesses.
-    /// </summary>
-    /// <remarks>This is used in the <see cref="TrackerControl" /> to convert BorderThickness properties to Path.StrokeThickness (double).
-    /// The maximum thickness value is used.</remarks>
-    public class ThicknessConverter : IValueConverter
-    {
-        /// <summary>
-        /// Converts a value.
-        /// </summary>
-        /// <param name="value">The value produced by the binding source.</param>
-        /// <param name="targetType">The type of the binding target property.</param>
-        /// <param name="parameter">The converter parameter to use.</param>
-        /// <param name="culture">The culture to use in the converter.</param>
-        /// <returns>A converted value. If the method returns <c>null</c>, the valid <c>null</c> value is used.</returns>
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            if (value is Thickness t && targetType == typeof(double))
-            {
-                return Math.Max(Math.Max(t.Left, t.Right), Math.Max(t.Top, t.Bottom));
-            }
-
-            return null;
-        }
-
-        /// <summary>
-        /// Converts a value.
-        /// </summary>
-        /// <param name="value">The value that is produced by the binding target.</param>
-        /// <param name="targetType">The type to convert to.</param>
-        /// <param name="parameter">The converter parameter to use.</param>
-        /// <param name="culture">The culture to use in the converter.</param>
-        /// <returns>A converted value. If the method returns <c>null</c>, the valid <c>null</c> value is used.</returns>
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return null;
-        }
-    }
-}

+ 0 - 31
OxyPlot/OxyPlot.Wpf.Shared/ExporterExtensions.cs

@@ -1,31 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="ExporterExtensions.cs" company="OxyPlot">
-//   Copyright (c) 2014 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Provides extension methods for exporters.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System.IO;
-
-    /// <summary>
-    /// Provides extension methods for exporters.
-    /// </summary>
-    public static class ExporterExtensions
-    {
-        /// <summary>
-        /// Exports the specified <see cref="PlotModel" /> to a file.
-        /// </summary>
-        /// <param name="exporter">The exporter.</param>
-        /// <param name="model">The model to export.</param>
-        /// <param name="path">The path to the file.</param>
-        public static void ExportToFile(this IExporter exporter, IPlotModel model, string path)
-        {
-            using var stream = File.OpenWrite(path);
-            exporter.Export(model, stream);
-        }
-    }
-}

+ 0 - 29
OxyPlot/OxyPlot.Wpf.Shared/MoreColors.cs

@@ -1,29 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="MoreColors.cs" company="OxyPlot">
-//   Copyright (c) 2014 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Defines additional <see cref="Colors" />.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System.Windows.Media;
-
-    /// <summary>
-    /// Defines additional <see cref="Colors" />.
-    /// </summary>
-    public static class MoreColors
-    {
-        /// <summary>
-        /// The undefined color.
-        /// </summary>
-        public static readonly Color Undefined = Color.FromArgb(0, 0, 0, 0);
-
-        /// <summary>
-        /// The automatic color.
-        /// </summary>
-        public static readonly Color Automatic = Color.FromArgb(0, 0, 0, 1);
-    }
-}

+ 0 - 32
OxyPlot/OxyPlot.Wpf.Shared/OxyPlot.Wpf.Shared.csproj

@@ -1,32 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
-    <UseWPF>true</UseWPF>
-    <LangVersion>8</LangVersion>
-    <Description>OxyPlot is a plotting library for .NET. This package is the base for WPF PlotView implementations.</Description>
-    <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
-    <GenerateDocumentationFile>False</GenerateDocumentationFile>
-    <PackageTags>plotting plot charting chart wpf</PackageTags>
-    <SignAssembly>False</SignAssembly>
-    <AssemblyOriginatorKeyFile>OxyPlot.Wpf.Shared.snk</AssemblyOriginatorKeyFile>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net462|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net462|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-windows|AnyCPU'">
-    <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
-  </PropertyGroup>
-  <Import Project="..\OxyPlot\OxyPlot.projitems" Label="Shared" />
-</Project>

+ 0 - 24
OxyPlot/OxyPlot.Wpf.Shared/PlotCommands.cs

@@ -1,24 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PlotCommands.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Provides a standard set of commands for the <see cref="PlotView" /> control.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System.Windows.Input;
-
-    /// <summary>
-    /// Provides a standard set of commands for the <see cref="PlotViewBase" /> control.
-    /// </summary>
-    public static class PlotCommands
-    {
-        /// <summary>
-        /// Gets the value that represents the "Reset all axes" command.
-        /// </summary>
-        public static readonly ICommand ResetAxes = new RoutedUICommand("Reset all axes", "ResetAxes", typeof(PlotViewBase));
-    }
-}

+ 0 - 197
OxyPlot/OxyPlot.Wpf.Shared/PlotViewBase.Events.cs

@@ -1,197 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PlotViewBase.Events.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System;
-    using System.Windows.Input;
-
-    /// <summary>
-    /// Base class for WPF PlotView implementations.
-    /// </summary>
-    public abstract partial class PlotViewBase
-    {
-        /// <summary>
-        /// Called before the <see cref="E:System.Windows.UIElement.KeyDown" /> event occurs.
-        /// </summary>
-        /// <param name="e">The data for the event.</param>
-        protected override void OnKeyDown(KeyEventArgs e)
-        {
-            base.OnKeyDown(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            var args = new OxyKeyEventArgs { ModifierKeys = Keyboard.GetModifierKeys(), Key = e.Key.Convert() };
-            e.Handled = this.ActualController.HandleKeyDown(this, args);
-        }
-
-        /// <summary>
-        /// Called when the <see cref="E:System.Windows.UIElement.ManipulationStarted" /> event occurs.
-        /// </summary>
-        /// <param name="e">The data for the event.</param>
-        protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
-        {
-            base.OnManipulationStarted(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleTouchStarted(this, e.ToTouchEventArgs(this));
-        }
-
-        /// <summary>
-        /// Called when the <see cref="E:System.Windows.UIElement.ManipulationDelta" /> event occurs.
-        /// </summary>
-        /// <param name="e">The data for the event.</param>
-        protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
-        {
-            base.OnManipulationDelta(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleTouchDelta(this, e.ToTouchEventArgs(this));
-        }
-
-        /// <summary>
-        /// Called when the <see cref="E:System.Windows.UIElement.ManipulationCompleted" /> event occurs.
-        /// </summary>
-        /// <param name="e">The data for the event.</param>
-        protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
-        {
-            base.OnManipulationCompleted(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleTouchCompleted(this, e.ToTouchEventArgs(this));
-        }
-
-        /// <summary>
-        /// Called before the <see cref="E:System.Windows.UIElement.MouseWheel" /> event occurs to provide handling for the event in a derived class without attaching a delegate.
-        /// </summary>
-        /// <param name="e">A <see cref="T:System.Windows.Input.MouseWheelEventArgs" /> that contains the event data.</param>
-        protected override void OnMouseWheel(MouseWheelEventArgs e)
-        {
-            base.OnMouseWheel(e);
-            if (e.Handled || !this.IsMouseWheelEnabled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleMouseWheel(this, e.ToMouseWheelEventArgs(this));
-        }
-
-        /// <summary>
-        /// Invoked when an unhandled MouseDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
-        /// </summary>
-        /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. This event data reports details about the mouse button that was pressed and the handled state.</param>
-        protected override void OnMouseDown(MouseButtonEventArgs e)
-        {
-            base.OnMouseDown(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            this.Focus();
-            this.CaptureMouse();
-
-            // store the mouse down point, check it when mouse button is released to determine if the context menu should be shown
-            this.mouseDownPoint = e.GetPosition(this).ToScreenPoint();
-
-            e.Handled = this.ActualController.HandleMouseDown(this, e.ToMouseDownEventArgs(this));
-        }
-
-        /// <summary>
-        /// Invoked when an unhandled MouseMove attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
-        /// </summary>
-        /// <param name="e">The <see cref="T:System.Windows.Input.MouseEventArgs" /> that contains the event data.</param>
-        protected override void OnMouseMove(MouseEventArgs e)
-        {
-            base.OnMouseMove(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleMouseMove(this, e.ToMouseEventArgs(this));
-        }
-
-        /// <summary>
-        /// Invoked when an unhandled MouseUp routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
-        /// </summary>
-        /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. The event data reports that the mouse button was released.</param>
-        protected override void OnMouseUp(MouseButtonEventArgs e)
-        {
-            base.OnMouseUp(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            this.ReleaseMouseCapture();
-
-            e.Handled = this.ActualController.HandleMouseUp(this, e.ToMouseReleasedEventArgs(this));
-
-            // Open the context menu
-            var p = e.GetPosition(this).ToScreenPoint();
-            var d = p.DistanceTo(this.mouseDownPoint);
-
-            if (this.ContextMenu != null)
-            {
-                if (Math.Abs(d) < 1e-8 && e.ChangedButton == MouseButton.Right)
-                {
-                    // TODO: why is the data context not passed to the context menu??
-                    this.ContextMenu.DataContext = this.DataContext;
-                    this.ContextMenu.PlacementTarget = this;
-                    this.ContextMenu.Visibility = System.Windows.Visibility.Visible;
-                    this.ContextMenu.IsOpen = true;
-                }
-                else
-                {
-                    this.ContextMenu.Visibility = System.Windows.Visibility.Collapsed;
-                    this.ContextMenu.IsOpen = false;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.MouseEnter" /> attached event is raised on this element. Implement this method to add class handling for this event.
-        /// </summary>
-        /// <param name="e">The <see cref="T:System.Windows.Input.MouseEventArgs" /> that contains the event data.</param>
-        protected override void OnMouseEnter(MouseEventArgs e)
-        {
-            base.OnMouseEnter(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleMouseEnter(this, e.ToMouseEventArgs(this));
-        }
-
-        /// <summary>
-        /// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.MouseLeave" /> attached event is raised on this element. Implement this method to add class handling for this event.
-        /// </summary>
-        /// <param name="e">The <see cref="T:System.Windows.Input.MouseEventArgs" /> that contains the event data.</param>
-        protected override void OnMouseLeave(MouseEventArgs e)
-        {
-            base.OnMouseEnter(e);
-            if (e.Handled)
-            {
-                return;
-            }
-
-            e.Handled = this.ActualController.HandleMouseLeave(this, e.ToMouseEventArgs(this));
-        }
-    }
-}

+ 0 - 165
OxyPlot/OxyPlot.Wpf.Shared/PlotViewBase.Properties.cs

@@ -1,165 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PlotViewBase.Properties.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System.Windows;
-    using System.Windows.Controls;
-    using System.Windows.Input;
-
-    /// <summary>
-    /// Base class for WPF PlotView implementations.
-    /// </summary>
-    public abstract partial class PlotViewBase
-    {
-        /// <summary>
-        /// Identifies the <see cref="Controller"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ControllerProperty =
-            DependencyProperty.Register(nameof(Controller), typeof(IPlotController), typeof(PlotViewBase));
-
-        /// <summary>
-        /// Identifies the <see cref="DefaultTrackerTemplate"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty DefaultTrackerTemplateProperty =
-            DependencyProperty.Register(
-                nameof(DefaultTrackerTemplate), typeof(ControlTemplate), typeof(PlotViewBase), new PropertyMetadata(null));
-
-        /// <summary>
-        /// Identifies the <see cref="IsMouseWheelEnabled"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty IsMouseWheelEnabledProperty =
-            DependencyProperty.Register(nameof(IsMouseWheelEnabled), typeof(bool), typeof(PlotViewBase), new PropertyMetadata(true));
-
-        /// <summary>
-        /// Identifies the <see cref="Model"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ModelProperty =
-            DependencyProperty.Register(nameof(Model), typeof(PlotModel), typeof(PlotViewBase), new PropertyMetadata(null, ModelChanged));
-
-        /// <summary>
-        /// Identifies the <see cref="PanCursor"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty PanCursorProperty = DependencyProperty.Register(
-            nameof(PanCursor), typeof(Cursor), typeof(PlotViewBase), new PropertyMetadata(Cursors.Hand));
-
-        /// <summary>
-        /// Identifies the <see cref="ZoomHorizontalCursor"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ZoomHorizontalCursorProperty =
-            DependencyProperty.Register(
-                nameof(ZoomHorizontalCursor), typeof(Cursor), typeof(PlotViewBase), new PropertyMetadata(Cursors.SizeWE));
-
-        /// <summary>
-        /// Identifies the <see cref="ZoomRectangleCursor"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ZoomRectangleCursorProperty =
-            DependencyProperty.Register(
-                nameof(ZoomRectangleCursor), typeof(Cursor), typeof(PlotViewBase), new PropertyMetadata(Cursors.SizeNWSE));
-
-        /// <summary>
-        /// Identifies the <see cref="ZoomRectangleTemplate"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ZoomRectangleTemplateProperty =
-            DependencyProperty.Register(
-                nameof(ZoomRectangleTemplate), typeof(ControlTemplate), typeof(PlotViewBase), new PropertyMetadata(null));
-
-        /// <summary>
-        /// Identifies the <see cref="ZoomVerticalCursor"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ZoomVerticalCursorProperty =
-            DependencyProperty.Register(
-                nameof(ZoomVerticalCursor), typeof(Cursor), typeof(PlotViewBase), new PropertyMetadata(Cursors.SizeNS));
-
-        /// <summary>
-        /// Gets or sets the Plot controller.
-        /// </summary>
-        /// <value>The Plot controller.</value>
-        public IPlotController Controller
-        {
-            get => (IPlotController)this.GetValue(ControllerProperty);
-            set => this.SetValue(ControllerProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the default tracker template.
-        /// </summary>
-        public ControlTemplate DefaultTrackerTemplate
-        {
-            get => (ControlTemplate)this.GetValue(DefaultTrackerTemplateProperty);
-            set => this.SetValue(DefaultTrackerTemplateProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether IsMouseWheelEnabled.
-        /// </summary>
-        public bool IsMouseWheelEnabled
-        {
-            get => (bool)this.GetValue(IsMouseWheelEnabledProperty);
-            set => this.SetValue(IsMouseWheelEnabledProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the model.
-        /// </summary>
-        /// <value>The model.</value>
-        public PlotModel Model
-        {
-            get => (PlotModel)this.GetValue(ModelProperty);
-            set => this.SetValue(ModelProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the pan cursor.
-        /// </summary>
-        /// <value>The pan cursor.</value>
-        public Cursor PanCursor
-        {
-            get => (Cursor)this.GetValue(PanCursorProperty);
-            set => this.SetValue(PanCursorProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the horizontal zoom cursor.
-        /// </summary>
-        /// <value>The zoom horizontal cursor.</value>
-        public Cursor ZoomHorizontalCursor
-        {
-            get => (Cursor)this.GetValue(ZoomHorizontalCursorProperty);
-            set => this.SetValue(ZoomHorizontalCursorProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the rectangle zoom cursor.
-        /// </summary>
-        /// <value>The zoom rectangle cursor.</value>
-        public Cursor ZoomRectangleCursor
-        {
-            get => (Cursor)this.GetValue(ZoomRectangleCursorProperty);
-            set => this.SetValue(ZoomRectangleCursorProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the zoom rectangle template.
-        /// </summary>
-        /// <value>The zoom rectangle template.</value>
-        public ControlTemplate ZoomRectangleTemplate
-        {
-            get => (ControlTemplate)this.GetValue(ZoomRectangleTemplateProperty);
-            set => this.SetValue(ZoomRectangleTemplateProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the vertical zoom cursor.
-        /// </summary>
-        /// <value>The zoom vertical cursor.</value>
-        public Cursor ZoomVerticalCursor
-        {
-            get => (Cursor)this.GetValue(ZoomVerticalCursorProperty);
-            set => this.SetValue(ZoomVerticalCursorProperty, value);
-        }
-    }
-}

+ 0 - 489
OxyPlot/OxyPlot.Wpf.Shared/PlotViewBase.cs

@@ -1,489 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="PlotViewBase.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using OxyPlot;
-    using System;
-    using System.Collections.ObjectModel;
-    using System.Linq;
-    using System.Windows;
-    using System.Windows.Controls;
-    using System.Windows.Controls.Primitives;
-    using System.Windows.Input;
-    using System.Windows.Media;
-    using System.Windows.Threading;
-    using System.Windows.Documents;
-    using CursorType = OxyPlot.CursorType;
-
-    /// <summary>
-    /// Base class for WPF PlotView implementations.
-    /// </summary>
-    [TemplatePart(Name = PartGrid, Type = typeof(Grid))]
-    public abstract partial class PlotViewBase : Control, IPlotView
-    {
-        /// <summary>
-        /// The Grid PART constant.
-        /// </summary>
-        protected const string PartGrid = "PART_Grid";
-
-        /// <summary>
-        /// The grid.
-        /// </summary>
-        protected Grid grid;
-
-        /// <summary>
-        /// The plot presenter.
-        /// </summary>
-        protected FrameworkElement plotPresenter;
-
-        /// <summary>
-        /// The render context
-        /// </summary>
-        protected IRenderContext renderContext;
-
-        /// <summary>
-        /// The model lock.
-        /// </summary>
-        private readonly object modelLock = new object();
-
-        /// <summary>
-        /// The current tracker.
-        /// </summary>
-        private FrameworkElement currentTracker;
-
-        /// <summary>
-        /// The current tracker template.
-        /// </summary>
-        private ControlTemplate currentTrackerTemplate;
-
-        /// <summary>
-        /// The default plot controller.
-        /// </summary>
-        private IPlotController defaultController;
-
-        /// <summary>
-        /// Indicates whether the <see cref="PlotViewBase"/> was in the visual tree the last time <see cref="Render"/> was called.
-        /// </summary>
-        private bool isInVisualTree;
-
-        /// <summary>
-        /// The mouse down point.
-        /// </summary>
-        private ScreenPoint mouseDownPoint;
-
-        /// <summary>
-        /// The overlays.
-        /// </summary>
-        private Canvas overlays;
-
-        /// <summary>
-        /// The zoom control.
-        /// </summary>
-        private ContentControl zoomControl;
-
-        /// <summary>
-        /// Initializes static members of the <see cref="PlotViewBase" /> class.
-        /// </summary>
-        static PlotViewBase()
-        {
-            DefaultStyleKeyProperty.OverrideMetadata(typeof(PlotViewBase), new FrameworkPropertyMetadata(typeof(PlotViewBase)));
-            PaddingProperty.OverrideMetadata(typeof(PlotViewBase), new FrameworkPropertyMetadata(new Thickness(8)));
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="PlotViewBase" /> class.
-        /// </summary>
-        protected PlotViewBase()
-        {
-            this.TrackerDefinitions = new ObservableCollection<TrackerDefinition>();
-            this.CommandBindings.Add(new CommandBinding(PlotCommands.ResetAxes, (s, e) => this.ResetAllAxes()));
-            this.IsManipulationEnabled = true;
-            this.LayoutUpdated += this.OnLayoutUpdated;
-        }
-
-        /// <summary>
-        /// Gets the actual PlotView controller.
-        /// </summary>
-        /// <value>The actual PlotView controller.</value>
-        public IPlotController ActualController => this.Controller ?? (this.defaultController ??= new PlotController());
-
-        /// <inheritdoc/>
-        IController IView.ActualController => this.ActualController;
-
-        /// <summary>
-        /// Gets the actual model.
-        /// </summary>
-        /// <value>The actual model.</value>
-        public PlotModel ActualModel { get; private set; }
-
-        /// <inheritdoc/>
-        Model IView.ActualModel => this.ActualModel;
-
-        /// <summary>
-        /// Gets the coordinates of the client area of the view.
-        /// </summary>
-        public OxyRect ClientArea => new OxyRect(0, 0, this.ActualWidth, this.ActualHeight);
-
-        /// <summary>
-        /// Gets the tracker definitions.
-        /// </summary>
-        /// <value>The tracker definitions.</value>
-        public ObservableCollection<TrackerDefinition> TrackerDefinitions { get; }
-
-        /// <summary>
-        /// Hides the tracker.
-        /// </summary>
-        public void HideTracker()
-        {
-            if (this.currentTracker != null)
-            {
-                this.overlays.Children.Remove(this.currentTracker);
-                this.currentTracker = null;
-                this.currentTrackerTemplate = null;
-            }
-        }
-
-        /// <summary>
-        /// Hides the zoom rectangle.
-        /// </summary>
-        public void HideZoomRectangle()
-        {
-            this.zoomControl.Visibility = Visibility.Collapsed;
-        }
-
-        /// <summary>
-        /// Invalidate the PlotView (not blocking the UI thread)
-        /// </summary>
-        /// <param name="updateData">The update Data.</param>
-        public void InvalidatePlot(bool updateData = true)
-        {
-            if (this.ActualModel == null)
-            {
-                return;
-            }
-
-            lock (this.ActualModel.SyncRoot)
-            {
-                ((IPlotModel)this.ActualModel).Update(updateData);
-            }
-
-            this.BeginInvoke(this.Render);
-        }
-
-        /// <inheritdoc/>
-        public override void OnApplyTemplate()
-        {
-            base.OnApplyTemplate();
-            this.grid = this.GetTemplateChild(PartGrid) as Grid;
-            if (this.grid == null)
-            {
-                return;
-            }
-
-            this.plotPresenter = this.CreatePlotPresenter();
-            this.grid.Children.Add(this.plotPresenter);
-            this.plotPresenter.UpdateLayout();
-            this.renderContext = this.CreateRenderContext();
-
-            this.overlays = new Canvas();
-            this.grid.Children.Add(this.overlays);
-
-            this.zoomControl = new ContentControl();
-            this.zoomControl.Focusable = false;
-            this.overlays.Children.Add(this.zoomControl);
-
-            // add additional grid on top of everthing else to fix issue of mouse events getting lost
-            // it must be added last so it covers all other controls
-            var mouseGrid = new Grid
-            {
-                Background = Brushes.Transparent // background must be set for hit test to work
-            };
-            this.grid.Children.Add(mouseGrid);
-        }
-
-        /// <summary>
-        /// Pans all axes.
-        /// </summary>
-        /// <param name="delta">The delta.</param>
-        public void PanAllAxes(Vector delta)
-        {
-            if (this.ActualModel != null)
-            {
-                this.ActualModel.PanAllAxes(delta.X, delta.Y);
-            }
-
-            this.InvalidatePlot(false);
-        }
-
-        /// <summary>
-        /// Resets all axes.
-        /// </summary>
-        public void ResetAllAxes()
-        {
-            if (this.ActualModel != null)
-            {
-                this.ActualModel.ResetAllAxes();
-            }
-
-            this.InvalidatePlot(false);
-        }
-
-        /// <summary>
-        /// Stores text on the clipboard.
-        /// </summary>
-        /// <param name="text">The text.</param>
-        public void SetClipboardText(string text)
-        {
-            Clipboard.SetText(text);
-        }
-
-        /// <summary>
-        /// Sets the cursor type.
-        /// </summary>
-        /// <param name="cursorType">The cursor type.</param>
-        public void SetCursorType(CursorType cursorType)
-        {
-            this.Cursor = cursorType switch
-            {
-                CursorType.Pan => this.PanCursor,
-                CursorType.ZoomRectangle => this.ZoomRectangleCursor,
-                CursorType.ZoomHorizontal => this.ZoomHorizontalCursor,
-                CursorType.ZoomVertical => this.ZoomVerticalCursor,
-                _ => Cursors.Arrow,
-            };
-        }
-
-        /// <summary>
-        /// Shows the tracker.
-        /// </summary>
-        /// <param name="trackerHitResult">The tracker data.</param>
-        public void ShowTracker(TrackerHitResult trackerHitResult)
-        {
-            if (trackerHitResult == null)
-            {
-                this.HideTracker();
-                return;
-            }
-
-            var trackerTemplate = this.DefaultTrackerTemplate;
-            if (trackerHitResult.Series != null && !string.IsNullOrEmpty(trackerHitResult.Series.TrackerKey))
-            {
-                var match = this.TrackerDefinitions.FirstOrDefault(t => t.TrackerKey == trackerHitResult.Series.TrackerKey);
-                if (match != null)
-                {
-                    trackerTemplate = match.TrackerTemplate;
-                }
-            }
-
-            if (trackerTemplate == null)
-            {
-                this.HideTracker();
-                return;
-            }
-
-            if (!ReferenceEquals(trackerTemplate, this.currentTrackerTemplate))
-            {
-                this.HideTracker();
-
-                var tracker = new ContentControl { Template = trackerTemplate };
-                this.overlays.Children.Add(tracker);
-                this.currentTracker = tracker;
-                this.currentTrackerTemplate = trackerTemplate;
-            }
-
-            if (this.currentTracker != null)
-            {
-                this.currentTracker.DataContext = trackerHitResult;
-            }
-        }
-
-        /// <summary>
-        /// Shows the zoom rectangle.
-        /// </summary>
-        /// <param name="r">The rectangle.</param>
-        public void ShowZoomRectangle(OxyRect r)
-        {
-            this.zoomControl.Width = r.Width;
-            this.zoomControl.Height = r.Height;
-            Canvas.SetLeft(this.zoomControl, r.Left);
-            Canvas.SetTop(this.zoomControl, r.Top);
-            this.zoomControl.Template = this.ZoomRectangleTemplate;
-            this.zoomControl.Visibility = Visibility.Visible;
-        }
-
-        /// <summary>
-        /// Zooms all axes.
-        /// </summary>
-        /// <param name="factor">The zoom factor.</param>
-        public void ZoomAllAxes(double factor)
-        {
-            if (this.ActualModel != null)
-            {
-                this.ActualModel.ZoomAllAxes(factor);
-            }
-
-            this.InvalidatePlot(false);
-        }
-
-        /// <summary>
-        /// Clears the background of the plot presenter.
-        /// </summary>
-        protected abstract void ClearBackground();
-
-        /// <summary>
-        /// Creates the plot presenter.
-        /// </summary>
-        /// <returns>The plot presenter.</returns>
-        protected abstract FrameworkElement CreatePlotPresenter();
-
-        /// <summary>
-        /// Creates the render context.
-        /// </summary>
-        /// <returns>The render context.</returns>
-        protected abstract IRenderContext CreateRenderContext();
-
-        /// <summary>
-        /// Called when the model is changed.
-        /// </summary>
-        protected void OnModelChanged()
-        {
-            lock (this.modelLock)
-            {
-                if (this.ActualModel != null)
-                {
-                    ((IPlotModel)this.ActualModel).AttachPlotView(null);
-                    this.ActualModel = null;
-                }
-
-                if (this.Model != null)
-                {
-                    ((IPlotModel)this.Model).AttachPlotView(this);
-                    this.ActualModel = this.Model;
-                }
-            }
-
-            this.InvalidatePlot();
-        }
-
-        /// <summary>
-        /// Renders the plot model to the plot presenter.
-        /// </summary>
-        protected void Render()
-        {
-            if (this.plotPresenter == null || this.renderContext == null)
-            {
-                return;
-            }
-            this.isInVisualTree = this.IsInVisualTree();
-
-            this.RenderOverride();
-        }
-
-        /// <summary>
-        /// Renders the plot model to the plot presenter.
-        /// </summary>
-        protected virtual void RenderOverride()
-        {
-            var dpiScale = this.UpdateDpi();
-            this.ClearBackground();
-
-            if (this.ActualModel != null)
-            {
-                // round width and height to full device pixels
-                var width = ((int)(this.plotPresenter.ActualWidth * dpiScale)) / dpiScale;
-                var height = ((int)(this.plotPresenter.ActualHeight * dpiScale)) / dpiScale;
-
-                lock (this.ActualModel.SyncRoot)
-                {
-                    ((IPlotModel)this.ActualModel).Render(this.renderContext, new OxyRect(0, 0, width, height));
-                }
-            }
-        }
-
-        /// <summary>
-        /// Updates the DPI scale of the render context.
-        /// </summary>
-        /// <returns>The DPI scale.</returns>
-        protected virtual double UpdateDpi()
-        {
-            var transformMatrix = PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice;
-            var scale = transformMatrix == null ? 1 : (transformMatrix.Value.M11 + transformMatrix.Value.M22) / 2;
-            return scale;
-        }
-
-        /// <summary>
-        /// Called when the model is changed.
-        /// </summary>
-        /// <param name="d">The sender.</param>
-        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
-        private static void ModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            ((PlotViewBase)d).OnModelChanged();
-        }
-
-        /// <summary>
-        /// Invokes the specified action on the dispatcher, if necessary.
-        /// </summary>
-        /// <param name="action">The action.</param>
-        private void BeginInvoke(Action action)
-        {
-            if (!this.Dispatcher.CheckAccess())
-            {
-                this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, action);
-            }
-            else
-            {
-                action();
-            }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether the <see cref="PlotViewBase"/> is connected to the visual tree.
-        /// </summary>
-        /// <returns><c>true</c> if the PlotViewBase is connected to the visual tree; <c>false</c> otherwise.</returns>
-        private bool IsInVisualTree()
-        {
-            DependencyObject dpObject = this;
-            while ((dpObject = VisualTreeHelper.GetParent(dpObject)) != null)
-            {
-                if (dpObject is Window)
-                {
-                    return true;
-                }
-
-                //Check if the parent is an AdornerDecorator like in an ElementHost
-                if (dpObject is AdornerDecorator)
-                {
-                    return true;
-                }
-
-                //Check if the logical parent is a popup. If so, we found the popuproot
-                var logicalRoot = LogicalTreeHelper.GetParent(dpObject);
-                if (logicalRoot is Popup)
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        /// <summary>
-        /// This event fires every time Layout updates the layout of the trees associated with current Dispatcher.
-        /// </summary>
-        /// <param name="sender">The sender.</param>
-        /// <param name="e">The event args.</param>
-        private void OnLayoutUpdated(object sender, EventArgs e)
-        {
-            // if we were not in the visual tree the last time we tried to render but are now, we have to render
-            if (!this.isInVisualTree && this.IsInVisualTree())
-            {
-                this.Render();
-            }
-        }
-    }
-}

+ 0 - 98
OxyPlot/OxyPlot.Wpf.Shared/Themes/Generic.xaml

@@ -1,98 +0,0 @@
-<ResourceDictionary
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="clr-namespace:OxyPlot.Wpf">
-
-    <local:ThicknessConverter x:Key="ThicknessConverter" />
-
-    <Style TargetType="{x:Type local:TrackerControl}">
-        <Setter Property="Background" Value="#E0FFFFA0" />
-        <Setter Property="BorderBrush" Value="Black" />
-        <Setter Property="BorderThickness" Value="1" />
-        <Setter Property="BorderEdgeMode" Value="Aliased" />
-        <Setter Property="LineStroke" Value="#80000000" />
-        <Setter Property="HorizontalLineVisibility" Value="Visible" />
-        <Setter Property="VerticalLineVisibility" Value="Visible" />
-        <Setter Property="LineThickness" Value="1" />
-        <Setter Property="Distance" Value="7" />
-        <Setter Property="CornerRadius" Value="0" />
-        <Setter Property="ShowPointer" Value="true" />
-        <Setter Property="CanCenterHorizontally" Value="true" />
-        <Setter Property="CanCenterVertically" Value="true" />
-        <Setter Property="IsHitTestVisible" Value="false" />
-        <Setter Property="Template">
-            <Setter.Value>
-                <ControlTemplate TargetType="{x:Type local:TrackerControl}">
-                    <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-                        <Line
-                            x:Name="PART_HorizontalLine"
-                            RenderOptions.EdgeMode="Aliased"
-                            Stroke="{TemplateBinding LineStroke}"
-                            StrokeDashArray="{TemplateBinding LineDashArray}"
-                            StrokeThickness="{TemplateBinding LineThickness}"
-                            Visibility="{TemplateBinding HorizontalLineVisibility}" />
-                        <Line
-                            x:Name="PART_VerticalLine"
-                            RenderOptions.EdgeMode="Aliased"
-                            Stroke="{TemplateBinding LineStroke}"
-                            StrokeDashArray="{TemplateBinding LineDashArray}"
-                            StrokeThickness="{TemplateBinding LineThickness}"
-                            Visibility="{TemplateBinding VerticalLineVisibility}" />
-                        <Grid x:Name="PART_ContentContainer">
-                            <Path
-                                x:Name="PART_Path"
-                                Fill="{TemplateBinding Background}"
-                                RenderOptions.EdgeMode="{TemplateBinding BorderEdgeMode}"
-                                Stroke="{TemplateBinding BorderBrush}"
-                                StrokeThickness="{TemplateBinding BorderThickness,
-                                                                  Converter={StaticResource ThicknessConverter}}" />
-                            <ContentPresenter
-                                x:Name="PART_Content"
-                                HorizontalAlignment="Center"
-                                VerticalAlignment="Center" />
-                        </Grid>
-                    </Canvas>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-    </Style>
-
-    <Style TargetType="{x:Type local:PlotViewBase}">
-        <Setter Property="Background" Value="White" />
-        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
-        <Setter Property="DefaultTrackerTemplate">
-            <Setter.Value>
-                <ControlTemplate>
-                    <local:TrackerControl LineExtents="{Binding PlotModel.PlotArea}" Position="{Binding Position}">
-                        <local:TrackerControl.Content>
-                            <TextBlock Margin="7" Text="{Binding}" />
-                        </local:TrackerControl.Content>
-                    </local:TrackerControl>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-        <Setter Property="ZoomRectangleTemplate">
-            <Setter.Value>
-                <ControlTemplate>
-                    <Rectangle
-                        Fill="#40FFFF00"
-                        Stroke="Black"
-                        StrokeDashArray="3,1" />
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-        <Setter Property="Template">
-            <Setter.Value>
-                <ControlTemplate TargetType="{x:Type local:PlotViewBase}">
-                    <Border
-                        Background="{TemplateBinding Background}"
-                        BorderBrush="{TemplateBinding BorderBrush}"
-                        BorderThickness="{TemplateBinding BorderThickness}">
-                        <Grid x:Name="PART_Grid" />
-                    </Border>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-    </Style>
-
-</ResourceDictionary>

+ 0 - 657
OxyPlot/OxyPlot.Wpf.Shared/Tracker/TrackerControl.cs

@@ -1,657 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="TrackerControl.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   The tracker control.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System;
-    using System.Windows;
-    using System.Windows.Controls;
-    using System.Windows.Media;
-    using System.Windows.Shapes;
-
-    /// <summary>
-    /// The tracker control.
-    /// </summary>
-    public class TrackerControl : ContentControl
-    {
-        /// <summary>
-        /// Identifies the <see cref="HorizontalLineVisibility"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty HorizontalLineVisibilityProperty =
-            DependencyProperty.Register(
-                nameof(HorizontalLineVisibility),
-                typeof(Visibility),
-                typeof(TrackerControl),
-                new PropertyMetadata(Visibility.Visible));
-
-        /// <summary>
-        /// Identifies the <see cref="VerticalLineVisibility"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty VerticalLineVisibilityProperty =
-            DependencyProperty.Register(
-                nameof(VerticalLineVisibility),
-                typeof(Visibility),
-                typeof(TrackerControl),
-                new PropertyMetadata(Visibility.Visible));
-
-        /// <summary>
-        /// Identifies the <see cref="LineThickness"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty LineThicknessProperty = DependencyProperty.Register(
-            nameof(LineThickness), typeof(double), typeof(TrackerControl), new PropertyMetadata(1.0));
-
-        /// <summary>
-        /// Identifies the <see cref="LineStroke"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty LineStrokeProperty = DependencyProperty.Register(
-            nameof(LineStroke), typeof(Brush), typeof(TrackerControl), new PropertyMetadata(null));
-
-        /// <summary>
-        /// Identifies the <see cref="LineExtents"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty LineExtentsProperty = DependencyProperty.Register(
-            nameof(LineExtents), typeof(OxyRect), typeof(TrackerControl), new PropertyMetadata(new OxyRect()));
-
-        /// <summary>
-        /// Identifies the <see cref="LineDashArray"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty LineDashArrayProperty = DependencyProperty.Register(
-            nameof(LineDashArray), typeof(DoubleCollection), typeof(TrackerControl), new PropertyMetadata(null));
-
-        /// <summary>
-        /// Identifies the <see cref="BorderEdgeMode"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty BorderEdgeModeProperty = DependencyProperty.Register(
-            nameof(BorderEdgeMode), typeof(EdgeMode), typeof(TrackerControl));
-
-        /// <summary>
-        /// Identifies the <see cref="ShowPointer"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty ShowPointerProperty = DependencyProperty.Register(
-            nameof(ShowPointer), typeof(bool), typeof(TrackerControl), new PropertyMetadata(true));
-
-        /// <summary>
-        /// Identifies the <see cref="CornerRadius"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
-            nameof(CornerRadius), typeof(double), typeof(TrackerControl), new PropertyMetadata(0.0));
-
-        /// <summary>
-        /// Identifies the <see cref="Distance"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty DistanceProperty = DependencyProperty.Register(
-            nameof(Distance), typeof(double), typeof(TrackerControl), new PropertyMetadata(7.0));
-
-        /// <summary>
-        /// Identifies the <see cref="CanCenterHorizontally"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty CanCenterHorizontallyProperty =
-            DependencyProperty.Register(
-                nameof(CanCenterHorizontally), typeof(bool), typeof(TrackerControl), new PropertyMetadata(true));
-
-        /// <summary>
-        /// Identifies the <see cref="CanCenterVertically"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty CanCenterVerticallyProperty =
-            DependencyProperty.Register(
-                nameof(CanCenterVertically), typeof(bool), typeof(TrackerControl), new PropertyMetadata(true));
-
-        /// <summary>
-        /// Identifies the <see cref="Position"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty PositionProperty = DependencyProperty.Register(
-            nameof(Position),
-            typeof(ScreenPoint),
-            typeof(TrackerControl),
-            new PropertyMetadata(new ScreenPoint(), PositionChanged));
-
-        /// <summary>
-        /// The path part string.
-        /// </summary>
-        private const string PartPath = "PART_Path";
-
-        /// <summary>
-        /// The content part string.
-        /// </summary>
-        private const string PartContent = "PART_Content";
-
-        /// <summary>
-        /// The content container part string.
-        /// </summary>
-        private const string PartContentcontainer = "PART_ContentContainer";
-
-        /// <summary>
-        /// The horizontal line part string.
-        /// </summary>
-        private const string PartHorizontalline = "PART_HorizontalLine";
-
-        /// <summary>
-        /// The vertical line part string.
-        /// </summary>
-        private const string PartVerticalline = "PART_VerticalLine";
-
-        /// <summary>
-        /// The content.
-        /// </summary>
-        private ContentPresenter content;
-
-        /// <summary>
-        /// The horizontal line.
-        /// </summary>
-        private Line horizontalLine;
-
-        /// <summary>
-        /// The path.
-        /// </summary>
-        private Path path;
-
-        /// <summary>
-        /// The content container.
-        /// </summary>
-        private Grid contentContainer;
-
-        /// <summary>
-        /// The vertical line.
-        /// </summary>
-        private Line verticalLine;
-
-        /// <summary>
-        /// Initializes static members of the <see cref = "TrackerControl" /> class.
-        /// </summary>
-        static TrackerControl()
-        {
-            DefaultStyleKeyProperty.OverrideMetadata(
-                typeof(TrackerControl), new FrameworkPropertyMetadata(typeof(TrackerControl)));
-        }
-
-        /// <summary>
-        /// Gets or sets BorderEdgeMode.
-        /// </summary>
-        public EdgeMode BorderEdgeMode
-        {
-            get => (EdgeMode)this.GetValue(BorderEdgeModeProperty);
-            set => this.SetValue(BorderEdgeModeProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets HorizontalLineVisibility.
-        /// </summary>
-        public Visibility HorizontalLineVisibility
-        {
-            get => (Visibility)this.GetValue(HorizontalLineVisibilityProperty);
-            set => this.SetValue(HorizontalLineVisibilityProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets VerticalLineVisibility.
-        /// </summary>
-        public Visibility VerticalLineVisibility
-        {
-            get => (Visibility)this.GetValue(VerticalLineVisibilityProperty);
-            set => this.SetValue(VerticalLineVisibilityProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets LineThickness.
-        /// </summary>
-        public double LineThickness
-        {
-            get => (double)this.GetValue(LineThicknessProperty);
-            set => this.SetValue(LineThicknessProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets LineStroke.
-        /// </summary>
-        public Brush LineStroke
-        {
-            get => (Brush)this.GetValue(LineStrokeProperty);
-            set => this.SetValue(LineStrokeProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets LineExtents.
-        /// </summary>
-        public OxyRect LineExtents
-        {
-            get => (OxyRect)this.GetValue(LineExtentsProperty);
-            set => this.SetValue(LineExtentsProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets LineDashArray.
-        /// </summary>
-        public DoubleCollection LineDashArray
-        {
-            get => (DoubleCollection)this.GetValue(LineDashArrayProperty);
-            set => this.SetValue(LineDashArrayProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether to show a 'pointer' on the border.
-        /// </summary>
-        public bool ShowPointer
-        {
-            get => (bool)this.GetValue(ShowPointerProperty);
-            set => this.SetValue(ShowPointerProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the corner radius (only used when ShowPoint=<c>false</c>).
-        /// </summary>
-        public double CornerRadius
-        {
-            get => (double)this.GetValue(CornerRadiusProperty);
-
-            set => this.SetValue(CornerRadiusProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the distance of the content container from the trackers Position.
-        /// </summary>
-        public double Distance
-        {
-            get => (double)this.GetValue(DistanceProperty);
-            set => this.SetValue(DistanceProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether the tracker can center its content box horizontally.
-        /// </summary>
-        public bool CanCenterHorizontally
-        {
-            get => (bool)this.GetValue(CanCenterHorizontallyProperty);
-            set => this.SetValue(CanCenterHorizontallyProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether the tracker can center its content box vertically.
-        /// </summary>
-        public bool CanCenterVertically
-        {
-            get => (bool)this.GetValue(CanCenterVerticallyProperty);
-            set => this.SetValue(CanCenterVerticallyProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets Position of the tracker.
-        /// </summary>
-        public ScreenPoint Position
-        {
-            get => (ScreenPoint)this.GetValue(PositionProperty);
-            set => this.SetValue(PositionProperty, value);
-        }
-
-        /// <summary>
-        /// When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate" />.
-        /// </summary>
-        public override void OnApplyTemplate()
-        {
-            base.OnApplyTemplate();
-            this.path = this.GetTemplateChild(PartPath) as Path;
-            this.content = this.GetTemplateChild(PartContent) as ContentPresenter;
-            this.contentContainer = this.GetTemplateChild(PartContentcontainer) as Grid;
-            this.horizontalLine = this.GetTemplateChild(PartHorizontalline) as Line;
-            this.verticalLine = this.GetTemplateChild(PartVerticalline) as Line;
-
-            if (this.contentContainer == null)
-            {
-                throw new InvalidOperationException($"The TrackerControl template must contain a content container with name +'{PartContentcontainer}'");
-            }
-
-            if (this.path == null)
-            {
-                throw new InvalidOperationException($"The TrackerControl template must contain a Path with name +'{PartPath}'");
-            }
-
-            if (this.content == null)
-            {
-                throw new InvalidOperationException($"The TrackerControl template must contain a ContentPresenter with name +'{PartContent}'");
-            }
-
-            this.UpdatePositionAndBorder();
-        }
-
-        /// <summary>
-        /// Called when the position is changed.
-        /// </summary>
-        /// <param name="sender">The sender.</param>
-        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
-        private static void PositionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
-        {
-            ((TrackerControl)sender).OnPositionChanged(e);
-        }
-
-        /// <summary>
-        /// Called when the position is changed.
-        /// </summary>
-        /// <param name="dependencyPropertyChangedEventArgs">The dependency property changed event args.</param>
-        // ReSharper disable once UnusedParameter.Local
-        private void OnPositionChanged(DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
-        {
-            this.UpdatePositionAndBorder();
-        }
-
-        /// <summary>
-        /// Update the position and border of the tracker.
-        /// </summary>
-        private void UpdatePositionAndBorder()
-        {
-            if (this.contentContainer == null)
-            {
-                return;
-            }
-
-            Canvas.SetLeft(this.contentContainer, this.Position.X);
-            Canvas.SetTop(this.contentContainer, this.Position.Y);
-            FrameworkElement parent = this;
-            while (!(parent is Canvas) && parent != null)
-            {
-                parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
-            }
-
-            if (parent == null)
-            {
-                return;
-            }
-
-            // throw new InvalidOperationException("The TrackerControl must have a Canvas parent.");
-            double canvasWidth = parent.ActualWidth;
-            double canvasHeight = parent.ActualHeight;
-
-            this.content.Measure(new Size(canvasWidth, canvasHeight));
-            this.content.Arrange(new Rect(0, 0, this.content.DesiredSize.Width, this.content.DesiredSize.Height));
-
-            double contentWidth = this.content.DesiredSize.Width;
-            double contentHeight = this.content.DesiredSize.Height;
-
-            // Minimum allowed margins around the tracker
-            const double MarginLimit = 10;
-
-            var ha = HorizontalAlignment.Center;
-            if (this.CanCenterHorizontally)
-            {
-                if (this.Position.X - (contentWidth / 2) < MarginLimit)
-                {
-                    ha = HorizontalAlignment.Left;
-                }
-
-                if (this.Position.X + (contentWidth / 2) > canvasWidth - MarginLimit)
-                {
-                    ha = HorizontalAlignment.Right;
-                }
-            }
-            else
-            {
-                ha = this.Position.X < canvasWidth / 2 ? HorizontalAlignment.Left : HorizontalAlignment.Right;
-            }
-
-            var va = VerticalAlignment.Center;
-            if (this.CanCenterVertically)
-            {
-                if (this.Position.Y - (contentHeight / 2) < MarginLimit)
-                {
-                    va = VerticalAlignment.Top;
-                }
-
-                if (ha == HorizontalAlignment.Center)
-                {
-                    va = VerticalAlignment.Bottom;
-                    if (this.Position.Y - contentHeight < MarginLimit)
-                    {
-                        va = VerticalAlignment.Top;
-                    }
-                }
-
-                if (va == VerticalAlignment.Center && this.Position.Y + (contentHeight / 2) > canvasHeight - MarginLimit)
-                {
-                    va = VerticalAlignment.Bottom;
-                }
-
-                if (va == VerticalAlignment.Top && this.Position.Y + contentHeight > canvasHeight - MarginLimit)
-                {
-                    va = VerticalAlignment.Bottom;
-                }
-            }
-            else
-            {
-                va = this.Position.Y < canvasHeight / 2 ? VerticalAlignment.Top : VerticalAlignment.Bottom;
-            }
-
-            double dx = ha == HorizontalAlignment.Center ? -0.5 : ha == HorizontalAlignment.Left ? 0 : -1;
-            double dy = va == VerticalAlignment.Center ? -0.5 : va == VerticalAlignment.Top ? 0 : -1;
-
-            this.path.Data = this.ShowPointer
-                                 ? this.CreatePointerBorderGeometry(ha, va, contentWidth, contentHeight, out Thickness margin)
-                                 : this.CreateBorderGeometry(ha, va, contentWidth, contentHeight, out margin);
-
-            this.content.Margin = margin;
-
-            this.contentContainer.Measure(new Size(canvasWidth, canvasHeight));
-            var contentSize = this.contentContainer.DesiredSize;
-
-            this.contentContainer.RenderTransform = new TranslateTransform
-                {
-                    X = dx * contentSize.Width,
-                    Y = dy * contentSize.Height
-                };
-
-            var pos = this.Position;
-
-            if (this.horizontalLine != null)
-            {
-                if (this.LineExtents.Width > 0)
-                {
-                    this.horizontalLine.X1 = this.LineExtents.Left;
-                    this.horizontalLine.X2 = this.LineExtents.Right;
-                }
-                else
-                {
-                    this.horizontalLine.X1 = 0;
-                    this.horizontalLine.X2 = canvasWidth;
-                }
-
-                this.horizontalLine.Y1 = pos.Y;
-                this.horizontalLine.Y2 = pos.Y;
-            }
-
-            if (this.verticalLine != null)
-            {
-                if (this.LineExtents.Width > 0)
-                {
-                    this.verticalLine.Y1 = this.LineExtents.Top;
-                    this.verticalLine.Y2 = this.LineExtents.Bottom;
-                }
-                else
-                {
-                    this.verticalLine.Y1 = 0;
-                    this.verticalLine.Y2 = canvasHeight;
-                }
-
-                this.verticalLine.X1 = pos.X;
-                this.verticalLine.X2 = pos.X;
-            }
-        }
-
-        /// <summary>
-        /// Create the border geometry.
-        /// </summary>
-        /// <param name="ha">The horizontal alignment.</param>
-        /// <param name="va">The vertical alignment.</param>
-        /// <param name="width">The width.</param>
-        /// <param name="height">The height.</param>
-        /// <param name="margin">The margin.</param>
-        /// <returns>The border geometry.</returns>
-        private Geometry CreateBorderGeometry(
-            HorizontalAlignment ha, VerticalAlignment va, double width, double height, out Thickness margin)
-        {
-            double m = this.Distance;
-            var rect = new Rect(
-                ha == HorizontalAlignment.Left ? m : 0, va == VerticalAlignment.Top ? m : 0, width, height);
-            margin = new Thickness(
-                ha == HorizontalAlignment.Left ? m : 0,
-                va == VerticalAlignment.Top ? m : 0,
-                ha == HorizontalAlignment.Right ? m : 0,
-                va == VerticalAlignment.Bottom ? m : 0);
-            return new RectangleGeometry { Rect = rect, RadiusX = this.CornerRadius, RadiusY = this.CornerRadius };
-        }
-
-        /// <summary>
-        /// Create a border geometry with a 'pointer'.
-        /// </summary>
-        /// <param name="ha">The horizontal alignment.</param>
-        /// <param name="va">The vertical alignment.</param>
-        /// <param name="width">The width.</param>
-        /// <param name="height">The height.</param>
-        /// <param name="margin">The margin.</param>
-        /// <returns>The border geometry.</returns>
-        private Geometry CreatePointerBorderGeometry(
-            HorizontalAlignment ha, VerticalAlignment va, double width, double height, out Thickness margin)
-        {
-            Point[] points = null;
-            double m = this.Distance;
-            margin = new Thickness();
-
-            if (ha == HorizontalAlignment.Center && va == VerticalAlignment.Bottom)
-            {
-                double x0 = 0;
-                double x1 = width;
-                double x2 = (x0 + x1) / 2;
-                double y0 = 0;
-                double y1 = height;
-                margin = new Thickness(0, 0, 0, m);
-                points = new[]
-                    {
-                        new Point(x0, y0), new Point(x1, y0), new Point(x1, y1), new Point(x2 + (m / 2), y1),
-                        new Point(x2, y1 + m), new Point(x2 - (m / 2), y1), new Point(x0, y1)
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Center && va == VerticalAlignment.Top)
-            {
-                double x0 = 0;
-                double x1 = width;
-                double x2 = (x0 + x1) / 2;
-                double y0 = m;
-                double y1 = m + height;
-                margin = new Thickness(0, m, 0, 0);
-                points = new[]
-                    {
-                        new Point(x0, y0), new Point(x2 - (m / 2), y0), new Point(x2, 0), new Point(x2 + (m / 2), y0),
-                        new Point(x1, y0), new Point(x1, y1), new Point(x0, y1)
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Left && va == VerticalAlignment.Center)
-            {
-                double x0 = m;
-                double x1 = m + width;
-                double y0 = 0;
-                double y1 = height;
-                double y2 = (y0 + y1) / 2;
-                margin = new Thickness(m, 0, 0, 0);
-                points = new[]
-                    {
-                        new Point(0, y2), new Point(x0, y2 - (m / 2)), new Point(x0, y0), new Point(x1, y0),
-                        new Point(x1, y1), new Point(x0, y1), new Point(x0, y2 + (m / 2))
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Right && va == VerticalAlignment.Center)
-            {
-                double x0 = 0;
-                double x1 = width;
-                double y0 = 0;
-                double y1 = height;
-                double y2 = (y0 + y1) / 2;
-                margin = new Thickness(0, 0, m, 0);
-                points = new[]
-                    {
-                        new Point(x1 + m, y2), new Point(x1, y2 + (m / 2)), new Point(x1, y1), new Point(x0, y1),
-                        new Point(x0, y0), new Point(x1, y0), new Point(x1, y2 - (m / 2))
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Left && va == VerticalAlignment.Top)
-            {
-                m *= 0.67;
-                double x0 = m;
-                double x1 = m + width;
-                double y0 = m;
-                double y1 = m + height;
-                margin = new Thickness(m, m, 0, 0);
-                points = new[]
-                    {
-                        new Point(0, 0), new Point(m * 2, y0), new Point(x1, y0), new Point(x1, y1), new Point(x0, y1),
-                        new Point(x0, m * 2)
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Right && va == VerticalAlignment.Top)
-            {
-                m *= 0.67;
-                double x0 = 0;
-                double x1 = width;
-                double y0 = m;
-                double y1 = m + height;
-                margin = new Thickness(0, m, m, 0);
-                points = new[]
-                    {
-                        new Point(x1 + m, 0), new Point(x1, y0 + m), new Point(x1, y1), new Point(x0, y1),
-                        new Point(x0, y0), new Point(x1 - m, y0)
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Left && va == VerticalAlignment.Bottom)
-            {
-                m *= 0.67;
-                double x0 = m;
-                double x1 = m + width;
-                double y0 = 0;
-                double y1 = height;
-                margin = new Thickness(m, 0, 0, m);
-                points = new[]
-                    {
-                        new Point(0, y1 + m), new Point(x0, y1 - m), new Point(x0, y0), new Point(x1, y0),
-                        new Point(x1, y1), new Point(x0 + m, y1)
-                    };
-            }
-
-            if (ha == HorizontalAlignment.Right && va == VerticalAlignment.Bottom)
-            {
-                m *= 0.67;
-                double x0 = 0;
-                double x1 = width;
-                double y0 = 0;
-                double y1 = height;
-                margin = new Thickness(0, 0, m, m);
-                points = new[]
-                    {
-                        new Point(x1 + m, y1 + m), new Point(x1 - m, y1), new Point(x0, y1), new Point(x0, y0),
-                        new Point(x1, y0), new Point(x1, y1 - m)
-                    };
-            }
-
-            if (points == null)
-            {
-                return null;
-            }
-
-            var pc = new PointCollection(points.Length);
-            foreach (var p in points)
-            {
-                pc.Add(p);
-            }
-
-            var segments = new PathSegmentCollection { new PolyLineSegment { Points = pc } };
-            var pf = new PathFigure { StartPoint = points[0], Segments = segments, IsClosed = true };
-            return new PathGeometry { Figures = new PathFigureCollection { pf } };
-        }
-    }
-}

+ 0 - 57
OxyPlot/OxyPlot.Wpf.Shared/Tracker/TrackerDefinition.cs

@@ -1,57 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="TrackerDefinition.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Represents a tracker definition.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System.Windows;
-    using System.Windows.Controls;
-
-    /// <summary>
-    /// Represents a tracker definition.
-    /// </summary>
-    /// <remarks>The tracker definitions make it possible to show different trackers for different series.
-    /// The <see cref="OxyPlot.Series.Series.TrackerKey" /> property is matched with the <see cref="TrackerDefinition.TrackerKey" />
-    /// in the TrackerDefinitions collection in the <see cref="PlotViewBase" /> control.</remarks>
-    public class TrackerDefinition : DependencyObject
-    {
-        /// <summary>
-        /// Identifies the <see cref="TrackerKey"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty TrackerKeyProperty = DependencyProperty.Register(
-            nameof(TrackerKey), typeof(string), typeof(TrackerDefinition), new PropertyMetadata(null));
-
-        /// <summary>
-        /// Identifies the <see cref="TrackerTemplate"/> dependency property.
-        /// </summary>
-        public static readonly DependencyProperty TrackerTemplateProperty =
-            DependencyProperty.Register(
-                nameof(TrackerTemplate), typeof(ControlTemplate), typeof(TrackerDefinition), new PropertyMetadata(null));
-
-        /// <summary>
-        /// Gets or sets the tracker key.
-        /// </summary>
-        /// <remarks>The Plot will use this property to find the TrackerDefinition that matches the TrackerKey of the current series.</remarks>
-        public string TrackerKey
-        {
-            get => (string)this.GetValue(TrackerKeyProperty);
-            set => this.SetValue(TrackerKeyProperty, value);
-        }
-
-        /// <summary>
-        /// Gets or sets the tracker template.
-        /// </summary>
-        /// <remarks>The tracker control will be added/removed from the Tracker overlay as necessary.
-        /// The DataContext of the tracker will be set to a TrackerHitResult with the current tracker data.</remarks>
-        public ControlTemplate TrackerTemplate
-        {
-            get => (ControlTemplate)this.GetValue(TrackerTemplateProperty);
-            set => this.SetValue(TrackerTemplateProperty, value);
-        }
-    }
-}

+ 0 - 487
OxyPlot/OxyPlot.Wpf.Shared/Utilities/ConverterExtensions.cs

@@ -1,487 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="ConverterExtensions.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Extension method used to convert to/from Windows/Windows.Media classes.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System;
-    using System.Windows;
-    using System.Windows.Input;
-    using System.Windows.Media;
-
-    using HorizontalAlignment = OxyPlot.HorizontalAlignment;
-    using VerticalAlignment = OxyPlot.VerticalAlignment;
-
-    /// <summary>
-    /// Extension method used to convert to/from Windows/Windows.Media classes.
-    /// </summary>
-    public static class ConverterExtensions
-    {
-        /// <summary>
-        /// Calculate the distance between two points.
-        /// </summary>
-        /// <param name="p1">The first point.</param>
-        /// <param name="p2">The second point.</param>
-        /// <returns>The distance.</returns>
-        public static double DistanceTo(this Point p1, Point p2)
-        {
-            double dx = p1.X - p2.X;
-            double dy = p1.Y - p2.Y;
-            return Math.Sqrt((dx * dx) + (dy * dy));
-        }
-
-        /// <summary>
-        /// Converts an <see cref="OxyColor" /> to a <see cref="Brush" />.
-        /// </summary>
-        /// <param name="c">The color.</param>
-        /// <returns>A <see cref="SolidColorBrush" />.</returns>
-        public static Brush ToBrush(this OxyColor c)
-        {
-            return !c.IsUndefined() ? new SolidColorBrush(c.ToColor()) : null;
-        }
-
-        /// <summary>
-        /// Converts an <see cref="OxyColor" /> to a <see cref="Color" />.
-        /// </summary>
-        /// <param name="c">The color.</param>
-        /// <returns>A Color.</returns>
-        public static Color ToColor(this OxyColor c)
-        {
-            return Color.FromArgb(c.A, c.R, c.G, c.B);
-        }
-
-        /// <summary>
-        /// Converts an OxyThickness to a Thickness.
-        /// </summary>
-        /// <param name="c">The thickness.</param>
-        /// <returns>A <see cref="Thickness" /> instance.</returns>
-        public static Thickness ToThickness(this OxyThickness c)
-        {
-            return new Thickness(c.Left, c.Top, c.Right, c.Bottom);
-        }
-
-        /// <summary>
-        /// Converts a ScreenVector to a Vector.
-        /// </summary>
-        /// <param name="c">The c.</param>
-        /// <returns>A <see cref="Vector" /> instance.</returns>
-        public static Vector ToVector(this ScreenVector c)
-        {
-            return new Vector(c.X, c.Y);
-        }
-
-        /// <summary>
-        /// Converts a HorizontalAlignment to a HorizontalAlignment.
-        /// </summary>
-        /// <param name="alignment">The alignment.</param>
-        /// <returns>A HorizontalAlignment.</returns>
-        public static HorizontalAlignment ToHorizontalAlignment(this System.Windows.HorizontalAlignment alignment)
-        {
-            switch (alignment)
-            {
-                case System.Windows.HorizontalAlignment.Center:
-                    return HorizontalAlignment.Center;
-                case System.Windows.HorizontalAlignment.Right:
-                    return HorizontalAlignment.Right;
-                default:
-                    return HorizontalAlignment.Left;
-            }
-        }
-
-        /// <summary>
-        /// Converts a HorizontalAlignment to a VerticalAlignment.
-        /// </summary>
-        /// <param name="alignment">The alignment.</param>
-        /// <returns>A VerticalAlignment.</returns>
-        public static VerticalAlignment ToVerticalAlignment(this System.Windows.VerticalAlignment alignment)
-        {
-            switch (alignment)
-            {
-                case System.Windows.VerticalAlignment.Center:
-                    return VerticalAlignment.Middle;
-                case System.Windows.VerticalAlignment.Top:
-                    return VerticalAlignment.Top;
-                default:
-                    return VerticalAlignment.Bottom;
-            }
-        }
-
-        /// <summary>
-        /// Converts a Color to an OxyColor.
-        /// </summary>
-        /// <param name="color">The color.</param>
-        /// <returns>An OxyColor.</returns>
-        public static OxyColor ToOxyColor(this Color color)
-        {
-            return OxyColor.FromArgb(color.A, color.R, color.G, color.B);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="Brush" /> to an <see cref="OxyColor" />.
-        /// </summary>
-        /// <param name="brush">The brush.</param>
-        /// <returns>An <see cref="OxyColor" />.</returns>
-        public static OxyColor ToOxyColor(this Brush brush)
-        {
-            var scb = brush as SolidColorBrush;
-            return scb != null ? scb.Color.ToOxyColor() : OxyColors.Undefined;
-        }
-
-        /// <summary>
-        /// Converts a Thickness to an <see cref="OxyThickness" />.
-        /// </summary>
-        /// <param name="t">The thickness.</param>
-        /// <returns>An <see cref="OxyThickness" />.</returns>
-        public static OxyThickness ToOxyThickness(this Thickness t)
-        {
-            return new OxyThickness(t.Left, t.Top, t.Right, t.Bottom);
-        }
-
-        /// <summary>
-        /// Converts a <see cref="Point" /> to a <see cref="ScreenPoint" />.
-        /// </summary>
-        /// <param name="pt">The point.</param>
-        /// <returns>A <see cref="ScreenPoint" />.</returns>
-        public static ScreenPoint ToScreenPoint(this Point pt)
-        {
-            return new ScreenPoint(pt.X, pt.Y);
-        }
-
-        /// <summary>
-        /// Converts a Point array to a ScreenPoint array.
-        /// </summary>
-        /// <param name="points">The points.</param>
-        /// <returns>A ScreenPoint array.</returns>
-        public static ScreenPoint[] ToScreenPointArray(this Point[] points)
-        {
-            if (points == null)
-            {
-                return null;
-            }
-
-            var pts = new ScreenPoint[points.Length];
-            for (int i = 0; i < points.Length; i++)
-            {
-                pts[i] = points[i].ToScreenPoint();
-            }
-
-            return pts;
-        }
-
-        /// <summary>
-        /// Converts the specified vector to a ScreenVector.
-        /// </summary>
-        /// <param name="vector">The vector.</param>
-        /// <returns>A <see cref="ScreenVector" />.</returns>
-        public static ScreenVector ToScreenVector(this Vector vector)
-        {
-            return new ScreenVector(vector.X, vector.Y);
-        }
-
-        /// <summary>
-        /// Converts the specified key.
-        /// </summary>
-        /// <param name="k">The key to convert.</param>
-        /// <returns>The converted key.</returns>
-        public static OxyKey Convert(this Key k)
-        {
-            switch (k)
-            {
-                case Key.A:
-                    return OxyKey.A;
-                case Key.Add:
-                    return OxyKey.Add;
-                case Key.B:
-                    return OxyKey.B;
-                case Key.Back:
-                    return OxyKey.Backspace;
-                case Key.C:
-                    return OxyKey.C;
-                case Key.D:
-                    return OxyKey.D;
-                case Key.D0:
-                    return OxyKey.D0;
-                case Key.D1:
-                    return OxyKey.D1;
-                case Key.D2:
-                    return OxyKey.D2;
-                case Key.D3:
-                    return OxyKey.D3;
-                case Key.D4:
-                    return OxyKey.D4;
-                case Key.D5:
-                    return OxyKey.D5;
-                case Key.D6:
-                    return OxyKey.D6;
-                case Key.D7:
-                    return OxyKey.D7;
-                case Key.D8:
-                    return OxyKey.D8;
-                case Key.D9:
-                    return OxyKey.D9;
-                case Key.Decimal:
-                    return OxyKey.Decimal;
-                case Key.Delete:
-                    return OxyKey.Delete;
-                case Key.Divide:
-                    return OxyKey.Divide;
-                case Key.Down:
-                    return OxyKey.Down;
-                case Key.E:
-                    return OxyKey.E;
-                case Key.End:
-                    return OxyKey.End;
-                case Key.Enter:
-                    return OxyKey.Enter;
-                case Key.Escape:
-                    return OxyKey.Escape;
-                case Key.F:
-                    return OxyKey.F;
-                case Key.F1:
-                    return OxyKey.F1;
-                case Key.F10:
-                    return OxyKey.F10;
-                case Key.F11:
-                    return OxyKey.F11;
-                case Key.F12:
-                    return OxyKey.F12;
-                case Key.F2:
-                    return OxyKey.F2;
-                case Key.F3:
-                    return OxyKey.F3;
-                case Key.F4:
-                    return OxyKey.F4;
-                case Key.F5:
-                    return OxyKey.F5;
-                case Key.F6:
-                    return OxyKey.F6;
-                case Key.F7:
-                    return OxyKey.F7;
-                case Key.F8:
-                    return OxyKey.F8;
-                case Key.F9:
-                    return OxyKey.F9;
-                case Key.G:
-                    return OxyKey.G;
-                case Key.H:
-                    return OxyKey.H;
-                case Key.Home:
-                    return OxyKey.Home;
-                case Key.I:
-                    return OxyKey.I;
-                case Key.Insert:
-                    return OxyKey.Insert;
-                case Key.J:
-                    return OxyKey.J;
-                case Key.K:
-                    return OxyKey.K;
-                case Key.L:
-                    return OxyKey.L;
-                case Key.Left:
-                    return OxyKey.Left;
-                case Key.M:
-                    return OxyKey.M;
-                case Key.Multiply:
-                    return OxyKey.Multiply;
-                case Key.N:
-                    return OxyKey.N;
-                case Key.NumPad0:
-                    return OxyKey.NumPad0;
-                case Key.NumPad1:
-                    return OxyKey.NumPad1;
-                case Key.NumPad2:
-                    return OxyKey.NumPad2;
-                case Key.NumPad3:
-                    return OxyKey.NumPad3;
-                case Key.NumPad4:
-                    return OxyKey.NumPad4;
-                case Key.NumPad5:
-                    return OxyKey.NumPad5;
-                case Key.NumPad6:
-                    return OxyKey.NumPad6;
-                case Key.NumPad7:
-                    return OxyKey.NumPad7;
-                case Key.NumPad8:
-                    return OxyKey.NumPad8;
-                case Key.NumPad9:
-                    return OxyKey.NumPad9;
-                case Key.O:
-                    return OxyKey.O;
-                case Key.P:
-                    return OxyKey.P;
-                case Key.PageDown:
-                    return OxyKey.PageDown;
-                case Key.PageUp:
-                    return OxyKey.PageUp;
-                case Key.Q:
-                    return OxyKey.Q;
-                case Key.R:
-                    return OxyKey.R;
-                case Key.Right:
-                    return OxyKey.Right;
-                case Key.S:
-                    return OxyKey.S;
-                case Key.Space:
-                    return OxyKey.Space;
-                case Key.Subtract:
-                    return OxyKey.Subtract;
-                case Key.T:
-                    return OxyKey.T;
-                case Key.Tab:
-                    return OxyKey.Tab;
-                case Key.U:
-                    return OxyKey.U;
-                case Key.Up:
-                    return OxyKey.Up;
-                case Key.V:
-                    return OxyKey.V;
-                case Key.W:
-                    return OxyKey.W;
-                case Key.X:
-                    return OxyKey.X;
-                case Key.Y:
-                    return OxyKey.Y;
-                case Key.Z:
-                    return OxyKey.Z;
-                default:
-                    return OxyKey.Unknown;
-            }
-        }
-
-        /// <summary>
-        /// Converts the specified button.
-        /// </summary>
-        /// <param name="button">The button to convert.</param>
-        /// <returns>The converted mouse button.</returns>
-        public static OxyMouseButton Convert(this MouseButton button)
-        {
-            switch (button)
-            {
-                case MouseButton.Left:
-                    return OxyMouseButton.Left;
-                case MouseButton.Middle:
-                    return OxyMouseButton.Middle;
-                case MouseButton.Right:
-                    return OxyMouseButton.Right;
-                case MouseButton.XButton1:
-                    return OxyMouseButton.XButton1;
-                case MouseButton.XButton2:
-                    return OxyMouseButton.XButton2;
-                default:
-                    return OxyMouseButton.None;
-            }
-        }
-
-        /// <summary>
-        /// Converts <see cref="MouseWheelEventArgs" /> to <see cref="OxyMouseWheelEventArgs" /> for a mouse wheel event.
-        /// </summary>
-        /// <param name="e">The <see cref="MouseWheelEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="IInputElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseWheelEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyMouseWheelEventArgs ToMouseWheelEventArgs(this MouseWheelEventArgs e, IInputElement relativeTo)
-        {
-            return new OxyMouseWheelEventArgs
-            {
-                Position = e.GetPosition(relativeTo).ToScreenPoint(),
-                ModifierKeys = Keyboard.GetModifierKeys(),
-                Delta = e.Delta
-            };
-        }
-
-        /// <summary>
-        /// Converts <see cref="MouseButtonEventArgs" /> to <see cref="OxyMouseEventArgs" /> for a mouse down event.
-        /// </summary>
-        /// <param name="e">The <see cref="MouseButtonEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="IInputElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyMouseDownEventArgs ToMouseDownEventArgs(this MouseButtonEventArgs e, IInputElement relativeTo)
-        {
-            return new OxyMouseDownEventArgs
-            {
-                ChangedButton = e.ChangedButton.Convert(),
-                ClickCount = e.ClickCount,
-                Position = e.GetPosition(relativeTo).ToScreenPoint(),
-                ModifierKeys = Keyboard.GetModifierKeys()
-            };
-        }
-
-        /// <summary>
-        /// Converts <see cref="MouseButtonEventArgs" /> to <see cref="OxyMouseEventArgs" /> for a mouse up event.
-        /// </summary>
-        /// <param name="e">The <see cref="MouseButtonEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="IInputElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyMouseEventArgs ToMouseReleasedEventArgs(this MouseButtonEventArgs e, IInputElement relativeTo)
-        {
-            return new OxyMouseEventArgs
-            {
-                Position = e.GetPosition(relativeTo).ToScreenPoint(),
-                ModifierKeys = Keyboard.GetModifierKeys()
-            };
-        }
-
-        /// <summary>
-        /// Converts <see cref="MouseEventArgs" /> to <see cref="OxyMouseEventArgs" /> for a mouse event.
-        /// </summary>
-        /// <param name="e">The <see cref="MouseEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="IInputElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyMouseEventArgs ToMouseEventArgs(this MouseEventArgs e, IInputElement relativeTo)
-        {
-            return new OxyMouseEventArgs
-            {
-                Position = e.GetPosition(relativeTo).ToScreenPoint(),
-                ModifierKeys = Keyboard.GetModifierKeys()
-            };
-        }
-
-        /// <summary>
-        /// Converts <see cref="ManipulationStartedEventArgs" /> to <see cref="OxyMouseEventArgs" /> for a touch started event.
-        /// </summary>
-        /// <param name="e">The <see cref="ManipulationStartedEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="UIElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyTouchEventArgs ToTouchEventArgs(this ManipulationStartedEventArgs e, UIElement relativeTo)
-        {
-            return new OxyTouchEventArgs
-            {
-                Position = e.ManipulationOrigin.ToScreenPoint(),
-            };
-        }
-
-        /// <summary>
-        /// Converts <see cref="ManipulationDeltaEventArgs" /> to <see cref="OxyMouseEventArgs" /> for a touch delta event.
-        /// </summary>
-        /// <param name="e">The <see cref="ManipulationDeltaEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="UIElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyTouchEventArgs ToTouchEventArgs(this ManipulationDeltaEventArgs e, UIElement relativeTo)
-        {
-            return new OxyTouchEventArgs
-            {
-                Position = e.ManipulationOrigin.ToScreenPoint(),
-                DeltaTranslation = e.DeltaManipulation.Translation.ToScreenVector(),
-                DeltaScale = e.DeltaManipulation.Scale.ToScreenVector()
-            };
-        }
-
-        /// <summary>
-        /// Converts <see cref="ManipulationCompletedEventArgs" /> to <see cref="OxyMouseEventArgs" /> for a touch completed event.
-        /// </summary>
-        /// <param name="e">The <see cref="ManipulationCompletedEventArgs" /> instance containing the event data.</param>
-        /// <param name="relativeTo">The <see cref="UIElement" /> that the event is relative to.</param>
-        /// <returns>A <see cref="OxyMouseEventArgs" /> containing the converted event arguments.</returns>
-        public static OxyTouchEventArgs ToTouchEventArgs(this ManipulationCompletedEventArgs e, UIElement relativeTo)
-        {
-            return new OxyTouchEventArgs
-            {
-                Position = e.ManipulationOrigin.ToScreenPoint()
-            };
-        }
-    }
-}

+ 0 - 49
OxyPlot/OxyPlot.Wpf.Shared/Utilities/Keyboard.cs

@@ -1,49 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="Keyboard.cs" company="OxyPlot">
-//   Copyright (c) 2020 OxyPlot contributors
-// </copyright>
-// <summary>
-//   Provides utility methods related to the keyboard.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace OxyPlot.Wpf
-{
-    using System.Windows.Input;
-
-    /// <summary>
-    /// Provides utility methods related to the keyboard.
-    /// </summary>
-    internal static class Keyboard
-    {
-        /// <summary>
-        /// Gets the current modifier keys.
-        /// </summary>
-        /// <returns>A <see cref="OxyModifierKeys" /> value.</returns>
-        public static OxyModifierKeys GetModifierKeys()
-        {
-            var modifiers = OxyModifierKeys.None;
-            if (System.Windows.Input.Keyboard.IsKeyDown(Key.LeftShift) || System.Windows.Input.Keyboard.IsKeyDown(Key.RightShift))
-            {
-                modifiers |= OxyModifierKeys.Shift;
-            }
-
-            if (System.Windows.Input.Keyboard.IsKeyDown(Key.LeftCtrl) || System.Windows.Input.Keyboard.IsKeyDown(Key.RightCtrl))
-            {
-                modifiers |= OxyModifierKeys.Control;
-            }
-
-            if (System.Windows.Input.Keyboard.IsKeyDown(Key.LeftAlt) || System.Windows.Input.Keyboard.IsKeyDown(Key.RightAlt))
-            {
-                modifiers |= OxyModifierKeys.Alt;
-            }
-
-            if (System.Windows.Input.Keyboard.IsKeyDown(Key.LWin) || System.Windows.Input.Keyboard.IsKeyDown(Key.RWin))
-            {
-                modifiers |= OxyModifierKeys.Windows;
-            }
-
-            return modifiers;
-        }
-    }
-}

+ 3 - 0
PLCConnect/NModbus/Data/FileRecordCollection.cs

@@ -2,6 +2,7 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
 using System.Net;
@@ -12,7 +13,9 @@ namespace NModbus.Data
 {
     public class FileRecordCollection : IModbusMessageDataCollection
     {
+        [AllowNull]
         private IReadOnlyList<byte> networkBytes;
+        [AllowNull]
         private IReadOnlyList<byte> dataBytes;
 
         public FileRecordCollection(ushort fileNumber, ushort startingAddress, byte[] data)

+ 1 - 0
PLCConnect/NModbus/Data/PointSource.cs

@@ -1,6 +1,7 @@
 using NModbus.Device;
 using NModbus.Unme.Common;
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 
 namespace NModbus.Data

+ 2 - 2
PLCConnect/NModbus/Device/ConcurrentModbusMaster.cs

@@ -55,9 +55,9 @@
         }
 #endif
 
-        private async Task<T> PerformFuncAsync<T>(Func<Task<T>> action, CancellationToken cancellationToken)
+        private async Task<T?> PerformFuncAsync<T>(Func<Task<T>> action, CancellationToken cancellationToken)
         {
-            T value = default(T);
+            T? value = default(T);
 
             await PerformAsync(async () => value = await action(), cancellationToken);
 

+ 22 - 7
PLCConnect/NModbus/Device/ModbusMasterTcpConnection.cs

@@ -12,6 +12,7 @@ using NModbus.Logging;
 namespace NModbus.Device
 {
     using Extensions;
+    using System.Diagnostics.CodeAnalysis;
 
     /// <summary>
     /// Represents an incoming connection from a Modbus master. Contains the slave's logic to process the connection.
@@ -20,21 +21,21 @@ namespace NModbus.Device
     {
         
         private readonly TcpClient _client;
-        private readonly string _endPoint;
+        private readonly string _endPoint=string.Empty;
         private readonly Stream _stream;
         private readonly IModbusSlaveNetwork _slaveNetwork;
         private readonly IModbusFactory _modbusFactory;
         private readonly Task _requestHandlerTask;
 
         private readonly byte[] _mbapHeader = new byte[6];
-        private byte[] _messageFrame;
+        private byte[] _messageFrame = new byte[0];
 
         public ModbusMasterTcpConnection(TcpClient client, IModbusSlaveNetwork slaveNetwork, IModbusFactory modbusFactory, IModbusLogger logger)
             : base(new ModbusIpTransport(new TcpClientAdapter(client), modbusFactory, logger))
         {
             Logger = logger ?? throw new ArgumentNullException(nameof(logger));
             _client = client ?? throw new ArgumentNullException(nameof(client));
-            _endPoint = client.Client.RemoteEndPoint.ToString();
+            _endPoint = client.Client?.RemoteEndPoint?.ToString() ?? string.Empty;
             _stream = client.GetStream();
             _slaveNetwork = slaveNetwork ?? throw new ArgumentNullException(nameof(slaveNetwork));
             _modbusFactory = modbusFactory ?? throw new ArgumentNullException(nameof(modbusFactory));
@@ -44,8 +45,22 @@ namespace NModbus.Device
         /// <summary>
         ///     Occurs when a Modbus master TCP connection is closed.
         /// </summary>
-        public event EventHandler<TcpConnectionEventArgs> ModbusMasterTcpConnectionClosed;
+        
+        public event EventHandler<TcpConnectionEventArgs> ModbusMasterTcpConnectionClosed
+        {
+            add
+            {
+                _modbusMasterTcpConnectionClosed += value;
+            }
+            remove
+            {
+                _modbusMasterTcpConnectionClosed -= value;
+            }
+
+        }
+
 
+        private event EventHandler<TcpConnectionEventArgs> _modbusMasterTcpConnectionClosed;
         public IModbusLogger Logger { get; }
 
         public string EndPoint => _endPoint;
@@ -76,7 +91,7 @@ namespace NModbus.Device
                    if (readBytes == 0)
                    {
                        Logger.Debug($"0 bytes read, Master at {EndPoint} has closed Socket connection.");
-                       ModbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint));
+                       _modbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint));
                        return;
                    }
             
@@ -88,7 +103,7 @@ namespace NModbus.Device
                    if (readBytes == 0)
                    {
                        Logger.Debug($"0 bytes read, Master at {EndPoint} has closed Socket connection.");
-                       ModbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint));
+                        _modbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint));
                        return;
                    }
             
@@ -120,7 +135,7 @@ namespace NModbus.Device
             catch(Exception e)
             {
                Logger.Warning($"{e.GetType().Name} occured with Master at {EndPoint}. Closing connection.");
-               ModbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint));
+                _modbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint));
                return;
             }
         }

+ 2 - 2
PLCConnect/NModbus/Device/ModbusSlaveNetwork.cs

@@ -36,7 +36,7 @@ namespace NModbus.Device
         /// Apply the request.
         /// </summary>
         /// <param name="request"></param>
-        protected IModbusMessage ApplyRequest(IModbusMessage request)
+        protected IModbusMessage? ApplyRequest(IModbusMessage request)
         {
             //Check for broadcast requests
             if (request.SlaveAddress == 0)
@@ -93,7 +93,7 @@ namespace NModbus.Device
 
         public IModbusSlave GetSlave(byte unitId)
         {
-            return _slaves.GetValueOrDefault(unitId);
+            return _slaves.GetValueOrDefault(unitId)!;
         }
     }
 }

+ 4 - 5
PLCConnect/NModbus/Device/ModbusTcpSlaveNetwork.cs

@@ -25,7 +25,7 @@ namespace NModbus.Device
         private readonly ConcurrentDictionary<string, ModbusMasterTcpConnection> _masters =
             new ConcurrentDictionary<string, ModbusMasterTcpConnection>();
 
-        private TcpListener _server;
+        private TcpListener? _server;
 #if TIMER
         private Timer _timer;
 #endif
@@ -124,7 +124,7 @@ namespace NModbus.Device
                         TcpClient client = await Server.AcceptTcpClientAsync().ConfigureAwait(false);
                         var masterConnection = new ModbusMasterTcpConnection(client, this, ModbusFactory, Logger);
                         masterConnection.ModbusMasterTcpConnectionClosed += OnMasterConnectionClosedHandler;
-                        _masters.TryAdd(client.Client.RemoteEndPoint.ToString(), masterConnection);
+                        _masters.TryAdd(client.Client.RemoteEndPoint?.ToString() ?? string.Empty, masterConnection);
                     }
                 }
                 catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
@@ -181,7 +181,7 @@ namespace NModbus.Device
                             {
                                 ModbusMasterTcpConnection connection;
 
-                                if (_masters.TryRemove(key, out connection))
+                                if (_masters.TryRemove(key, out connection!))
                                 {
                                     connection.ModbusMasterTcpConnectionClosed -= OnMasterConnectionClosedHandler;
                                     connection.Dispose();
@@ -216,12 +216,11 @@ namespace NModbus.Device
         {
             ModbusMasterTcpConnection connection;
 
-            if (!_masters.TryRemove(e.EndPoint, out connection))
+            if (!_masters.TryRemove(e.EndPoint, out connection!))
             {
                 string msg = $"EndPoint {e.EndPoint} cannot be removed, it does not exist.";
                 throw new ArgumentException(msg);
             }
-
             connection.Dispose();
             Logger.Information($"Removed Master {e.EndPoint}");
         }

+ 2 - 2
PLCConnect/NModbus/Extensions/DictionaryExtensions.cs

@@ -12,11 +12,11 @@ namespace NModbus.Extensions
         /// <param name="dictionary"></param>
         /// <param name="key"></param>
         /// <returns></returns>
-        internal static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
+        internal static TValue? GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
         {
             TValue value;
 
-            if (dictionary.TryGetValue(key, out value))
+            if (dictionary.TryGetValue(key, out value!))
                 return value;
 
             return default(TValue);

+ 1 - 1
PLCConnect/NModbus/Extensions/ModbusMasterEnhanced.cs

@@ -21,7 +21,7 @@
     /// <param name="wordSize">Wordsize used by device. 16/32/64 are valid.</param>
     /// <param name="endian">The endian encoding of the device.</param>
     /// <param name="wordSwapped">Should the ushort words mirrored then flattened to bytes.</param>
-    public ModbusMasterEnhanced(IModbusMaster master, uint wordSize=32, Func<byte[], byte[]> endian = null, bool wordSwapped = false)
+    public ModbusMasterEnhanced(IModbusMaster master, uint wordSize=32, Func<byte[], byte[]>? endian = null, bool wordSwapped = false)
     {
       this.master = master;
       this.wordSize = wordSize;

+ 1 - 1
PLCConnect/NModbus/IO/ModbusTransport.cs

@@ -118,7 +118,7 @@ namespace NModbus.IO
         public virtual T UnicastMessage<T>(IModbusMessage message)
             where T : IModbusMessage, new()
         {
-            IModbusMessage response = null;
+            IModbusMessage? response = null;
             int attempt = 1;
             bool success = false;
 

+ 1 - 1
PLCConnect/NModbus/Logging/ConsoleModbusLogger.cs

@@ -14,7 +14,7 @@
 
         protected override void LogCore(LoggingLevel level, string message)
         {
-            message = message?.Replace(Environment.NewLine, BlankHeader);
+            message = message?.Replace(Environment.NewLine, BlankHeader) ?? string.Empty;
 
             Console.WriteLine($"[{level}]".PadRight(LevelColumnSize) + message);
         }

+ 1 - 1
PLCConnect/NModbus/Logging/TraceModbusLogger.cs

@@ -18,7 +18,7 @@ namespace NModbus.Logging
 
         protected override void LogCore(LoggingLevel level, string message)
         {
-            message = message?.Replace(Environment.NewLine, BlankHeader);
+            message = message?.Replace(Environment.NewLine, BlankHeader) ?? string.Empty;
 
             Trace.WriteLine($"[{level}]".PadRight(LevelColumnSize) + message);
         }

+ 2 - 1
PLCConnect/NModbus/Message/ModbusMessageImpl.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Net;
 using NModbus.Data;
@@ -41,7 +42,7 @@ namespace NModbus.Message
         public ushort? StartAddress { get; set; }
 
         public ushort? SubFunctionCode { get; set; }
-
+        [AllowNull]
         public IModbusMessageDataCollection Data { get; set; }
 
         public byte[] MessageFrame

+ 3 - 0
PLCConnect/NModbus/Message/ReadWriteMultipleRegistersRequest.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
 using NModbus.Data;
@@ -8,7 +9,9 @@ namespace NModbus.Message
 {
     public class ReadWriteMultipleRegistersRequest : AbstractModbusMessageWithData<RegisterCollection>, IModbusRequest
     {
+        [AllowNull]
         private ReadHoldingInputRegistersRequest _readRequest;
+        [AllowNull]
         private WriteMultipleRegistersRequest _writeRequest;
 
         public ReadWriteMultipleRegistersRequest()

+ 1 - 1
PLCConnect/NModbus/Message/WriteFileRecordResponse.cs

@@ -27,7 +27,7 @@ namespace NModbus.Message
 
         public byte ByteCount
         {
-            get => MessageImpl.ByteCount.Value;
+            get => MessageImpl.ByteCount!.Value;
             set => MessageImpl.ByteCount = value;
         }
 

+ 3 - 3
PLCConnect/NModbus/Message/WriteMultipleCoilsRequest.cs

@@ -33,13 +33,13 @@ namespace NModbus.Message
 
         public byte ByteCount
         {
-            get => MessageImpl.ByteCount.Value;
+            get => MessageImpl.ByteCount!.Value;
             set => MessageImpl.ByteCount = value;
         }
 
         public ushort NumberOfPoints
         {
-            get => MessageImpl.NumberOfPoints.Value;
+            get => MessageImpl.NumberOfPoints!.Value;
 
             set
             {
@@ -55,7 +55,7 @@ namespace NModbus.Message
 
         public ushort StartAddress
         {
-            get => MessageImpl.StartAddress.Value;
+            get => MessageImpl.StartAddress!.Value;
             set => MessageImpl.StartAddress = value;
         }
 

+ 2 - 2
PLCConnect/NModbus/Message/WriteMultipleCoilsResponse.cs

@@ -18,7 +18,7 @@ namespace NModbus.Message
 
         public ushort NumberOfPoints
         {
-            get => MessageImpl.NumberOfPoints.Value;
+            get => MessageImpl.NumberOfPoints!.Value;
 
             set
             {
@@ -34,7 +34,7 @@ namespace NModbus.Message
 
         public ushort StartAddress
         {
-            get => MessageImpl.StartAddress.Value;
+            get => MessageImpl.StartAddress!.Value;
             set => MessageImpl.StartAddress = value;
         }
 

+ 3 - 3
PLCConnect/NModbus/Message/WriteMultipleRegistersRequest.cs

@@ -24,13 +24,13 @@ namespace NModbus.Message
 
         public byte ByteCount
         {
-            get => MessageImpl.ByteCount.Value;
+            get => MessageImpl.ByteCount!.Value;
             set => MessageImpl.ByteCount = value;
         }
 
         public ushort NumberOfPoints
         {
-            get => MessageImpl.NumberOfPoints.Value;
+            get => MessageImpl.NumberOfPoints!.Value;
 
             set
             {
@@ -46,7 +46,7 @@ namespace NModbus.Message
 
         public ushort StartAddress
         {
-            get => MessageImpl.StartAddress.Value;
+            get => MessageImpl.StartAddress!.Value;
             set => MessageImpl.StartAddress = value;
         }
 

+ 1 - 1
PLCConnect/NModbus/Message/WriteSingleRegisterRequestResponse.cs

@@ -24,7 +24,7 @@ namespace NModbus.Message
 
         public ushort StartAddress
         {
-            get => MessageImpl.StartAddress.Value;
+            get => MessageImpl.StartAddress!.Value;
             set => MessageImpl.StartAddress = value;
         }
 

+ 4 - 4
PLCConnect/NModbus/ModbusFactory.cs

@@ -50,9 +50,9 @@ namespace NModbus
         /// <param name="includeBuiltIn">If true, the built in function services are included. Otherwise, all function services will come from the functionService parameter.</param>
         /// <param name="logger">Logger</param>
         public ModbusFactory(
-            IEnumerable<IModbusFunctionService> functionServices = null, 
+            IEnumerable<IModbusFunctionService>? functionServices = null, 
             bool includeBuiltIn = true, 
-            IModbusLogger logger = null)
+            IModbusLogger? logger = null)
         {
             Logger = logger ?? NullModbusLogger.Instance;
 
@@ -80,7 +80,7 @@ namespace NModbus
             }
         }
 
-        public IModbusSlave CreateSlave(byte unitId, ISlaveDataStore dataStore = null)
+        public IModbusSlave CreateSlave(byte unitId, ISlaveDataStore? dataStore = null)
         {
             if (dataStore == null)
                 dataStore = new DefaultSlaveDataStore();
@@ -166,7 +166,7 @@ namespace NModbus
 
         public IModbusFunctionService GetFunctionService(byte functionCode)
         {
-            return _functionServices.GetValueOrDefault(functionCode);
+            return _functionServices.GetValueOrDefault(functionCode)!;
         }
     }
 }

+ 1 - 1
PLCConnect/NModbus/SlaveException.cs

@@ -20,7 +20,7 @@ namespace NModbus
         private const string SlaveAddressPropertyName = "SlaveAdress";
         private const string FunctionCodePropertyName = "FunctionCode";
         private const string SlaveExceptionCodePropertyName = "SlaveExceptionCode";
-
+        [AllowNull]
         private readonly SlaveExceptionResponse _slaveExceptionResponse;
 
         /// <summary>

+ 1 - 1
PLCConnect/NModbus/Unme.Common/DisposableUtility.cs

@@ -13,7 +13,7 @@ namespace NModbus.Unme.Common
             }
 
             item.Dispose();
-            item = default(T);
+            item = default;
         }
     }
 }

+ 8 - 8
PLCConnect/NModbus/Utility/DiscriminatedUnion.cs

@@ -28,15 +28,15 @@ namespace NModbus.Utility
     /// <typeparam name="TB">The type of option B.</typeparam>
     public class DiscriminatedUnion<TA, TB>
     {
-        private TA optionA;
-        private TB optionB;
+        private TA? optionA;
+        private TB? optionB;
         private DiscriminatedUnionOption option;
 
         /// <summary>
         ///     Gets the value of option A.
         /// </summary>
         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "A")]
-        public TA A
+        public TA? A
         {
             get
             {
@@ -54,7 +54,7 @@ namespace NModbus.Utility
         ///     Gets the value of option B.
         /// </summary>
         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "B")]
-        public TB B
+        public TB? B
         {
             get
             {
@@ -101,19 +101,19 @@ namespace NModbus.Utility
         /// </returns>
         public override string ToString()
         {
-            string value = null;
+            string value = string.Empty;
 
             switch (Option)
             {
                 case DiscriminatedUnionOption.A:
-                    value = A.ToString();
+                    value = A?.ToString() ?? string.Empty;
                     break;
                 case DiscriminatedUnionOption.B:
-                    value = B.ToString();
+                    value = B?.ToString() ?? string.Empty;
                     break;
             }
 
-            return value;
+            return value ?? string.Empty;
         }
     }
 }

+ 1 - 1
Shaker/Service.cs

@@ -229,7 +229,7 @@ namespace ShakerService
                     {
                         ReadFifo();
                     }
-                    catch(Exception ex)
+                    catch
                     {
 
                     }

+ 1 - 2
Shaker/ShakerService.csproj

@@ -19,6 +19,7 @@
     <ProjectReference Include="..\Communication\LocalCommunication\LocalCommunication.csproj" />
     <ProjectReference Include="..\DBHelper\DBHelper.csproj" />
     <ProjectReference Include="..\EventBroker\EventBroker\EventBroker.csproj" />
+    <ProjectReference Include="..\NativeLibraryLoader\NativeLibraryLoader.csproj" />
     <ProjectReference Include="..\PLCConnect\IPLCConnect\IPLCConnect.csproj" />
     <ProjectReference Include="..\Shaker.Model\Shaker.Models.csproj" />
   </ItemGroup>
@@ -34,8 +35,6 @@
 
   <Import Project="..\NIFPGA\NIFPGA.projitems" Label="Shared" />
 
-  <Import Project="..\NativeLoader\NativeLoader.projitems" Label="Shared" />
-
   <Import Project="..\Timer\Timer\Timer.projitems" Label="Shared" />
 
 </Project>

+ 1 - 1
Shaker/ViewModel/ServiceRandomConfigViewModel.cs

@@ -90,7 +90,7 @@ namespace ShakerService.ViewModel
                 Communication.Instance.DbConnection.DeleteAll<RandomSpectralTableModel>(nameof(SpectralTables));
                 Communication.Instance.DbConnection.InsertAll(Model.SpectralTables, tableName: nameof(SpectralTables));
             }
-            catch(Exception ex)
+            catch
             {
 
             }

+ 1 - 1
Shaker/ViewModel/ServiceRandomDataViewModel.cs

@@ -36,7 +36,7 @@ namespace ShakerService.ViewModel
                 TransferFunction = new double[DriverPSD.Length];
             }
             ServiceDataCacheViewModel.Instance.Calc.Division.Division(ref CurrentAccelerationSynthesisPSD[0], ref DriverPSD[0], (uint)TransferFunction.Length, ref TransferFunction[0]);
-            Communication.Instance.Context.GetEvent(nameof(RandomDataModel.TransferFunction)).Publish(this, null, TransferFunction);
+            Communication.Instance.Context?.GetEvent(nameof(RandomDataModel.TransferFunction))?.Publish(this, null, TransferFunction);
         }
         public double[] AddAccelerationPSD(int index, double[] accpsd, bool avg = true)
         {

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff