├── .gitignore ├── BuildUtilites └── VersionIncrement.ps1 ├── LICENSE ├── README.md ├── TestApp ├── App.config ├── App.xaml ├── App.xaml.cs ├── MainViewModel.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── TestApp.csproj └── packages.config ├── UnitTests └── VectorGraphicsHelperTests │ ├── Properties │ └── AssemblyInfo.cs │ ├── VectorGeometryHelperTests.cs │ ├── VectorGraphicParserTests.cs │ ├── VectorGraphicsHelperTests.csproj │ └── packages.config ├── VectorGraphicsHelper ├── Enums.cs ├── Extensions.cs ├── Properties │ └── AssemblyInfo.cs ├── VectorCommand.cs ├── VectorGeometryHelper.cs ├── VectorGraphicParser.cs ├── VectorGraphicsHelper.csproj └── packages.config ├── WpfDirect2d.sln └── WpfDirect2d ├── Direct2dSurface.xaml ├── Direct2dSurface.xaml.cs ├── Enums.cs ├── Extensions.cs ├── FodyWeavers.xml ├── Properties └── AssemblyInfo.cs ├── Shapes ├── BaseGeometry.cs ├── GeometryPath.cs ├── IShape.cs ├── LineGeometry.cs ├── LineShape.cs └── VectorShape.cs ├── WpfDirect2D.nuspec ├── WpfDirect2d.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | 244 | /.axoCover/ 245 | -------------------------------------------------------------------------------- /BuildUtilites/VersionIncrement.ps1: -------------------------------------------------------------------------------- 1 | ##----------------------------------------------------------------------- 2 | ## (c) Microsoft Corporation. This source is subject to the Microsoft Permissive License. See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. All other rights reserved. 3 | ##----------------------------------------------------------------------- 4 | # Look for a 0.0.0.0 pattern in the build number. 5 | # If found use it to version the assemblies. 6 | # 7 | # For example, if the 'Build number format' build process parameter 8 | # $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r) 9 | # then your build numbers come out like this: 10 | # "Build HelloWorld_2013.07.19.1" 11 | # This script would then apply version 2013.07.19.1 to your assemblies. 12 | 13 | # Enable -Verbose option 14 | [CmdletBinding()] 15 | 16 | # Regular expression pattern to find the version in the build number 17 | # and then apply it to the assemblies 18 | $VersionRegex = "\d+\.\d+\.\d+\.\d+" 19 | 20 | # If this script is not running on a build server, remind user to 21 | # set environment variables so that this script can be debugged 22 | if(-not ($Env:BUILD_SOURCESDIRECTORY -and $Env:BUILD_BUILDNUMBER)) 23 | { 24 | Write-Error "You must set the following environment variables" 25 | Write-Error "to test this script interactively." 26 | Write-Host '$Env:BUILD_SOURCESDIRECTORY - For example, enter something like:' 27 | Write-Host '$Env:BUILD_SOURCESDIRECTORY = "C:\code\FabrikamTFVC\HelloWorld"' 28 | Write-Host '$Env:BUILD_BUILDNUMBER - For example, enter something like:' 29 | Write-Host '$Env:BUILD_BUILDNUMBER = "Build HelloWorld_0000.00.00.0"' 30 | exit 1 31 | } 32 | 33 | # Make sure path to source code directory is available 34 | if (-not $Env:BUILD_SOURCESDIRECTORY) 35 | { 36 | Write-Error ("BUILD_SOURCESDIRECTORY environment variable is missing.") 37 | exit 1 38 | } 39 | elseif (-not (Test-Path $Env:BUILD_SOURCESDIRECTORY)) 40 | { 41 | Write-Error "BUILD_SOURCESDIRECTORY does not exist: $Env:BUILD_SOURCESDIRECTORY" 42 | exit 1 43 | } 44 | Write-Verbose "BUILD_SOURCESDIRECTORY: $Env:BUILD_SOURCESDIRECTORY" 45 | 46 | # Make sure there is a build number 47 | if (-not $Env:BUILD_BUILDNUMBER) 48 | { 49 | Write-Error ("BUILD_BUILDNUMBER environment variable is missing.") 50 | exit 1 51 | } 52 | Write-Verbose "BUILD_BUILDNUMBER: $Env:BUILD_BUILDNUMBER" 53 | 54 | # Get and validate the version data 55 | $VersionData = [regex]::matches($Env:BUILD_BUILDNUMBER,$VersionRegex) 56 | switch($VersionData.Count) 57 | { 58 | 0 59 | { 60 | Write-Error "Could not find version number data in BUILD_BUILDNUMBER." 61 | exit 1 62 | } 63 | 1 {} 64 | default 65 | { 66 | Write-Warning "Found more than instance of version data in BUILD_BUILDNUMBER." 67 | Write-Warning "Will assume first instance is version." 68 | } 69 | } 70 | $NewVersion = $VersionData[0] 71 | Write-Verbose "Version: $NewVersion" 72 | 73 | # Apply the version to the assembly property files 74 | $files = gci $Env:BUILD_SOURCESDIRECTORY -recurse -include "*Properties*","My Project" | 75 | ?{ $_.PSIsContainer } | 76 | foreach { gci -Path $_.FullName -Recurse -include AssemblyInfo.* } 77 | if($files) 78 | { 79 | Write-Verbose "Will apply $NewVersion to $($files.count) files." 80 | 81 | foreach ($file in $files) { 82 | $filecontent = Get-Content($file) 83 | attrib $file -r 84 | $filecontent -replace $VersionRegex, $NewVersion | Out-File $file 85 | Write-Verbose "$file.FullName - version applied" 86 | } 87 | } 88 | else 89 | { 90 | Write-Warning "Found no files." 91 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ljchristinson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WPFDirect2D 2 | WPF Control that supports rendering geometries / shapes via Direct2D. 3 | 4 | ![Build status](https://ci.appveyor.com/api/projects/status/e5k5e676yp06h52c?svg=true)
5 | [![nuget](https://img.shields.io/nuget/v/WPF.Direct2D.Surface.svg)](https://www.nuget.org/packages/WPF.Direct2D.Surface/) 6 | 7 | 8 | ## Documentation 9 | Documentation can be found on the [Wiki](https://github.com/ljchristinson/WPFDirect2D/wiki) 10 | -------------------------------------------------------------------------------- /TestApp/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /TestApp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /TestApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace TestApp 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TestApp/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using System.Windows.Input; 6 | using System.Windows.Media; 7 | using Prism.Commands; 8 | using WpfDirect2D.Shapes; 9 | using Prism.Mvvm; 10 | using System.Linq; 11 | using System.Windows; 12 | 13 | namespace TestApp 14 | { 15 | public class MainViewModel : BindableBase 16 | { 17 | private const string DOT_CIRCLE_VECTOR = "F1 M 38,27.1542C 43.99,27.1542 48.8458,32.01 48.8458,38C 48.8458,43.99 43.99,48.8458 38,48.8458C 32.01,48.8458 27.1542,43.99 27.1542,38C 27.1542,32.01 32.01,27.1542 38,27.1542 Z M 38,16.625C 49.8051,16.625 59.375,26.1949 59.375,38C 59.375,49.8051 49.8051,59.375 38,59.375C 26.1949,59.375 16.625,49.8051 16.625,38C 16.625,26.1949 26.1949,16.625 38,16.625 Z M 38,20.5833C 28.381,20.5833 20.5833,28.381 20.5833,38C 20.5833,47.619 28.381,55.4167 38,55.4167C 47.6189,55.4167 55.4167,47.619 55.4167,38C 55.4167,28.381 47.619,20.5833 38,20.5833 Z"; 18 | private const string MOVE_VECTOR = "F1 M 34,39.1716L 34,22.4583L 28,28.0833L 28,22.5833L 36,15.0833L 44,22.5833L 44,28.0833L 38,22.4583L 38,38L 54.625,38L 49,32L 54.5,32L 62,40L 54.5,48L 49,48L 54.625,42L 36.8284,42L 25.8284,53L 34,53L 30,57L 19,57L 19,46L 23,42L 23,50.1716L 34,39.1716 Z M 40.2533,47.5333L 37.8,52.345L 37.8,55L 36.0933,55L 36.0933,52.375L 33.7467,47.5333L 35.6683,47.5333L 36.8633,50.3183L 37.0333,50.9283L 37.055,50.9283L 37.22,50.34L 38.4717,47.5333L 40.2533,47.5333 Z M 48.52,37L 46.49,37L 45.1817,34.5683L 45.0283,34.0683L 45.0067,34.0683L 44.8317,34.59L 43.5183,37L 41.48,37L 43.9,33.2667L 41.6933,29.5333L 43.7717,29.5333L 44.855,31.7717L 45.0817,32.4017L 45.1033,32.4017L 45.3383,31.7517L 46.5317,29.5333L 48.4133,29.5333L 46.1783,33.235L 48.52,37 Z M 32.04,38L 25.96,38L 25.96,37.015L 29.835,31.92L 26.28,31.92L 26.28,30.5333L 32.04,30.5333L 32.04,31.4883L 28.2483,36.6133L 32.04,36.6133L 32.04,38 Z"; 19 | 20 | private int _numberOfItemsToRender; 21 | private readonly Random _random; 22 | private IShape _selectedShape; 23 | private bool _rerender; 24 | 25 | public MainViewModel() 26 | { 27 | _random = new Random(10); 28 | ApplyNumberOfRenderItems = new DelegateCommand(() => GenerateShapes()); 29 | NumberOfItemsToRender = 10; 30 | Geometries = new List(); 31 | 32 | Task.Run(() => 33 | { 34 | while (true) 35 | { 36 | Thread.Sleep(100); 37 | Geometries = new List(Geometries); 38 | RaisePropertyChanged(nameof(Geometries)); 39 | 40 | var item = Geometries.ElementAtOrDefault(_random.Next(0, Geometries.Count)); 41 | if (item != null) 42 | { 43 | item.IsSelected = !item.IsSelected; 44 | item.FillColor = Colors.Yellow; 45 | } 46 | } 47 | }); 48 | } 49 | 50 | public ICommand ApplyNumberOfRenderItems { get; private set; } 51 | 52 | public int NumberOfItemsToRender 53 | { 54 | get { return _numberOfItemsToRender; } 55 | set { SetProperty(ref _numberOfItemsToRender, value); } 56 | } 57 | 58 | public List Geometries { get; private set; } 59 | 60 | public IShape SelectedShape 61 | { 62 | get { return _selectedShape; } 63 | set { _selectedShape = value; } 64 | } 65 | 66 | public bool Rerender 67 | { 68 | get { return _rerender; } 69 | set { SetProperty(ref _rerender, value); } 70 | } 71 | 72 | private void GenerateShapes() 73 | { 74 | Geometries = null; 75 | var geometryList = new List(); 76 | 77 | int count = 0; 78 | while (count < NumberOfItemsToRender) 79 | { 80 | var shape = new VectorShape 81 | { 82 | GeometryPath = DOT_CIRCLE_VECTOR, 83 | PixelXLocation = GetRandomPixelLocation(), 84 | PixelYLocation = GetRandomPixelLocation(), 85 | FillColor = Colors.Black, 86 | StrokeColor = Colors.Black, 87 | SelectedColor = Colors.Green, 88 | StrokeWidth = 0.5f, 89 | Scaling = 0.2f 90 | }; 91 | shape.BrushColorsToCache.Add(Colors.Yellow); 92 | shape.BrushColorsToCache.Add(Colors.Wheat); 93 | shape.BrushColorsToCache.Add(Colors.Turquoise); 94 | shape.BrushColorsToCache.Add(Colors.SaddleBrown); 95 | geometryList.Add(shape); 96 | 97 | geometryList.Add(new VectorShape 98 | { 99 | GeometryPath = DOT_CIRCLE_VECTOR, 100 | PixelXLocation = GetRandomPixelLocation(), 101 | PixelYLocation = GetRandomPixelLocation(), 102 | FillColor = Colors.Blue, 103 | StrokeColor = Colors.Red, 104 | SelectedColor = Colors.Green, 105 | StrokeWidth = 0.5f, 106 | Scaling = 0.4f 107 | }); 108 | 109 | geometryList.Add(new VectorShape 110 | { 111 | GeometryPath = MOVE_VECTOR, 112 | PixelXLocation = GetRandomPixelLocation(), 113 | PixelYLocation = GetRandomPixelLocation(), 114 | FillColor = Colors.Black, 115 | StrokeColor = Colors.Black, 116 | SelectedColor = Colors.Green, 117 | StrokeWidth = 0.5f, 118 | Scaling = 0.6f 119 | }); 120 | 121 | geometryList.Add(new VectorShape 122 | { 123 | GeometryPath = MOVE_VECTOR, 124 | PixelXLocation = GetRandomPixelLocation(), 125 | PixelYLocation = GetRandomPixelLocation(), 126 | FillColor = Colors.Blue, 127 | StrokeColor = Colors.Red, 128 | SelectedColor = Colors.Green, 129 | StrokeWidth = 0.5f, 130 | Scaling = 0.8f 131 | }); 132 | 133 | count += 4; 134 | } 135 | 136 | //add a line 137 | var line = new LineShape 138 | { 139 | FillColor = Colors.Blue, 140 | StrokeColor = Colors.Blue, 141 | SelectedColor = Colors.PaleVioletRed, 142 | StrokeWidth = 4f, 143 | IsLineClosed = false 144 | }; 145 | line.LineNodes.Add(new Point(10, 40)); 146 | line.LineNodes.Add(new Point(400, 10)); 147 | line.LineNodes.Add(new Point(400, 400)); 148 | geometryList.Add(line); 149 | 150 | //int numLines = 4000; 151 | //for (int i = 0; i < numLines; i++) 152 | //{ 153 | // var line = new LineShape 154 | // { 155 | // FillColor = Colors.Blue, 156 | // StrokeColor = Colors.Blue, 157 | // SelectedColor = Colors.PaleVioletRed, 158 | // StrokeWidth = 4f, 159 | // IsLineClosed = false 160 | // }; 161 | // line.LineNodes.Add(new Point(GetRandomPixelLocation(), GetRandomPixelLocation())); 162 | // line.LineNodes.Add(new Point(GetRandomPixelLocation(), GetRandomPixelLocation())); 163 | // geometryList.Add(line); 164 | //} 165 | 166 | 167 | Geometries = new List(geometryList); 168 | RaisePropertyChanged(nameof(Geometries)); 169 | } 170 | 171 | private int GetRandomPixelLocation() 172 | { 173 | return _random.Next(10, 1024); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /TestApp/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 |