瀏覽代碼

Merge branch 'master' of https://github.com/AvaloniaUI/Avalonia into wip-animations

Jumar Macato 7 年之前
父節點
當前提交
db6e2bcf3b
共有 61 個文件被更改,包括 2876 次插入846 次删除
  1. 1 0
      samples/ControlCatalog.Desktop/Program.cs
  2. 2 0
      samples/ControlCatalog.NetCore/Program.cs
  3. 7 205
      samples/ControlCatalog/ControlCatalog.csproj
  4. 1 0
      samples/ControlCatalog/MainView.xaml
  5. 19 0
      samples/ControlCatalog/Pages/DragAndDropPage.xaml
  6. 71 0
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  7. 0 36
      samples/ControlCatalog/Properties/AssemblyInfo.cs
  8. 205 0
      src/Avalonia.Base/Utilities/StringTokenizer.cs
  9. 6 3
      src/Avalonia.Controls/Application.cs
  10. 8 1
      src/Avalonia.Controls/GridLength.cs
  11. 210 0
      src/Avalonia.Controls/Platform/InProcessDragSource.cs
  12. 41 6
      src/Avalonia.Controls/Primitives/Popup.cs
  13. 2 2
      src/Avalonia.Controls/TextBlock.cs
  14. 5 2
      src/Avalonia.Controls/TextBox.cs
  15. 2 1
      src/Avalonia.Controls/Utils/UndoRedoHelper.cs
  16. 4 1
      src/Avalonia.Input/Cursors.cs
  17. 15 0
      src/Avalonia.Input/DataFormats.cs
  18. 43 0
      src/Avalonia.Input/DataObject.cs
  19. 54 0
      src/Avalonia.Input/DragDrop.cs
  20. 111 0
      src/Avalonia.Input/DragDropDevice.cs
  21. 13 0
      src/Avalonia.Input/DragDropEffects.cs
  22. 18 0
      src/Avalonia.Input/DragEventArgs.cs
  23. 39 0
      src/Avalonia.Input/IDataObject.cs
  24. 14 0
      src/Avalonia.Input/Platform/IPlatformDragSource.cs
  25. 8 0
      src/Avalonia.Input/Raw/IDragDropDevice.cs
  26. 26 0
      src/Avalonia.Input/Raw/RawDragEvent.cs
  27. 10 0
      src/Avalonia.Input/Raw/RawDragEventType.cs
  28. 9 15
      src/Avalonia.Visuals/Matrix.cs
  29. 9 14
      src/Avalonia.Visuals/Media/Brush.cs
  30. 142 292
      src/Avalonia.Visuals/Media/Brushes.cs
  31. 12 15
      src/Avalonia.Visuals/Media/Color.cs
  32. 143 141
      src/Avalonia.Visuals/Media/Colors.cs
  33. 224 0
      src/Avalonia.Visuals/Media/KnownColors.cs
  34. 6 10
      src/Avalonia.Visuals/Point.cs
  35. 7 13
      src/Avalonia.Visuals/Rect.cs
  36. 11 15
      src/Avalonia.Visuals/RelativePoint.cs
  37. 29 26
      src/Avalonia.Visuals/RelativeRect.cs
  38. 5 10
      src/Avalonia.Visuals/Size.cs
  39. 15 20
      src/Avalonia.Visuals/Thickness.cs
  40. 4 1
      src/Gtk/Avalonia.Gtk3/CursorFactory.cs
  41. 2 2
      src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
  42. 4 0
      src/OSX/Avalonia.MonoMac/Cursor.cs
  43. 124 0
      src/OSX/Avalonia.MonoMac/DragSource.cs
  44. 90 0
      src/OSX/Avalonia.MonoMac/DraggingInfo.cs
  45. 2 1
      src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs
  46. 47 0
      src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
  47. 7 4
      src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
  48. 80 0
      src/Windows/Avalonia.Win32/ClipboardFormats.cs
  49. 27 0
      src/Windows/Avalonia.Win32/CursorFactory.cs
  50. 361 0
      src/Windows/Avalonia.Win32/DataObject.cs
  51. 27 0
      src/Windows/Avalonia.Win32/DragSource.cs
  52. 99 3
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  53. 47 0
      src/Windows/Avalonia.Win32/OleContext.cs
  54. 171 0
      src/Windows/Avalonia.Win32/OleDataObject.cs
  55. 39 0
      src/Windows/Avalonia.Win32/OleDragSource.cs
  56. 160 0
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  57. 3 0
      src/Windows/Avalonia.Win32/Win32Platform.cs
  58. 9 0
      src/Windows/Avalonia.Win32/WindowImpl.cs
  59. 4 3
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  60. 14 4
      tests/Avalonia.Visuals.UnitTests/Media/BrushTests.cs
  61. 8 0
      tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs

+ 1 - 0
samples/ControlCatalog.Desktop/Program.cs

@@ -10,6 +10,7 @@ namespace ControlCatalog
 {
     internal class Program
     {
+        [STAThread]
         static void Main(string[] args)
         {
             // TODO: Make this work with GTK/Skia/Cairo depending on command-line args

+ 2 - 0
samples/ControlCatalog.NetCore/Program.cs

@@ -9,8 +9,10 @@ namespace ControlCatalog.NetCore
 {
     static class Program
     {
+        
         static void Main(string[] args)
         {
+            Thread.CurrentThread.TrySetApartmentState(ApartmentState.STA);
             if (args.Contains("--wait-for-attach"))
             {
                 Console.WriteLine("Attach debugger and use 'Set next statement'");

+ 7 - 205
samples/ControlCatalog/ControlCatalog.csproj

@@ -1,201 +1,17 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <TargetFramework>netstandard2.0</TargetFramework>    
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <None Remove="Pages\ContextMenuPage.xaml" />
-  </ItemGroup>
   <ItemGroup>
-    <!-- A reference to the entire .NET Framework is automatically included -->
-    <EmbeddedResource Include="App.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="MainView.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="DecoratedWindow.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ButtonSpinnerPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\DialogsPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\AutoCompleteBoxPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\BorderPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ButtonPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\CalendarPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\CanvasPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\CarouselPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\CheckBoxPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ContextMenuPage.xaml" />
-    <EmbeddedResource Include="Pages\DropDownPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\DatePickerPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ExpanderPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ImagePage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\LayoutTransformControlPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\MenuPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\NumericUpDownPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ProgressBarPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\RadioButtonPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\SliderPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\TextBoxPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Pages\ToolTipPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="App.xaml.cs">
-      <DependentUpon>App.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="MainView.xaml.cs">
-      <DependentUpon>MainView.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="DecoratedWindow.xaml.cs">
-      <DependentUpon>DecoratedWindow.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="MainWindow.xaml.cs">
-      <DependentUpon>MainWindow.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\DialogsPage.xaml.cs">
-      <DependentUpon>DialogsPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\BorderPage.xaml.cs">
-      <DependentUpon>BorderPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\AutoCompleteBoxPage.xaml.cs">
-      <DependentUpon>AutoCompleteBoxPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ButtonPage.xaml.cs">
-      <DependentUpon>ButtonPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\CalendarPage.xaml.cs">
-      <DependentUpon>CalendarPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\CanvasPage.xaml.cs">
-      <DependentUpon>CanvasPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\CarouselPage.xaml.cs">
-      <DependentUpon>CarouselPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ContextMenuPage.xaml.cs">
-      <DependentUpon>ContextMenuPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\CheckBoxPage.xaml.cs">
-      <DependentUpon>CheckBoxPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\DropDownPage.xaml.cs">
-      <DependentUpon>DropDownPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\DatePickerPage.xaml.cs">
-      <DependentUpon>DatePickerPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ExpanderPage.xaml.cs">
-      <DependentUpon>ExpanderPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ImagePage.xaml.cs">
-      <DependentUpon>ImagePage.xaml</DependentUpon>
+    <Compile Update="**\*.xaml.cs">
+      <DependentUpon>%(Filename)</DependentUpon>
     </Compile>
-    <Compile Include="Pages\LayoutTransformControlPage.xaml.cs">
-      <DependentUpon>LayoutTransformControlPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\MenuPage.xaml.cs">
-      <DependentUpon>MenuPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ProgressBarPage.xaml.cs">
-      <DependentUpon>ProgressBarPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\RadioButtonPage.xaml.cs">
-      <DependentUpon>RadioButtonPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\SliderPage.xaml.cs">
-      <DependentUpon>SliderPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\TreeViewPage.xaml.cs">
-      <DependentUpon>TreeViewPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\TextBoxPage.xaml.cs">
-      <DependentUpon>TextBoxPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ToolTipPage.xaml.cs">
-      <DependentUpon>ToolTipPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ButtonSpinnerPage.xaml.cs">
-      <DependentUpon>ButtonSpinnerPage.xaml</DependentUpon>
-    </Compile>
-	<Compile Include="Pages\NumericUpDownPage.xaml.cs">
-      <DependentUpon>NumericUpDownPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\ScreenPage.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Assets\delicate-arch-896885_640.jpg" />
-    <EmbeddedResource Include="Assets\github_icon.png" />
-    <EmbeddedResource Include="Assets\hirsch-899118_640.jpg" />
-    <EmbeddedResource Include="Assets\maple-leaf-888807_640.jpg" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="SideBar.xaml">
+    <EmbeddedResource Include="**\*.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
+    <EmbeddedResource Include="Assets\*" />
   </ItemGroup>
+
   <ItemGroup>
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
@@ -212,20 +28,6 @@
     <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Assets\test_icon.ico" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Pages\TreeViewPage.xaml">
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="MainWindow.xaml">
-      <Generator>MSBuild:Compile</Generator>
-      <SubType>
-      </SubType>
-    </EmbeddedResource>
-  </ItemGroup>
+  
   <Import Project="..\..\build\Serilog.props" />
 </Project>

+ 1 - 0
samples/ControlCatalog/MainView.xaml

@@ -15,6 +15,7 @@
     <TabItem Header="CheckBox"><pages:CheckBoxPage/></TabItem>
     <TabItem Header="ContextMenu"><pages:ContextMenuPage/></TabItem>
     <TabItem Header="DatePicker"><pages:DatePickerPage/></TabItem>
+    <TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem>
     <TabItem Header="DropDown"><pages:DropDownPage/></TabItem>
     <TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
     <TabItem Header="Image"><pages:ImagePage/></TabItem>

+ 19 - 0
samples/ControlCatalog/Pages/DragAndDropPage.xaml

@@ -0,0 +1,19 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+    <StackPanel Orientation="Vertical" Gap="4">
+        <TextBlock Classes="h1">Drag+Drop</TextBlock>
+        <TextBlock Classes="h2">Example of Drag+Drop capabilities</TextBlock>
+
+        <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Gap="16">
+            <Border BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="2" Padding="16" Name="DragMe">
+                <TextBlock Name="DragState">Drag Me</TextBlock>
+            </Border>
+            <Border Background="{DynamicResource ThemeAccentBrush2}" Padding="16" 
+                    DragDrop.AllowDrop="True">
+                <TextBlock Name="DropState">Drop some text or files here</TextBlock>
+            </Border>
+        </StackPanel>
+    </StackPanel>
+</UserControl>

+ 71 - 0
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@@ -0,0 +1,71 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ControlCatalog.Pages
+{
+    public class DragAndDropPage : UserControl
+    {
+        private TextBlock _DropState;
+        private TextBlock _DragState;
+        private Border _DragMe;
+        private int DragCount = 0;
+
+        public DragAndDropPage()
+        {
+            this.InitializeComponent();
+
+            _DragMe.PointerPressed += DoDrag;
+
+            AddHandler(DragDrop.DropEvent, Drop);
+            AddHandler(DragDrop.DragOverEvent, DragOver);
+        }
+
+        private async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
+        {
+            DataObject dragData = new DataObject();
+            dragData.Set(DataFormats.Text, $"You have dragged text {++DragCount} times");
+
+            var result = await DragDrop.DoDragDrop(dragData, DragDropEffects.Copy);
+            switch(result)
+            {
+                case DragDropEffects.Copy:
+                    _DragState.Text = "The text was copied"; break;
+                case DragDropEffects.Link:
+                    _DragState.Text = "The text was linked"; break;
+                case DragDropEffects.None:
+                    _DragState.Text = "The drag operation was canceled"; break;
+            }
+        }
+
+        private void DragOver(object sender, DragEventArgs e)
+        {
+            // Only allow Copy or Link as Drop Operations.
+            e.DragEffects = e.DragEffects & (DragDropEffects.Copy | DragDropEffects.Link);
+
+            // Only allow if the dragged data contains text or filenames.
+            if (!e.Data.Contains(DataFormats.Text) && !e.Data.Contains(DataFormats.FileNames))
+                e.DragEffects = DragDropEffects.None; 
+        }
+
+        private void Drop(object sender, DragEventArgs e)
+        {
+            if (e.Data.Contains(DataFormats.Text))
+                _DropState.Text = e.Data.GetText();
+            else if (e.Data.Contains(DataFormats.FileNames))
+                _DropState.Text = string.Join(Environment.NewLine, e.Data.GetFileNames());
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+
+            _DropState = this.Find<TextBlock>("DropState");
+            _DragState = this.Find<TextBlock>("DragState");
+            _DragMe = this.Find<Border>("DragMe");
+        }
+    }
+}

+ 0 - 36
samples/ControlCatalog/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("ControlCatalog")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ControlCatalog")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("61bec86c-f307-4295-b5b8-9428610d7d55")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 205 - 0
src/Avalonia.Base/Utilities/StringTokenizer.cs

@@ -0,0 +1,205 @@
+using System;
+using System.Globalization;
+using static System.Char;
+
+namespace Avalonia.Utilities
+{
+    public struct StringTokenizer : IDisposable
+    {
+        private const char DefaultSeparatorChar = ',';
+
+        private readonly string _s;
+        private readonly int _length;
+        private readonly char _separator;
+        private readonly string _exceptionMessage;
+        private readonly IFormatProvider _formatProvider;
+        private int _index;
+        private int _tokenIndex;
+        private int _tokenLength;
+
+        public StringTokenizer(string s, IFormatProvider formatProvider, string exceptionMessage = null)
+            : this(s, GetSeparatorFromFormatProvider(formatProvider), exceptionMessage)
+        {
+            _formatProvider = formatProvider;
+        }
+
+        public StringTokenizer(string s, char separator = DefaultSeparatorChar, string exceptionMessage = null)
+        {
+            _s = s ?? throw new ArgumentNullException(nameof(s));
+            _length = s?.Length ?? 0;
+            _separator = separator;
+            _exceptionMessage = exceptionMessage;
+            _formatProvider = CultureInfo.InvariantCulture;
+            _index = 0;
+            _tokenIndex = -1;
+            _tokenLength = 0;
+
+            while (_index < _length && IsWhiteSpace(_s, _index))
+            {
+                _index++;
+            }
+        }
+
+        public string CurrentToken => _tokenIndex < 0 ? null : _s.Substring(_tokenIndex, _tokenLength);
+
+        public void Dispose()
+        {
+            if (_index != _length)
+            {
+                throw GetFormatException();
+            }
+        }
+
+        public bool TryReadInt32(out Int32 result, char? separator = null)
+        {
+            var success = TryReadString(out var stringResult, separator);
+            result = success ? int.Parse(stringResult, _formatProvider) : 0;
+            return success;
+        }
+
+        public int ReadInt32(char? separator = null)
+        {
+            if (!TryReadInt32(out var result, separator))
+            {
+                throw GetFormatException();
+            }
+
+            return result;
+        }
+
+        public bool TryReadDouble(out double result, char? separator = null)
+        {
+            var success = TryReadString(out var stringResult, separator);
+            result = success ? double.Parse(stringResult, _formatProvider) : 0;
+            return success;
+        }
+
+        public double ReadDouble(char? separator = null)
+        {
+            if (!TryReadDouble(out var result, separator))
+            {
+                throw GetFormatException();
+            }
+
+            return result;
+        }
+
+        public bool TryReadString(out string result, char? separator = null)
+        {
+            var success = TryReadToken(separator ?? _separator);
+            result = CurrentToken;
+            return success;
+        }
+
+        public string ReadString(char? separator = null)
+        {
+            if (!TryReadString(out var result, separator))
+            {
+                throw GetFormatException();
+            }
+
+            return result;
+        }
+
+        private bool TryReadToken(char separator)
+        {
+            _tokenIndex = -1;
+
+            if (_index >= _length)
+            {
+                return false;
+            }
+
+            var c = _s[_index];
+
+            var index = _index;
+            var length = 0;
+
+            while (_index < _length)
+            {
+                c = _s[_index];
+
+                if (IsWhiteSpace(c) || c == separator)
+                {
+                    break;
+                }
+
+                _index++;
+                length++;
+            }
+
+            SkipToNextToken(separator);
+
+            _tokenIndex = index;
+            _tokenLength = length;
+
+            if (_tokenLength < 1)
+            {
+                throw GetFormatException();
+            }
+
+            return true;
+        }
+
+        private void SkipToNextToken(char separator)
+        {
+            if (_index < _length)
+            {
+                var c = _s[_index];
+
+                if (c != separator && !IsWhiteSpace(c))
+                {
+                    throw GetFormatException();
+                }
+
+                var length = 0;
+
+                while (_index < _length)
+                {
+                    c = _s[_index];
+
+                    if (c == separator)
+                    {
+                        length++;
+                        _index++;
+
+                        if (length > 1)
+                        {
+                            throw GetFormatException();
+                        }
+                    }
+                    else
+                    {
+                        if (!IsWhiteSpace(c))
+                        {
+                            break;
+                        }
+
+                        _index++;
+                    }
+                }
+
+                if (length > 0 && _index >= _length)
+                {
+                    throw GetFormatException();
+                }
+            }
+        }
+
+        private FormatException GetFormatException() =>
+            _exceptionMessage != null ? new FormatException(_exceptionMessage) : new FormatException();
+
+        private static char GetSeparatorFromFormatProvider(IFormatProvider provider)
+        {
+            var c = DefaultSeparatorChar;
+
+            var formatInfo = NumberFormatInfo.GetInstance(provider);
+            if (formatInfo.NumberDecimalSeparator.Length > 0 && c == formatInfo.NumberDecimalSeparator[0])
+            {
+                c = ';';
+            }
+
+            return c;
+        }
+    }
+}

+ 6 - 3
src/Avalonia.Controls/Application.cs

@@ -2,16 +2,17 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using System.Reactive.Concurrency;
 using System.Threading;
 using Avalonia.Controls;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
 using Avalonia.Layout;
-using Avalonia.Rendering;
+using Avalonia.Platform;
 using Avalonia.Styling;
 using Avalonia.Threading;
-using System.Reactive.Concurrency;
 
 namespace Avalonia
 {
@@ -234,7 +235,9 @@ namespace Avalonia
                 .Bind<IStyler>().ToConstant(_styler)
                 .Bind<ILayoutManager>().ToSingleton<LayoutManager>()
                 .Bind<IApplicationLifecycle>().ToConstant(this)
-                .Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance);
+                .Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance)
+                .Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance)
+                .Bind<IPlatformDragSource>().ToTransient<InProcessDragSource>();
         }
     }
 }

+ 8 - 1
src/Avalonia.Controls/GridLength.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -210,7 +211,13 @@ namespace Avalonia.Controls
         /// <returns>The <see cref="GridLength"/>.</returns>
         public static IEnumerable<GridLength> ParseLengths(string s, CultureInfo culture)
         {
-            return s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Parse(x, culture));
+            using (var tokenizer = new StringTokenizer(s, culture))
+            {
+                while (tokenizer.TryReadString(out var item))
+                {
+                    yield return Parse(item, culture);
+                }
+            }
         }
     }
 }

+ 210 - 0
src/Avalonia.Controls/Platform/InProcessDragSource.cs

@@ -0,0 +1,210 @@
+using System;
+using System.Linq;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
+using Avalonia.Threading;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Platform
+{
+    class InProcessDragSource : IPlatformDragSource
+    {
+        private const InputModifiers MOUSE_INPUTMODIFIERS = InputModifiers.LeftMouseButton|InputModifiers.MiddleMouseButton|InputModifiers.RightMouseButton;
+        private readonly IDragDropDevice _dragDrop;
+        private readonly IInputManager _inputManager;
+        private readonly Subject<DragDropEffects> _result = new Subject<DragDropEffects>();
+
+        private DragDropEffects _allowedEffects;
+        private IDataObject _draggedData;
+        private IInputElement _lastRoot;
+        private Point _lastPosition;
+        private StandardCursorType _lastCursorType;
+        private object _originalCursor;
+        private InputModifiers? _initialInputModifiers;
+
+        public InProcessDragSource()
+        {
+            _inputManager = AvaloniaLocator.Current.GetService<IInputManager>();
+            _dragDrop = AvaloniaLocator.Current.GetService<IDragDropDevice>();
+        }
+
+        public async Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+        {
+            Dispatcher.UIThread.VerifyAccess();
+            if (_draggedData == null)
+            {
+                _draggedData = data;
+                _lastRoot = null;
+                _lastPosition = default(Point);
+                _allowedEffects = allowedEffects;
+
+                using (_inputManager.PreProcess.OfType<RawMouseEventArgs>().Subscribe(ProcessMouseEvents))
+                {
+                    using (_inputManager.PreProcess.OfType<RawKeyEventArgs>().Subscribe(ProcessKeyEvents))
+                    {
+                        var effect = await _result.FirstAsync();
+                        return effect;
+                    }
+                }
+            }
+            return DragDropEffects.None;
+        }
+
+
+        private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputElement root, Point pt, InputModifiers modifiers)
+        {
+            _lastPosition = pt;
+
+            RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects);
+            var tl = root.GetSelfAndVisualAncestors().OfType<TopLevel>().FirstOrDefault();
+            tl.PlatformImpl.Input(rawEvent);
+
+            var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers);
+            UpdateCursor(root, effect);
+            return effect;
+        }
+
+        private DragDropEffects GetPreferredEffect(DragDropEffects effect, InputModifiers modifiers)
+        {
+            if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None)
+                return effect; // No need to check for the modifiers.
+            if (effect.HasFlag(DragDropEffects.Link) && modifiers.HasFlag(InputModifiers.Alt))
+                return DragDropEffects.Link;
+            if (effect.HasFlag(DragDropEffects.Copy) && modifiers.HasFlag(InputModifiers.Control))
+                return DragDropEffects.Copy;
+            return DragDropEffects.Move;
+        }
+
+        private StandardCursorType GetCursorForDropEffect(DragDropEffects effects)
+        {
+            if (effects.HasFlag(DragDropEffects.Copy))
+                return StandardCursorType.DragCopy;
+            if (effects.HasFlag(DragDropEffects.Move))
+                return StandardCursorType.DragMove;
+            if (effects.HasFlag(DragDropEffects.Link))
+                return StandardCursorType.DragLink;
+            return StandardCursorType.No;
+        }
+        
+        private void UpdateCursor(IInputElement root, DragDropEffects effect)
+        {
+            if (_lastRoot != root)
+            {
+                if (_lastRoot is InputElement ieLast)
+                {
+                    if (_originalCursor == AvaloniaProperty.UnsetValue)
+                        ieLast.ClearValue(InputElement.CursorProperty);
+                    else
+                        ieLast.Cursor = _originalCursor as Cursor;
+                }
+
+                if (root is InputElement ieNew)
+                {
+                    if (!ieNew.IsSet(InputElement.CursorProperty))
+                        _originalCursor = AvaloniaProperty.UnsetValue;
+                    else
+                        _originalCursor = root.Cursor;
+                }
+                else
+                    _originalCursor = null;
+
+                _lastCursorType = StandardCursorType.Arrow;
+                _lastRoot = root;
+            }
+
+            if (root is InputElement ie)
+            {
+                var ct = GetCursorForDropEffect(effect);
+                if (ct != _lastCursorType)
+                {
+                    _lastCursorType = ct;
+                    ie.Cursor = new Cursor(ct);
+                }
+            }  
+        }
+
+        private void CancelDragging()
+        {
+            if (_lastRoot != null)
+                RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, InputModifiers.None);
+            UpdateCursor(null, DragDropEffects.None);
+            _result.OnNext(DragDropEffects.None);
+        }
+
+        private void ProcessKeyEvents(RawKeyEventArgs e)
+        {
+            if (e.Type == RawKeyEventType.KeyDown && e.Key == Key.Escape)
+            {
+                if (_lastRoot != null)
+                    RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, e.Modifiers);
+                UpdateCursor(null, DragDropEffects.None);
+                _result.OnNext(DragDropEffects.None);
+                e.Handled = true;
+            }
+            else if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl || e.Key == Key.LeftAlt || e.Key == Key.RightAlt)
+                RaiseEventAndUpdateCursor(RawDragEventType.DragOver, _lastRoot, _lastPosition, e.Modifiers);
+        }
+
+        private void ProcessMouseEvents(RawMouseEventArgs e)
+        {
+            if (!_initialInputModifiers.HasValue)
+                _initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS;
+
+            
+            void CheckDraggingAccepted(InputModifiers changedMouseButton)
+            {
+                if (_initialInputModifiers.Value.HasFlag(changedMouseButton))
+                {
+                    var result = RaiseEventAndUpdateCursor(RawDragEventType.Drop, e.Root, e.Position, e.InputModifiers);
+                    UpdateCursor(null, DragDropEffects.None);
+                    _result.OnNext(result);
+                }
+                else
+                    CancelDragging();
+                e.Handled = true;
+            }
+            
+            switch (e.Type)
+            {
+                case RawMouseEventType.LeftButtonDown:
+                case RawMouseEventType.RightButtonDown:
+                case RawMouseEventType.MiddleButtonDown:
+                case RawMouseEventType.NonClientLeftButtonDown:
+                    CancelDragging();
+                    e.Handled = true;
+                    return;
+                case RawMouseEventType.LeaveWindow:
+                    RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, e.Root, e.Position,  e.InputModifiers); break;
+                case RawMouseEventType.LeftButtonUp:
+                    CheckDraggingAccepted(InputModifiers.LeftMouseButton); break;
+                case RawMouseEventType.MiddleButtonUp:
+                    CheckDraggingAccepted(InputModifiers.MiddleMouseButton); break;
+                case RawMouseEventType.RightButtonUp:
+                    CheckDraggingAccepted(InputModifiers.RightMouseButton); break;
+                case RawMouseEventType.Move:
+                    var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS;
+                    if (_initialInputModifiers.Value != mods)
+                    {
+                        CancelDragging();
+                        e.Handled = true;
+                        return;
+                    }
+
+                    if (e.Root != _lastRoot)
+                    {
+                        if (_lastRoot != null)
+                            RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastRoot.PointToClient(e.Root.PointToScreen(e.Position)), e.InputModifiers);
+                        RaiseEventAndUpdateCursor(RawDragEventType.DragEnter, e.Root, e.Position, e.InputModifiers);
+                    }
+                    else
+                        RaiseEventAndUpdateCursor(RawDragEventType.DragOver, e.Root, e.Position, e.InputModifiers);
+                    break;
+            }
+        }
+    }
+}

+ 41 - 6
src/Avalonia.Controls/Primitives/Popup.cs

@@ -215,7 +215,17 @@ namespace Avalonia.Controls.Primitives
             {
                 var window = _topLevel as Window;
                 if (window != null)
-                    window.Deactivated += WindowDeactivated;
+                {
+                    window.Deactivated += WindowDeactivated;                  
+                }
+                else
+                {
+                    var parentPopuproot = _topLevel as PopupRoot;
+                    if(parentPopuproot != null && parentPopuproot.Parent!=null)
+                    {
+                        ((Popup)(parentPopuproot.Parent)).Closed += ParentClosed;
+                    }
+                }
                 _topLevel.AddHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel);
                 _nonClientListener = InputManager.Instance.Process.Subscribe(ListenForNonClientClick);
             }
@@ -230,7 +240,7 @@ namespace Avalonia.Controls.Primitives
 
             Opened?.Invoke(this, EventArgs.Empty);
         }
-
+        
         /// <summary>
         /// Closes the popup.
         /// </summary>
@@ -244,6 +254,14 @@ namespace Avalonia.Controls.Primitives
                     var window = _topLevel as Window;
                     if (window != null)
                         window.Deactivated -= WindowDeactivated;
+                    else
+                    {
+                        var parentPopuproot = _topLevel as PopupRoot;
+                        if (parentPopuproot != null && parentPopuproot.Parent != null)
+                        {
+                            ((Popup)parentPopuproot.Parent).Closed -= ParentClosed;
+                        }
+                    }
                     _nonClientListener?.Dispose();
                     _nonClientListener = null;
                 }
@@ -381,16 +399,25 @@ namespace Avalonia.Controls.Primitives
         {
             if (!StaysOpen)
             {
-                var root = ((IVisual)e.Source).GetVisualRoot();
-
-                if (root != this.PopupRoot)
-                {
+                if(!IsChildOrThis((IVisual)e.Source))
+                {                     
                     Close();
                     e.Handled = true;
                 }
             }
         }
 
+        private bool IsChildOrThis(IVisual child)
+        {
+            IVisual root = child.GetVisualRoot();
+            while (root is PopupRoot)
+            {
+                if (root == PopupRoot) return true;              
+                root = ((PopupRoot)root).Parent.GetVisualRoot();
+            }
+            return false;
+        }
+        
         private void WindowDeactivated(object sender, EventArgs e)
         {
             if (!StaysOpen)
@@ -398,5 +425,13 @@ namespace Avalonia.Controls.Primitives
                 Close();
             }
         }
+
+        private void ParentClosed(object sender, EventArgs e)
+        {
+            if (!StaysOpen)
+            {
+                Close();
+            }
+        }
     }
 }

+ 2 - 2
src/Avalonia.Controls/TextBlock.cs

@@ -120,6 +120,7 @@ namespace Avalonia.Controls
                 .Subscribe(_ =>
                 {
                     InvalidateFormattedText();
+                    InvalidateMeasure();
                 });
         }
 
@@ -370,8 +371,6 @@ namespace Avalonia.Controls
                 _constraint = _formattedText.Constraint;
                 _formattedText = null;
             }
-
-            InvalidateMeasure();
         }
 
         /// <summary>
@@ -402,6 +401,7 @@ namespace Avalonia.Controls
         {
             base.OnAttachedToLogicalTree(e);
             InvalidateFormattedText();
+            InvalidateMeasure();
         }
     }
 }

+ 5 - 2
src/Avalonia.Controls/TextBox.cs

@@ -275,8 +275,11 @@ namespace Avalonia.Controls
 
         protected override void OnTextInput(TextInputEventArgs e)
         {
-            HandleTextInput(e.Text);
-            e.Handled = true;
+            if (!e.Handled)
+            {
+                HandleTextInput(e.Text);
+                e.Handled = true;
+            }
         }
 
         private void HandleTextInput(string input)

+ 2 - 1
src/Avalonia.Controls/Utils/UndoRedoHelper.cs

@@ -59,7 +59,7 @@ namespace Avalonia.Controls.Utils
 
         public void UpdateLastState()
         {
-            _states.Last.Value = _host.UndoRedoState;
+            UpdateLastState(_host.UndoRedoState);
         }
 
         public void DiscardRedo()
@@ -94,6 +94,7 @@ namespace Avalonia.Controls.Utils
         public void Clear()
         {
             _states.Clear();
+            _currentNode = null;
         }
 
         bool WeakTimer.IWeakTimerSubscriber.Tick()

+ 4 - 1
src/Avalonia.Input/Cursors.cs

@@ -38,7 +38,10 @@ namespace Avalonia.Input
         TopLeftCorner,
         TopRightCorner,
         BottomLeftCorner,
-        BottomRightCorner
+        BottomRightCorner,
+        DragMove,
+        DragCopy,
+        DragLink,
 
         // Not available in GTK directly, see http://www.pixelbeat.org/programming/x_cursors/ 
         // We might enable them later, preferably, by loading pixmax direclty from theme with fallback image

+ 15 - 0
src/Avalonia.Input/DataFormats.cs

@@ -0,0 +1,15 @@
+namespace Avalonia.Input
+{
+    public static class DataFormats
+    {
+        /// <summary>
+        /// Dataformat for plaintext
+        /// </summary>
+        public static string Text = nameof(Text);
+
+        /// <summary>
+        /// Dataformat for one or more filenames
+        /// </summary>
+        public static string FileNames = nameof(FileNames);
+    }
+}

+ 43 - 0
src/Avalonia.Input/DataObject.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Avalonia.Input
+{
+    public class DataObject : IDataObject
+    {
+        private readonly Dictionary<string, object> _items = new Dictionary<string, object>();
+
+        public bool Contains(string dataFormat)
+        {
+            return _items.ContainsKey(dataFormat);
+        }
+
+        public object Get(string dataFormat)
+        {
+            if (_items.ContainsKey(dataFormat))
+                return _items[dataFormat];
+            return null;
+        }
+
+        public IEnumerable<string> GetDataFormats()
+        {
+            return _items.Keys;
+        }
+
+        public IEnumerable<string> GetFileNames()
+        {
+            return Get(DataFormats.FileNames) as IEnumerable<string>;
+        }
+
+        public string GetText()
+        {
+            return Get(DataFormats.Text) as string;
+        }
+
+        public void Set(string dataFormat, object value)
+        {
+            _items[dataFormat] = value;
+        }
+    }
+}

+ 54 - 0
src/Avalonia.Input/DragDrop.cs

@@ -0,0 +1,54 @@
+using System.Threading.Tasks;
+using Avalonia.Interactivity;
+using Avalonia.Input.Platform;
+
+namespace Avalonia.Input
+{
+    public static class DragDrop
+    {
+        /// <summary>
+        /// Event which is raised, when a drag-and-drop operation enters the element.
+        /// </summary>
+        public static RoutedEvent<DragEventArgs> DragEnterEvent = RoutedEvent.Register<DragEventArgs>("DragEnter", RoutingStrategies.Bubble, typeof(DragDrop));
+        /// <summary>
+        /// Event which is raised, when a drag-and-drop operation leaves the element.
+        /// </summary>
+        public static RoutedEvent<RoutedEventArgs> DragLeaveEvent = RoutedEvent.Register<RoutedEventArgs>("DragLeave", RoutingStrategies.Bubble, typeof(DragDrop));
+        /// <summary>
+        /// Event which is raised, when a drag-and-drop operation is updated while over the element.
+        /// </summary>
+        public static RoutedEvent<DragEventArgs> DragOverEvent = RoutedEvent.Register<DragEventArgs>("DragOver", RoutingStrategies.Bubble, typeof(DragDrop));
+        /// <summary>
+        /// Event which is raised, when a drag-and-drop operation should complete over the element.
+        /// </summary>
+        public static RoutedEvent<DragEventArgs> DropEvent = RoutedEvent.Register<DragEventArgs>("Drop", RoutingStrategies.Bubble, typeof(DragDrop));
+
+        public static AvaloniaProperty<bool> AllowDropProperty = AvaloniaProperty.RegisterAttached<Interactive, bool>("AllowDrop", typeof(DragDrop), inherits: true);
+
+        /// <summary>
+        /// Gets a value indicating whether the given element can be used as the target of a drag-and-drop operation. 
+        /// </summary>
+        public static bool GetAllowDrop(Interactive interactive)
+        {
+            return interactive.GetValue(AllowDropProperty);
+        }
+
+        /// <summary>
+        /// Sets a value indicating whether the given interactive can be used as the target of a drag-and-drop operation. 
+        /// </summary>
+        public static void SetAllowDrop(Interactive interactive, bool value)
+        {
+            interactive.SetValue(AllowDropProperty, value);
+        }
+
+        /// <summary>
+        /// Starts a dragging operation with the given <see cref="IDataObject"/> and returns the applied drop effect from the target.
+        /// <seealso cref="DataObject"/>
+        /// </summary>
+        public static Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+        {
+            var src = AvaloniaLocator.Current.GetService<IPlatformDragSource>();
+            return src?.DoDragDrop(data, allowedEffects) ?? Task.FromResult(DragDropEffects.None);
+        }
+    }
+}

+ 111 - 0
src/Avalonia.Input/DragDropDevice.cs

@@ -0,0 +1,111 @@
+using Avalonia.Interactivity;
+using Avalonia.VisualTree;
+using System.Linq;
+using Avalonia.Input.Raw;
+
+namespace Avalonia.Input
+{
+    public class DragDropDevice : IDragDropDevice
+    {
+        public static readonly DragDropDevice Instance = new DragDropDevice();
+        
+        private Interactive _lastTarget = null;
+        
+        private Interactive GetTarget(IInputElement root, Point local)
+        {
+            var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
+            if (target != null && DragDrop.GetAllowDrop(target))
+                return target;
+            return null;
+        }
+        
+        private DragDropEffects RaiseDragEvent(Interactive target, RoutedEvent<DragEventArgs> routedEvent, DragDropEffects operation, IDataObject data)
+        {
+            if (target == null)
+                return DragDropEffects.None;
+            var args = new DragEventArgs(routedEvent, data)
+            {
+                RoutedEvent = routedEvent,
+                DragEffects = operation
+            };
+            target.RaiseEvent(args);
+            return args.DragEffects;
+        }
+        
+        private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+        {
+            _lastTarget = GetTarget(inputRoot, point);
+            return RaiseDragEvent(_lastTarget, DragDrop.DragEnterEvent, effects, data);
+        }
+
+        private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+        {
+            var target = GetTarget(inputRoot, point);
+
+            if (target == _lastTarget)
+                return RaiseDragEvent(target, DragDrop.DragOverEvent, effects, data);
+            
+            try
+            {
+                if (_lastTarget != null)
+                    _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent));
+                return RaiseDragEvent(target, DragDrop.DragEnterEvent, effects, data);
+            }
+            finally
+            {
+                _lastTarget = target;
+            }            
+        }
+
+        private void DragLeave(IInputElement inputRoot)
+        {
+            if (_lastTarget == null)
+                return;
+            try
+            {
+                _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent));
+            }
+            finally 
+            {
+                _lastTarget = null;
+            }
+        }
+
+        private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+        {
+            try
+            {
+                return RaiseDragEvent(_lastTarget, DragDrop.DropEvent, effects, data);
+            }
+            finally 
+            {
+                _lastTarget = null;
+            }
+        }
+
+        public void ProcessRawEvent(RawInputEventArgs e)
+        {
+            if (!e.Handled && e is RawDragEvent margs)
+                ProcessRawEvent(margs);
+        }
+
+        private void ProcessRawEvent(RawDragEvent e)
+        {
+            switch (e.Type)
+            {
+                case RawDragEventType.DragEnter:
+                    e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects);
+                    break;
+                case RawDragEventType.DragOver:
+                    e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects);
+                    break;
+                case RawDragEventType.DragLeave:
+                    DragLeave(e.InputRoot);
+                    break;
+                case RawDragEventType.Drop:
+                    e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects);
+                    break;
+            }
+        }
+    }
+}

+ 13 - 0
src/Avalonia.Input/DragDropEffects.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace Avalonia.Input
+{
+    [Flags]
+    public enum DragDropEffects
+    {
+        None = 0,
+        Copy = 1,
+        Move = 2,
+        Link = 4,
+    }
+}

+ 18 - 0
src/Avalonia.Input/DragEventArgs.cs

@@ -0,0 +1,18 @@
+using Avalonia.Interactivity;
+
+namespace Avalonia.Input
+{
+    public class DragEventArgs : RoutedEventArgs
+    {
+        public DragDropEffects DragEffects { get; set; }
+
+        public IDataObject Data { get; private set; }
+
+        public DragEventArgs(RoutedEvent<DragEventArgs> routedEvent, IDataObject data)
+            : base(routedEvent)
+        {
+            this.Data = data;
+        }
+
+    }
+}

+ 39 - 0
src/Avalonia.Input/IDataObject.cs

@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Input
+{
+    /// <summary>
+    /// Interface to access information about the data of a drag-and-drop operation.
+    /// </summary>
+    public interface IDataObject
+    {
+        /// <summary>
+        /// Lists all formats which are present in the DataObject.
+        /// <seealso cref="DataFormats"/>
+        /// </summary>
+        IEnumerable<string> GetDataFormats();
+
+        /// <summary>
+        /// Checks wether a given DataFormat is present in this object
+        /// <seealso cref="DataFormats"/>
+        /// </summary>
+        bool Contains(string dataFormat);
+
+        /// <summary>
+        /// Returns the dragged text if the DataObject contains any text.
+        /// <seealso cref="DataFormats.Text"/>
+        /// </summary>
+        string GetText();
+
+        /// <summary>
+        /// Returns a list of filenames if the DataObject contains filenames.
+        /// <seealso cref="DataFormats.FileNames"/>
+        /// </summary>
+        IEnumerable<string> GetFileNames();
+        
+        /// <summary>
+        /// Tries to get the data of the given DataFormat.
+        /// </summary>
+        object Get(string dataFormat);
+    }
+}

+ 14 - 0
src/Avalonia.Input/Platform/IPlatformDragSource.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+
+namespace Avalonia.Input.Platform
+{
+    public interface IPlatformDragSource
+    {
+        Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects);
+    }
+}

+ 8 - 0
src/Avalonia.Input/Raw/IDragDropDevice.cs

@@ -0,0 +1,8 @@
+using Avalonia.Input;
+
+namespace Avalonia.Input.Raw
+{
+    public interface IDragDropDevice : IInputDevice
+    {
+    }
+}

+ 26 - 0
src/Avalonia.Input/Raw/RawDragEvent.cs

@@ -0,0 +1,26 @@
+using System;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+
+namespace Avalonia.Input.Raw
+{
+    public class RawDragEvent : RawInputEventArgs
+    {
+        public IInputElement InputRoot { get; }
+        public Point Location { get; }
+        public IDataObject Data { get; }
+        public DragDropEffects Effects { get; set; }
+        public RawDragEventType Type { get; }
+
+        public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type, 
+            IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects)
+            :base(inputDevice, 0)
+        {
+            Type = type;
+            InputRoot = inputRoot;
+            Location = location;
+            Data = data;
+            Effects = effects;
+        }
+    }
+}

+ 10 - 0
src/Avalonia.Input/Raw/RawDragEventType.cs

@@ -0,0 +1,10 @@
+namespace Avalonia.Input.Raw
+{
+    public enum RawDragEventType
+    {
+        DragEnter,
+        DragOver,
+        DragLeave,
+        Drop
+    }
+}

+ 9 - 15
src/Avalonia.Visuals/Matrix.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -317,23 +318,16 @@ namespace Avalonia
         /// <returns>The <see cref="Matrix"/>.</returns>
         public static Matrix Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToArray();
-
-            if (parts.Length == 6)
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Matrix"))
             {
                 return new Matrix(
-                    double.Parse(parts[0], culture), 
-                    double.Parse(parts[1], culture), 
-                    double.Parse(parts[2], culture), 
-                    double.Parse(parts[3], culture), 
-                    double.Parse(parts[4], culture), 
-                    double.Parse(parts[5], culture));
-            }
-            else
-            {
-                throw new FormatException("Invalid Matrix.");
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble()
+                );
             }
         }
     }

+ 9 - 14
src/Avalonia.Visuals/Media/Brush.cs

@@ -34,26 +34,21 @@ namespace Avalonia.Media
         /// <returns>The <see cref="Color"/>.</returns>
         public static IBrush Parse(string s)
         {
+            Contract.Requires<ArgumentNullException>(s != null);
+            Contract.Requires<FormatException>(s.Length > 0);
+
             if (s[0] == '#')
             {
                 return new SolidColorBrush(Color.Parse(s));
             }
-            else
-            {
-                var upper = s.ToUpperInvariant();
-                var member = typeof(Brushes).GetTypeInfo().DeclaredProperties
-                    .FirstOrDefault(x => x.Name.ToUpperInvariant() == upper);
 
-                if (member != null)
-                {
-                    var brush = (ISolidColorBrush)member.GetValue(null);
-                    return new SolidColorBrush(brush.Color, brush.Opacity);
-                }
-                else
-                {
-                    throw new FormatException($"Invalid brush string: '{s}'.");
-                }
+            var brush = KnownColors.GetKnownBrush(s);
+            if (brush != null)
+            {
+                return brush;
             }
+
+            throw new FormatException($"Invalid brush string: '{s}'.");
         }
     }
 }

+ 142 - 292
src/Avalonia.Visuals/Media/Brushes.cs

@@ -1,8 +1,6 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
-using Avalonia.Media.Immutable;
-
 namespace Avalonia.Media
 {
     /// <summary>
@@ -10,857 +8,709 @@ namespace Avalonia.Media
     /// </summary>
     public static class Brushes
     {
-        /// <summary>
-        /// Initializes static members of the <see cref="Brushes"/> class.
-        /// </summary>
-        static Brushes()
-        {
-            AliceBlue = new ImmutableSolidColorBrush(Colors.AliceBlue);
-            AntiqueWhite = new ImmutableSolidColorBrush(Colors.AntiqueWhite);
-            Aqua = new ImmutableSolidColorBrush(Colors.Aqua);
-            Aquamarine = new ImmutableSolidColorBrush(Colors.Aquamarine);
-            Azure = new ImmutableSolidColorBrush(Colors.Azure);
-            Beige = new ImmutableSolidColorBrush(Colors.Beige);
-            Bisque = new ImmutableSolidColorBrush(Colors.Bisque);
-            Black = new ImmutableSolidColorBrush(Colors.Black);
-            BlanchedAlmond = new ImmutableSolidColorBrush(Colors.BlanchedAlmond);
-            Blue = new ImmutableSolidColorBrush(Colors.Blue);
-            BlueViolet = new ImmutableSolidColorBrush(Colors.BlueViolet);
-            Brown = new ImmutableSolidColorBrush(Colors.Brown);
-            BurlyWood = new ImmutableSolidColorBrush(Colors.BurlyWood);
-            CadetBlue = new ImmutableSolidColorBrush(Colors.CadetBlue);
-            Chartreuse = new ImmutableSolidColorBrush(Colors.Chartreuse);
-            Chocolate = new ImmutableSolidColorBrush(Colors.Chocolate);
-            Coral = new ImmutableSolidColorBrush(Colors.Coral);
-            CornflowerBlue = new ImmutableSolidColorBrush(Colors.CornflowerBlue);
-            Cornsilk = new ImmutableSolidColorBrush(Colors.Cornsilk);
-            Crimson = new ImmutableSolidColorBrush(Colors.Crimson);
-            Cyan = new ImmutableSolidColorBrush(Colors.Cyan);
-            DarkBlue = new ImmutableSolidColorBrush(Colors.DarkBlue);
-            DarkCyan = new ImmutableSolidColorBrush(Colors.DarkCyan);
-            DarkGoldenrod = new ImmutableSolidColorBrush(Colors.DarkGoldenrod);
-            DarkGray = new ImmutableSolidColorBrush(Colors.DarkGray);
-            DarkGreen = new ImmutableSolidColorBrush(Colors.DarkGreen);
-            DarkKhaki = new ImmutableSolidColorBrush(Colors.DarkKhaki);
-            DarkMagenta = new ImmutableSolidColorBrush(Colors.DarkMagenta);
-            DarkOliveGreen = new ImmutableSolidColorBrush(Colors.DarkOliveGreen);
-            DarkOrange = new ImmutableSolidColorBrush(Colors.DarkOrange);
-            DarkOrchid = new ImmutableSolidColorBrush(Colors.DarkOrchid);
-            DarkRed = new ImmutableSolidColorBrush(Colors.DarkRed);
-            DarkSalmon = new ImmutableSolidColorBrush(Colors.DarkSalmon);
-            DarkSeaGreen = new ImmutableSolidColorBrush(Colors.DarkSeaGreen);
-            DarkSlateBlue = new ImmutableSolidColorBrush(Colors.DarkSlateBlue);
-            DarkSlateGray = new ImmutableSolidColorBrush(Colors.DarkSlateGray);
-            DarkTurquoise = new ImmutableSolidColorBrush(Colors.DarkTurquoise);
-            DarkViolet = new ImmutableSolidColorBrush(Colors.DarkViolet);
-            DeepPink = new ImmutableSolidColorBrush(Colors.DeepPink);
-            DeepSkyBlue = new ImmutableSolidColorBrush(Colors.DeepSkyBlue);
-            DimGray = new ImmutableSolidColorBrush(Colors.DimGray);
-            DodgerBlue = new ImmutableSolidColorBrush(Colors.DodgerBlue);
-            Firebrick = new ImmutableSolidColorBrush(Colors.Firebrick);
-            FloralWhite = new ImmutableSolidColorBrush(Colors.FloralWhite);
-            ForestGreen = new ImmutableSolidColorBrush(Colors.ForestGreen);
-            Fuchsia = new ImmutableSolidColorBrush(Colors.Fuchsia);
-            Gainsboro = new ImmutableSolidColorBrush(Colors.Gainsboro);
-            GhostWhite = new ImmutableSolidColorBrush(Colors.GhostWhite);
-            Gold = new ImmutableSolidColorBrush(Colors.Gold);
-            Goldenrod = new ImmutableSolidColorBrush(Colors.Goldenrod);
-            Gray = new ImmutableSolidColorBrush(Colors.Gray);
-            Green = new ImmutableSolidColorBrush(Colors.Green);
-            GreenYellow = new ImmutableSolidColorBrush(Colors.GreenYellow);
-            Honeydew = new ImmutableSolidColorBrush(Colors.Honeydew);
-            HotPink = new ImmutableSolidColorBrush(Colors.HotPink);
-            IndianRed = new ImmutableSolidColorBrush(Colors.IndianRed);
-            Indigo = new ImmutableSolidColorBrush(Colors.Indigo);
-            Ivory = new ImmutableSolidColorBrush(Colors.Ivory);
-            Khaki = new ImmutableSolidColorBrush(Colors.Khaki);
-            Lavender = new ImmutableSolidColorBrush(Colors.Lavender);
-            LavenderBlush = new ImmutableSolidColorBrush(Colors.LavenderBlush);
-            LawnGreen = new ImmutableSolidColorBrush(Colors.LawnGreen);
-            LemonChiffon = new ImmutableSolidColorBrush(Colors.LemonChiffon);
-            LightBlue = new ImmutableSolidColorBrush(Colors.LightBlue);
-            LightCoral = new ImmutableSolidColorBrush(Colors.LightCoral);
-            LightCyan = new ImmutableSolidColorBrush(Colors.LightCyan);
-            LightGoldenrodYellow = new ImmutableSolidColorBrush(Colors.LightGoldenrodYellow);
-            LightGray = new ImmutableSolidColorBrush(Colors.LightGray);
-            LightGreen = new ImmutableSolidColorBrush(Colors.LightGreen);
-            LightPink = new ImmutableSolidColorBrush(Colors.LightPink);
-            LightSalmon = new ImmutableSolidColorBrush(Colors.LightSalmon);
-            LightSeaGreen = new ImmutableSolidColorBrush(Colors.LightSeaGreen);
-            LightSkyBlue = new ImmutableSolidColorBrush(Colors.LightSkyBlue);
-            LightSlateGray = new ImmutableSolidColorBrush(Colors.LightSlateGray);
-            LightSteelBlue = new ImmutableSolidColorBrush(Colors.LightSteelBlue);
-            LightYellow = new ImmutableSolidColorBrush(Colors.LightYellow);
-            Lime = new ImmutableSolidColorBrush(Colors.Lime);
-            LimeGreen = new ImmutableSolidColorBrush(Colors.LimeGreen);
-            Linen = new ImmutableSolidColorBrush(Colors.Linen);
-            Magenta = new ImmutableSolidColorBrush(Colors.Magenta);
-            Maroon = new ImmutableSolidColorBrush(Colors.Maroon);
-            MediumAquamarine = new ImmutableSolidColorBrush(Colors.MediumAquamarine);
-            MediumBlue = new ImmutableSolidColorBrush(Colors.MediumBlue);
-            MediumOrchid = new ImmutableSolidColorBrush(Colors.MediumOrchid);
-            MediumPurple = new ImmutableSolidColorBrush(Colors.MediumPurple);
-            MediumSeaGreen = new ImmutableSolidColorBrush(Colors.MediumSeaGreen);
-            MediumSlateBlue = new ImmutableSolidColorBrush(Colors.MediumSlateBlue);
-            MediumSpringGreen = new ImmutableSolidColorBrush(Colors.MediumSpringGreen);
-            MediumTurquoise = new ImmutableSolidColorBrush(Colors.MediumTurquoise);
-            MediumVioletRed = new ImmutableSolidColorBrush(Colors.MediumVioletRed);
-            MidnightBlue = new ImmutableSolidColorBrush(Colors.MidnightBlue);
-            MintCream = new ImmutableSolidColorBrush(Colors.MintCream);
-            MistyRose = new ImmutableSolidColorBrush(Colors.MistyRose);
-            Moccasin = new ImmutableSolidColorBrush(Colors.Moccasin);
-            NavajoWhite = new ImmutableSolidColorBrush(Colors.NavajoWhite);
-            Navy = new ImmutableSolidColorBrush(Colors.Navy);
-            OldLace = new ImmutableSolidColorBrush(Colors.OldLace);
-            Olive = new ImmutableSolidColorBrush(Colors.Olive);
-            OliveDrab = new ImmutableSolidColorBrush(Colors.OliveDrab);
-            Orange = new ImmutableSolidColorBrush(Colors.Orange);
-            OrangeRed = new ImmutableSolidColorBrush(Colors.OrangeRed);
-            Orchid = new ImmutableSolidColorBrush(Colors.Orchid);
-            PaleGoldenrod = new ImmutableSolidColorBrush(Colors.PaleGoldenrod);
-            PaleGreen = new ImmutableSolidColorBrush(Colors.PaleGreen);
-            PaleTurquoise = new ImmutableSolidColorBrush(Colors.PaleTurquoise);
-            PaleVioletRed = new ImmutableSolidColorBrush(Colors.PaleVioletRed);
-            PapayaWhip = new ImmutableSolidColorBrush(Colors.PapayaWhip);
-            PeachPuff = new ImmutableSolidColorBrush(Colors.PeachPuff);
-            Peru = new ImmutableSolidColorBrush(Colors.Peru);
-            Pink = new ImmutableSolidColorBrush(Colors.Pink);
-            Plum = new ImmutableSolidColorBrush(Colors.Plum);
-            PowderBlue = new ImmutableSolidColorBrush(Colors.PowderBlue);
-            Purple = new ImmutableSolidColorBrush(Colors.Purple);
-            Red = new ImmutableSolidColorBrush(Colors.Red);
-            RosyBrown = new ImmutableSolidColorBrush(Colors.RosyBrown);
-            RoyalBlue = new ImmutableSolidColorBrush(Colors.RoyalBlue);
-            SaddleBrown = new ImmutableSolidColorBrush(Colors.SaddleBrown);
-            Salmon = new ImmutableSolidColorBrush(Colors.Salmon);
-            SandyBrown = new ImmutableSolidColorBrush(Colors.SandyBrown);
-            SeaGreen = new ImmutableSolidColorBrush(Colors.SeaGreen);
-            SeaShell = new ImmutableSolidColorBrush(Colors.SeaShell);
-            Sienna = new ImmutableSolidColorBrush(Colors.Sienna);
-            Silver = new ImmutableSolidColorBrush(Colors.Silver);
-            SkyBlue = new ImmutableSolidColorBrush(Colors.SkyBlue);
-            SlateBlue = new ImmutableSolidColorBrush(Colors.SlateBlue);
-            SlateGray = new ImmutableSolidColorBrush(Colors.SlateGray);
-            Snow = new ImmutableSolidColorBrush(Colors.Snow);
-            SpringGreen = new ImmutableSolidColorBrush(Colors.SpringGreen);
-            SteelBlue = new ImmutableSolidColorBrush(Colors.SteelBlue);
-            Tan = new ImmutableSolidColorBrush(Colors.Tan);
-            Teal = new ImmutableSolidColorBrush(Colors.Teal);
-            Thistle = new ImmutableSolidColorBrush(Colors.Thistle);
-            Tomato = new ImmutableSolidColorBrush(Colors.Tomato);
-            Transparent = new ImmutableSolidColorBrush(Colors.Transparent);
-            Turquoise = new ImmutableSolidColorBrush(Colors.Turquoise);
-            Violet = new ImmutableSolidColorBrush(Colors.Violet);
-            Wheat = new ImmutableSolidColorBrush(Colors.Wheat);
-            White = new ImmutableSolidColorBrush(Colors.White);
-            WhiteSmoke = new ImmutableSolidColorBrush(Colors.WhiteSmoke);
-            Yellow = new ImmutableSolidColorBrush(Colors.Yellow);
-            YellowGreen = new ImmutableSolidColorBrush(Colors.YellowGreen);
-        }
-
         /// <summary>
         /// Gets an <see cref="Colors.AliceBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush AliceBlue { get; private set; }
+        public static ISolidColorBrush AliceBlue => KnownColor.AliceBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.AntiqueWhite"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush AntiqueWhite { get; private set; }
+        public static ISolidColorBrush AntiqueWhite => KnownColor.AntiqueWhite.ToBrush();
 
         /// <summary>
-        /// Gets an <see cref="Colors.AliceBlue"/> colored brush.
+        /// Gets an <see cref="Colors.Aqua"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Aqua { get; private set; }
+        public static ISolidColorBrush Aqua => KnownColor.Aqua.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Aquamarine"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Aquamarine { get; private set; }
+        public static ISolidColorBrush Aquamarine => KnownColor.Aquamarine.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Azure"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Azure { get; private set; }
+        public static ISolidColorBrush Azure => KnownColor.Azure.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Beige"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Beige { get; private set; }
+        public static ISolidColorBrush Beige => KnownColor.Beige.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Bisque"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Bisque { get; private set; }
+        public static ISolidColorBrush Bisque => KnownColor.Bisque.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Black"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Black { get; private set; }
+        public static ISolidColorBrush Black => KnownColor.Black.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.BlanchedAlmond"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush BlanchedAlmond { get; private set; }
+        public static ISolidColorBrush BlanchedAlmond => KnownColor.BlanchedAlmond.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Blue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Blue { get; private set; }
+        public static ISolidColorBrush Blue => KnownColor.Blue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.BlueViolet"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush BlueViolet { get; private set; }
+        public static ISolidColorBrush BlueViolet => KnownColor.BlueViolet.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Brown"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Brown { get; private set; }
+        public static ISolidColorBrush Brown => KnownColor.Brown.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.BurlyWood"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush BurlyWood { get; private set; }
+        public static ISolidColorBrush BurlyWood => KnownColor.BurlyWood.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.CadetBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush CadetBlue { get; private set; }
+        public static ISolidColorBrush CadetBlue => KnownColor.CadetBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Chartreuse"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Chartreuse { get; private set; }
+        public static ISolidColorBrush Chartreuse => KnownColor.Chartreuse.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Chocolate"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Chocolate { get; private set; }
+        public static ISolidColorBrush Chocolate => KnownColor.Chocolate.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Coral"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Coral { get; private set; }
+        public static ISolidColorBrush Coral => KnownColor.Coral.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.CornflowerBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush CornflowerBlue { get; private set; }
+        public static ISolidColorBrush CornflowerBlue => KnownColor.CornflowerBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Cornsilk"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Cornsilk { get; private set; }
+        public static ISolidColorBrush Cornsilk => KnownColor.Cornsilk.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Crimson"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Crimson { get; private set; }
+        public static ISolidColorBrush Crimson => KnownColor.Crimson.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Cyan"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Cyan { get; private set; }
+        public static ISolidColorBrush Cyan => KnownColor.Cyan.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkBlue { get; private set; }
+        public static ISolidColorBrush DarkBlue => KnownColor.DarkBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkCyan"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkCyan { get; private set; }
+        public static ISolidColorBrush DarkCyan => KnownColor.DarkCyan.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkGoldenrod"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkGoldenrod { get; private set; }
+        public static ISolidColorBrush DarkGoldenrod => KnownColor.DarkGoldenrod.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkGray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkGray { get; private set; }
+        public static ISolidColorBrush DarkGray => KnownColor.DarkGray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkGreen { get; private set; }
+        public static ISolidColorBrush DarkGreen => KnownColor.DarkGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkKhaki"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkKhaki { get; private set; }
+        public static ISolidColorBrush DarkKhaki => KnownColor.DarkKhaki.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkMagenta"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkMagenta { get; private set; }
+        public static ISolidColorBrush DarkMagenta => KnownColor.DarkMagenta.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkOliveGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkOliveGreen { get; private set; }
+        public static ISolidColorBrush DarkOliveGreen => KnownColor.DarkOliveGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkOrange"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkOrange { get; private set; }
+        public static ISolidColorBrush DarkOrange => KnownColor.DarkOrange.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkOrchid"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkOrchid { get; private set; }
+        public static ISolidColorBrush DarkOrchid => KnownColor.DarkOrchid.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkRed"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkRed { get; private set; }
+        public static ISolidColorBrush DarkRed => KnownColor.DarkRed.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkSalmon"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkSalmon { get; private set; }
+        public static ISolidColorBrush DarkSalmon => KnownColor.DarkSalmon.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkSeaGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkSeaGreen { get; private set; }
+        public static ISolidColorBrush DarkSeaGreen => KnownColor.DarkSeaGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkSlateBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkSlateBlue { get; private set; }
+        public static ISolidColorBrush DarkSlateBlue => KnownColor.DarkSlateBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkSlateGray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkSlateGray { get; private set; }
+        public static ISolidColorBrush DarkSlateGray => KnownColor.DarkSlateGray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkTurquoise"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkTurquoise { get; private set; }
+        public static ISolidColorBrush DarkTurquoise => KnownColor.DarkTurquoise.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DarkViolet"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DarkViolet { get; private set; }
+        public static ISolidColorBrush DarkViolet => KnownColor.DarkViolet.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DeepPink"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DeepPink { get; private set; }
+        public static ISolidColorBrush DeepPink => KnownColor.DeepPink.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DeepSkyBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DeepSkyBlue { get; private set; }
+        public static ISolidColorBrush DeepSkyBlue => KnownColor.DeepSkyBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DimGray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DimGray { get; private set; }
+        public static ISolidColorBrush DimGray => KnownColor.DimGray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.DodgerBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush DodgerBlue { get; private set; }
+        public static ISolidColorBrush DodgerBlue => KnownColor.DodgerBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Firebrick"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Firebrick { get; private set; }
+        public static ISolidColorBrush Firebrick => KnownColor.Firebrick.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.FloralWhite"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush FloralWhite { get; private set; }
+        public static ISolidColorBrush FloralWhite => KnownColor.FloralWhite.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.ForestGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush ForestGreen { get; private set; }
+        public static ISolidColorBrush ForestGreen => KnownColor.ForestGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Fuchsia"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Fuchsia { get; private set; }
+        public static ISolidColorBrush Fuchsia => KnownColor.Fuchsia.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Gainsboro"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Gainsboro { get; private set; }
+        public static ISolidColorBrush Gainsboro => KnownColor.Gainsboro.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.GhostWhite"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush GhostWhite { get; private set; }
+        public static ISolidColorBrush GhostWhite => KnownColor.GhostWhite.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Gold"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Gold { get; private set; }
+        public static ISolidColorBrush Gold => KnownColor.Gold.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Goldenrod"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Goldenrod { get; private set; }
+        public static ISolidColorBrush Goldenrod => KnownColor.Goldenrod.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Gray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Gray { get; private set; }
+        public static ISolidColorBrush Gray => KnownColor.Gray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Green"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Green { get; private set; }
+        public static ISolidColorBrush Green => KnownColor.Green.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.GreenYellow"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush GreenYellow { get; private set; }
+        public static ISolidColorBrush GreenYellow => KnownColor.GreenYellow.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Honeydew"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Honeydew { get; private set; }
+        public static ISolidColorBrush Honeydew => KnownColor.Honeydew.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.HotPink"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush HotPink { get; private set; }
+        public static ISolidColorBrush HotPink => KnownColor.HotPink.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.IndianRed"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush IndianRed { get; private set; }
+        public static ISolidColorBrush IndianRed => KnownColor.IndianRed.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Indigo"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Indigo { get; private set; }
+        public static ISolidColorBrush Indigo => KnownColor.Indigo.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Ivory"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Ivory { get; private set; }
+        public static ISolidColorBrush Ivory => KnownColor.Ivory.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Khaki"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Khaki { get; private set; }
+        public static ISolidColorBrush Khaki => KnownColor.Khaki.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Lavender"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Lavender { get; private set; }
+        public static ISolidColorBrush Lavender => KnownColor.Lavender.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LavenderBlush"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LavenderBlush { get; private set; }
+        public static ISolidColorBrush LavenderBlush => KnownColor.LavenderBlush.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LawnGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LawnGreen { get; private set; }
+        public static ISolidColorBrush LawnGreen => KnownColor.LawnGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LemonChiffon"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LemonChiffon { get; private set; }
+        public static ISolidColorBrush LemonChiffon => KnownColor.LemonChiffon.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightBlue { get; private set; }
+        public static ISolidColorBrush LightBlue => KnownColor.LightBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightCoral"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightCoral { get; private set; }
+        public static ISolidColorBrush LightCoral => KnownColor.LightCoral.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightCyan"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightCyan { get; private set; }
+        public static ISolidColorBrush LightCyan => KnownColor.LightCyan.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightGoldenrodYellow"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightGoldenrodYellow { get; private set; }
+        public static ISolidColorBrush LightGoldenrodYellow => KnownColor.LightGoldenrodYellow.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightGray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightGray { get; private set; }
+        public static ISolidColorBrush LightGray => KnownColor.LightGray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightGreen { get; private set; }
+        public static ISolidColorBrush LightGreen => KnownColor.LightGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightPink"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightPink { get; private set; }
+        public static ISolidColorBrush LightPink => KnownColor.LightPink.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightSalmon"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightSalmon { get; private set; }
+        public static ISolidColorBrush LightSalmon => KnownColor.LightSalmon.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightSeaGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightSeaGreen { get; private set; }
+        public static ISolidColorBrush LightSeaGreen => KnownColor.LightSeaGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightSkyBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightSkyBlue { get; private set; }
+        public static ISolidColorBrush LightSkyBlue => KnownColor.LightSkyBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightSlateGray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightSlateGray { get; private set; }
+        public static ISolidColorBrush LightSlateGray => KnownColor.LightSlateGray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightSteelBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightSteelBlue { get; private set; }
+        public static ISolidColorBrush LightSteelBlue => KnownColor.LightSteelBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LightYellow"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LightYellow { get; private set; }
+        public static ISolidColorBrush LightYellow => KnownColor.LightYellow.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Lime"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Lime { get; private set; }
+        public static ISolidColorBrush Lime => KnownColor.Lime.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.LimeGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush LimeGreen { get; private set; }
+        public static ISolidColorBrush LimeGreen => KnownColor.LimeGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Linen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Linen { get; private set; }
+        public static ISolidColorBrush Linen => KnownColor.Linen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Magenta"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Magenta { get; private set; }
+        public static ISolidColorBrush Magenta => KnownColor.Magenta.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Maroon"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Maroon { get; private set; }
+        public static ISolidColorBrush Maroon => KnownColor.Maroon.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumAquamarine"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumAquamarine { get; private set; }
+        public static ISolidColorBrush MediumAquamarine => KnownColor.MediumAquamarine.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumBlue { get; private set; }
+        public static ISolidColorBrush MediumBlue => KnownColor.MediumBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumOrchid"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumOrchid { get; private set; }
+        public static ISolidColorBrush MediumOrchid => KnownColor.MediumOrchid.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumPurple"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumPurple { get; private set; }
+        public static ISolidColorBrush MediumPurple => KnownColor.MediumPurple.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumSeaGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumSeaGreen { get; private set; }
+        public static ISolidColorBrush MediumSeaGreen => KnownColor.MediumSeaGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumSlateBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumSlateBlue { get; private set; }
+        public static ISolidColorBrush MediumSlateBlue => KnownColor.MediumSlateBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumSpringGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumSpringGreen { get; private set; }
+        public static ISolidColorBrush MediumSpringGreen => KnownColor.MediumSpringGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumTurquoise"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumTurquoise { get; private set; }
+        public static ISolidColorBrush MediumTurquoise => KnownColor.MediumTurquoise.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MediumVioletRed"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MediumVioletRed { get; private set; }
+        public static ISolidColorBrush MediumVioletRed => KnownColor.MediumVioletRed.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MidnightBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MidnightBlue { get; private set; }
+        public static ISolidColorBrush MidnightBlue => KnownColor.MidnightBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MintCream"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MintCream { get; private set; }
+        public static ISolidColorBrush MintCream => KnownColor.MintCream.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.MistyRose"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush MistyRose { get; private set; }
+        public static ISolidColorBrush MistyRose => KnownColor.MistyRose.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Moccasin"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Moccasin { get; private set; }
+        public static ISolidColorBrush Moccasin => KnownColor.Moccasin.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.NavajoWhite"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush NavajoWhite { get; private set; }
+        public static ISolidColorBrush NavajoWhite => KnownColor.NavajoWhite.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Navy"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Navy { get; private set; }
+        public static ISolidColorBrush Navy => KnownColor.Navy.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.OldLace"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush OldLace { get; private set; }
+        public static ISolidColorBrush OldLace => KnownColor.OldLace.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Olive"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Olive { get; private set; }
+        public static ISolidColorBrush Olive => KnownColor.Olive.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.OliveDrab"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush OliveDrab { get; private set; }
+        public static ISolidColorBrush OliveDrab => KnownColor.OliveDrab.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Orange"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Orange { get; private set; }
+        public static ISolidColorBrush Orange => KnownColor.Orange.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.OrangeRed"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush OrangeRed { get; private set; }
+        public static ISolidColorBrush OrangeRed => KnownColor.OrangeRed.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Orchid"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Orchid { get; private set; }
+        public static ISolidColorBrush Orchid => KnownColor.Orchid.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PaleGoldenrod"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PaleGoldenrod { get; private set; }
+        public static ISolidColorBrush PaleGoldenrod => KnownColor.PaleGoldenrod.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PaleGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PaleGreen { get; private set; }
+        public static ISolidColorBrush PaleGreen => KnownColor.PaleGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PaleTurquoise"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PaleTurquoise { get; private set; }
+        public static ISolidColorBrush PaleTurquoise => KnownColor.PaleTurquoise.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PaleVioletRed"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PaleVioletRed { get; private set; }
+        public static ISolidColorBrush PaleVioletRed => KnownColor.PaleVioletRed.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PapayaWhip"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PapayaWhip { get; private set; }
+        public static ISolidColorBrush PapayaWhip => KnownColor.PapayaWhip.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PeachPuff"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PeachPuff { get; private set; }
+        public static ISolidColorBrush PeachPuff => KnownColor.PeachPuff.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Peru"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Peru { get; private set; }
+        public static ISolidColorBrush Peru => KnownColor.Peru.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Pink"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Pink { get; private set; }
+        public static ISolidColorBrush Pink => KnownColor.Pink.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Plum"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Plum { get; private set; }
+        public static ISolidColorBrush Plum => KnownColor.Plum.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.PowderBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush PowderBlue { get; private set; }
+        public static ISolidColorBrush PowderBlue => KnownColor.PowderBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Purple"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Purple { get; private set; }
+        public static ISolidColorBrush Purple => KnownColor.Purple.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Red"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Red { get; private set; }
+        public static ISolidColorBrush Red => KnownColor.Red.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.RosyBrown"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush RosyBrown { get; private set; }
+        public static ISolidColorBrush RosyBrown => KnownColor.RosyBrown.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.RoyalBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush RoyalBlue { get; private set; }
+        public static ISolidColorBrush RoyalBlue => KnownColor.RoyalBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SaddleBrown"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SaddleBrown { get; private set; }
+        public static ISolidColorBrush SaddleBrown => KnownColor.SaddleBrown.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Salmon"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Salmon { get; private set; }
+        public static ISolidColorBrush Salmon => KnownColor.Salmon.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SandyBrown"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SandyBrown { get; private set; }
+        public static ISolidColorBrush SandyBrown => KnownColor.SandyBrown.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SeaGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SeaGreen { get; private set; }
+        public static ISolidColorBrush SeaGreen => KnownColor.SeaGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SeaShell"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SeaShell { get; private set; }
+        public static ISolidColorBrush SeaShell => KnownColor.SeaShell.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Sienna"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Sienna { get; private set; }
+        public static ISolidColorBrush Sienna => KnownColor.Sienna.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Silver"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Silver { get; private set; }
+        public static ISolidColorBrush Silver => KnownColor.Silver.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SkyBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SkyBlue { get; private set; }
+        public static ISolidColorBrush SkyBlue => KnownColor.SkyBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SlateBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SlateBlue { get; private set; }
+        public static ISolidColorBrush SlateBlue => KnownColor.SlateBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SlateGray"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SlateGray { get; private set; }
+        public static ISolidColorBrush SlateGray => KnownColor.SlateGray.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Snow"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Snow { get; private set; }
+        public static ISolidColorBrush Snow => KnownColor.Snow.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SpringGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SpringGreen { get; private set; }
+        public static ISolidColorBrush SpringGreen => KnownColor.SpringGreen.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.SteelBlue"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush SteelBlue { get; private set; }
+        public static ISolidColorBrush SteelBlue => KnownColor.SteelBlue.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Tan"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Tan { get; private set; }
+        public static ISolidColorBrush Tan => KnownColor.Tan.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Teal"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Teal { get; private set; }
+        public static ISolidColorBrush Teal => KnownColor.Teal.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Thistle"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Thistle { get; private set; }
+        public static ISolidColorBrush Thistle => KnownColor.Thistle.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Tomato"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Tomato { get; private set; }
+        public static ISolidColorBrush Tomato => KnownColor.Tomato.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Transparent"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Transparent { get; private set; }
+        public static ISolidColorBrush Transparent => KnownColor.Transparent.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Turquoise"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Turquoise { get; private set; }
+        public static ISolidColorBrush Turquoise => KnownColor.Turquoise.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Violet"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Violet { get; private set; }
+        public static ISolidColorBrush Violet => KnownColor.Violet.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Wheat"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Wheat { get; private set; }
+        public static ISolidColorBrush Wheat => KnownColor.Wheat.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.White"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush White { get; private set; }
+        public static ISolidColorBrush White => KnownColor.White.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.WhiteSmoke"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush WhiteSmoke { get; private set; }
+        public static ISolidColorBrush WhiteSmoke => KnownColor.WhiteSmoke.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.Yellow"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush Yellow { get; private set; }
+        public static ISolidColorBrush Yellow => KnownColor.Yellow.ToBrush();
 
         /// <summary>
         /// Gets an <see cref="Colors.YellowGreen"/> colored brush.
         /// </summary>
-        public static ISolidColorBrush YellowGreen { get; private set; }
+        public static ISolidColorBrush YellowGreen => KnownColor.YellowGreen.ToBrush();
     }
 }

+ 12 - 15
src/Avalonia.Visuals/Media/Color.cs

@@ -115,6 +115,9 @@ namespace Avalonia.Media
         /// <returns>The <see cref="Color"/>.</returns>
         public static Color Parse(string s)
         {
+            if (s == null) throw new ArgumentNullException(nameof(s));
+            if (s.Length == 0) throw new FormatException();
+
             if (s[0] == '#')
             {
                 var or = 0u;
@@ -130,21 +133,15 @@ namespace Avalonia.Media
 
                 return FromUInt32(uint.Parse(s.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture) | or);
             }
-            else
-            {
-                var upper = s.ToUpperInvariant();
-                var member = typeof(Colors).GetTypeInfo().DeclaredProperties
-                    .FirstOrDefault(x => x.Name.ToUpperInvariant() == upper);
 
-                if (member != null)
-                {
-                    return (Color)member.GetValue(null);
-                }
-                else
-                {
-                    throw new FormatException($"Invalid color string: '{s}'.");
-                }
+            var knownColor = KnownColors.GetKnownColor(s);
+
+            if (knownColor != KnownColor.None)
+            {
+                return knownColor.ToColor();
             }
+
+            throw new FormatException($"Invalid color string: '{s}'.");
         }
 
         /// <summary>
@@ -155,8 +152,8 @@ namespace Avalonia.Media
         /// </returns>
         public override string ToString()
         {
-            uint rgb = ((uint)A << 24) | ((uint)R << 16) | ((uint)G << 8) | (uint)B;
-            return $"#{rgb:x8}";
+            uint rgb = ToUint32();
+            return KnownColors.GetKnownColorName(rgb) ?? $"#{rgb:x8}";
         }
 
         /// <summary>

+ 143 - 141
src/Avalonia.Visuals/Media/Colors.cs

@@ -1,6 +1,8 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System.Linq;
+
 namespace Avalonia.Media
 {
     /// <summary>
@@ -11,706 +13,706 @@ namespace Avalonia.Media
         /// <summary>
         /// Gets a color with an ARGB value of #fff0f8ff.
         /// </summary>
-        public static Color AliceBlue => Color.FromUInt32(0xfff0f8ff);
+        public static Color AliceBlue => KnownColor.AliceBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffaebd7.
         /// </summary>
-        public static Color AntiqueWhite => Color.FromUInt32(0xfffaebd7);
+        public static Color AntiqueWhite => KnownColor.AntiqueWhite.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00ffff.
         /// </summary>
-        public static Color Aqua => Color.FromUInt32(0xff00ffff);
+        public static Color Aqua => KnownColor.Aqua.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff7fffd4.
         /// </summary>
-        public static Color Aquamarine => Color.FromUInt32(0xff7fffd4);
+        public static Color Aquamarine => KnownColor.Aquamarine.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff0ffff.
         /// </summary>
-        public static Color Azure => Color.FromUInt32(0xfff0ffff);
+        public static Color Azure => KnownColor.Azure.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff5f5dc.
         /// </summary>
-        public static Color Beige => Color.FromUInt32(0xfff5f5dc);
+        public static Color Beige => KnownColor.Beige.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffe4c4.
         /// </summary>
-        public static Color Bisque => Color.FromUInt32(0xffffe4c4);
+        public static Color Bisque => KnownColor.Bisque.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff000000.
         /// </summary>
-        public static Color Black => Color.FromUInt32(0xff000000);
+        public static Color Black => KnownColor.Black.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffebcd.
         /// </summary>
-        public static Color BlanchedAlmond => Color.FromUInt32(0xffffebcd);
+        public static Color BlanchedAlmond => KnownColor.BlanchedAlmond.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff0000ff.
         /// </summary>
-        public static Color Blue => Color.FromUInt32(0xff0000ff);
+        public static Color Blue => KnownColor.Blue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff8a2be2.
         /// </summary>
-        public static Color BlueViolet => Color.FromUInt32(0xff8a2be2);
+        public static Color BlueViolet => KnownColor.BlueViolet.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffa52a2a.
         /// </summary>
-        public static Color Brown => Color.FromUInt32(0xffa52a2a);
+        public static Color Brown => KnownColor.Brown.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffdeb887.
         /// </summary>
-        public static Color BurlyWood => Color.FromUInt32(0xffdeb887);
+        public static Color BurlyWood => KnownColor.BurlyWood.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff5f9ea0.
         /// </summary>
-        public static Color CadetBlue => Color.FromUInt32(0xff5f9ea0);
+        public static Color CadetBlue => KnownColor.CadetBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff7fff00.
         /// </summary>
-        public static Color Chartreuse => Color.FromUInt32(0xff7fff00);
+        public static Color Chartreuse => KnownColor.Chartreuse.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffd2691e.
         /// </summary>
-        public static Color Chocolate => Color.FromUInt32(0xffd2691e);
+        public static Color Chocolate => KnownColor.Chocolate.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff7f50.
         /// </summary>
-        public static Color Coral => Color.FromUInt32(0xffff7f50);
+        public static Color Coral => KnownColor.Coral.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff6495ed.
         /// </summary>
-        public static Color CornflowerBlue => Color.FromUInt32(0xff6495ed);
+        public static Color CornflowerBlue => KnownColor.CornflowerBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffff8dc.
         /// </summary>
-        public static Color Cornsilk => Color.FromUInt32(0xfffff8dc);
+        public static Color Cornsilk => KnownColor.Cornsilk.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffdc143c.
         /// </summary>
-        public static Color Crimson => Color.FromUInt32(0xffdc143c);
+        public static Color Crimson => KnownColor.Crimson.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00ffff.
         /// </summary>
-        public static Color Cyan => Color.FromUInt32(0xff00ffff);
+        public static Color Cyan => KnownColor.Cyan.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00008b.
         /// </summary>
-        public static Color DarkBlue => Color.FromUInt32(0xff00008b);
+        public static Color DarkBlue => KnownColor.DarkBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff008b8b.
         /// </summary>
-        public static Color DarkCyan => Color.FromUInt32(0xff008b8b);
+        public static Color DarkCyan => KnownColor.DarkCyan.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffb8860b.
         /// </summary>
-        public static Color DarkGoldenrod => Color.FromUInt32(0xffb8860b);
+        public static Color DarkGoldenrod => KnownColor.DarkGoldenrod.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffa9a9a9.
         /// </summary>
-        public static Color DarkGray => Color.FromUInt32(0xffa9a9a9);
+        public static Color DarkGray => KnownColor.DarkGray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff006400.
         /// </summary>
-        public static Color DarkGreen => Color.FromUInt32(0xff006400);
+        public static Color DarkGreen => KnownColor.DarkGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffbdb76b.
         /// </summary>
-        public static Color DarkKhaki => Color.FromUInt32(0xffbdb76b);
+        public static Color DarkKhaki => KnownColor.DarkKhaki.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff8b008b.
         /// </summary>
-        public static Color DarkMagenta => Color.FromUInt32(0xff8b008b);
+        public static Color DarkMagenta => KnownColor.DarkMagenta.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff556b2f.
         /// </summary>
-        public static Color DarkOliveGreen => Color.FromUInt32(0xff556b2f);
+        public static Color DarkOliveGreen => KnownColor.DarkOliveGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff8c00.
         /// </summary>
-        public static Color DarkOrange => Color.FromUInt32(0xffff8c00);
+        public static Color DarkOrange => KnownColor.DarkOrange.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff9932cc.
         /// </summary>
-        public static Color DarkOrchid => Color.FromUInt32(0xff9932cc);
+        public static Color DarkOrchid => KnownColor.DarkOrchid.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff8b0000.
         /// </summary>
-        public static Color DarkRed => Color.FromUInt32(0xff8b0000);
+        public static Color DarkRed => KnownColor.DarkRed.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffe9967a.
         /// </summary>
-        public static Color DarkSalmon => Color.FromUInt32(0xffe9967a);
+        public static Color DarkSalmon => KnownColor.DarkSalmon.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff8fbc8f.
         /// </summary>
-        public static Color DarkSeaGreen => Color.FromUInt32(0xff8fbc8f);
+        public static Color DarkSeaGreen => KnownColor.DarkSeaGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff483d8b.
         /// </summary>
-        public static Color DarkSlateBlue => Color.FromUInt32(0xff483d8b);
+        public static Color DarkSlateBlue => KnownColor.DarkSlateBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff2f4f4f.
         /// </summary>
-        public static Color DarkSlateGray => Color.FromUInt32(0xff2f4f4f);
+        public static Color DarkSlateGray => KnownColor.DarkSlateGray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00ced1.
         /// </summary>
-        public static Color DarkTurquoise => Color.FromUInt32(0xff00ced1);
+        public static Color DarkTurquoise => KnownColor.DarkTurquoise.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff9400d3.
         /// </summary>
-        public static Color DarkViolet => Color.FromUInt32(0xff9400d3);
+        public static Color DarkViolet => KnownColor.DarkViolet.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff1493.
         /// </summary>
-        public static Color DeepPink => Color.FromUInt32(0xffff1493);
+        public static Color DeepPink => KnownColor.DeepPink.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00bfff.
         /// </summary>
-        public static Color DeepSkyBlue => Color.FromUInt32(0xff00bfff);
+        public static Color DeepSkyBlue => KnownColor.DeepSkyBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff696969.
         /// </summary>
-        public static Color DimGray => Color.FromUInt32(0xff696969);
+        public static Color DimGray => KnownColor.DimGray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff1e90ff.
         /// </summary>
-        public static Color DodgerBlue => Color.FromUInt32(0xff1e90ff);
+        public static Color DodgerBlue => KnownColor.DodgerBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffb22222.
         /// </summary>
-        public static Color Firebrick => Color.FromUInt32(0xffb22222);
+        public static Color Firebrick => KnownColor.Firebrick.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffffaf0.
         /// </summary>
-        public static Color FloralWhite => Color.FromUInt32(0xfffffaf0);
+        public static Color FloralWhite => KnownColor.FloralWhite.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff228b22.
         /// </summary>
-        public static Color ForestGreen => Color.FromUInt32(0xff228b22);
+        public static Color ForestGreen => KnownColor.ForestGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff00ff.
         /// </summary>
-        public static Color Fuchsia => Color.FromUInt32(0xffff00ff);
+        public static Color Fuchsia => KnownColor.Fuchsia.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffdcdcdc.
         /// </summary>
-        public static Color Gainsboro => Color.FromUInt32(0xffdcdcdc);
+        public static Color Gainsboro => KnownColor.Gainsboro.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff8f8ff.
         /// </summary>
-        public static Color GhostWhite => Color.FromUInt32(0xfff8f8ff);
+        public static Color GhostWhite => KnownColor.GhostWhite.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffd700.
         /// </summary>
-        public static Color Gold => Color.FromUInt32(0xffffd700);
+        public static Color Gold => KnownColor.Gold.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffdaa520.
         /// </summary>
-        public static Color Goldenrod => Color.FromUInt32(0xffdaa520);
+        public static Color Goldenrod => KnownColor.Goldenrod.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff808080.
         /// </summary>
-        public static Color Gray => Color.FromUInt32(0xff808080);
+        public static Color Gray => KnownColor.Gray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff008000.
         /// </summary>
-        public static Color Green => Color.FromUInt32(0xff008000);
+        public static Color Green => KnownColor.Green.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffadff2f.
         /// </summary>
-        public static Color GreenYellow => Color.FromUInt32(0xffadff2f);
+        public static Color GreenYellow => KnownColor.GreenYellow.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff0fff0.
         /// </summary>
-        public static Color Honeydew => Color.FromUInt32(0xfff0fff0);
+        public static Color Honeydew => KnownColor.Honeydew.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff69b4.
         /// </summary>
-        public static Color HotPink => Color.FromUInt32(0xffff69b4);
+        public static Color HotPink => KnownColor.HotPink.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffcd5c5c.
         /// </summary>
-        public static Color IndianRed => Color.FromUInt32(0xffcd5c5c);
+        public static Color IndianRed => KnownColor.IndianRed.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff4b0082.
         /// </summary>
-        public static Color Indigo => Color.FromUInt32(0xff4b0082);
+        public static Color Indigo => KnownColor.Indigo.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffffff0.
         /// </summary>
-        public static Color Ivory => Color.FromUInt32(0xfffffff0);
+        public static Color Ivory => KnownColor.Ivory.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff0e68c.
         /// </summary>
-        public static Color Khaki => Color.FromUInt32(0xfff0e68c);
+        public static Color Khaki => KnownColor.Khaki.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffe6e6fa.
         /// </summary>
-        public static Color Lavender => Color.FromUInt32(0xffe6e6fa);
+        public static Color Lavender => KnownColor.Lavender.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffff0f5.
         /// </summary>
-        public static Color LavenderBlush => Color.FromUInt32(0xfffff0f5);
+        public static Color LavenderBlush => KnownColor.LavenderBlush.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff7cfc00.
         /// </summary>
-        public static Color LawnGreen => Color.FromUInt32(0xff7cfc00);
+        public static Color LawnGreen => KnownColor.LawnGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffffacd.
         /// </summary>
-        public static Color LemonChiffon => Color.FromUInt32(0xfffffacd);
+        public static Color LemonChiffon => KnownColor.LemonChiffon.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffadd8e6.
         /// </summary>
-        public static Color LightBlue => Color.FromUInt32(0xffadd8e6);
+        public static Color LightBlue => KnownColor.LightBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff08080.
         /// </summary>
-        public static Color LightCoral => Color.FromUInt32(0xfff08080);
+        public static Color LightCoral => KnownColor.LightCoral.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffe0ffff.
         /// </summary>
-        public static Color LightCyan => Color.FromUInt32(0xffe0ffff);
+        public static Color LightCyan => KnownColor.LightCyan.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffafad2.
         /// </summary>
-        public static Color LightGoldenrodYellow => Color.FromUInt32(0xfffafad2);
+        public static Color LightGoldenrodYellow => KnownColor.LightGoldenrodYellow.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffd3d3d3.
         /// </summary>
-        public static Color LightGray => Color.FromUInt32(0xffd3d3d3);
+        public static Color LightGray => KnownColor.LightGray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff90ee90.
         /// </summary>
-        public static Color LightGreen => Color.FromUInt32(0xff90ee90);
+        public static Color LightGreen => KnownColor.LightGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffb6c1.
         /// </summary>
-        public static Color LightPink => Color.FromUInt32(0xffffb6c1);
+        public static Color LightPink => KnownColor.LightPink.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffa07a.
         /// </summary>
-        public static Color LightSalmon => Color.FromUInt32(0xffffa07a);
+        public static Color LightSalmon => KnownColor.LightSalmon.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff20b2aa.
         /// </summary>
-        public static Color LightSeaGreen => Color.FromUInt32(0xff20b2aa);
+        public static Color LightSeaGreen => KnownColor.LightSeaGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff87cefa.
         /// </summary>
-        public static Color LightSkyBlue => Color.FromUInt32(0xff87cefa);
+        public static Color LightSkyBlue => KnownColor.LightSkyBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff778899.
         /// </summary>
-        public static Color LightSlateGray => Color.FromUInt32(0xff778899);
+        public static Color LightSlateGray => KnownColor.LightSlateGray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffb0c4de.
         /// </summary>
-        public static Color LightSteelBlue => Color.FromUInt32(0xffb0c4de);
+        public static Color LightSteelBlue => KnownColor.LightSteelBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffffe0.
         /// </summary>
-        public static Color LightYellow => Color.FromUInt32(0xffffffe0);
+        public static Color LightYellow => KnownColor.LightYellow.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00ff00.
         /// </summary>
-        public static Color Lime => Color.FromUInt32(0xff00ff00);
+        public static Color Lime => KnownColor.Lime.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff32cd32.
         /// </summary>
-        public static Color LimeGreen => Color.FromUInt32(0xff32cd32);
+        public static Color LimeGreen => KnownColor.LimeGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffaf0e6.
         /// </summary>
-        public static Color Linen => Color.FromUInt32(0xfffaf0e6);
+        public static Color Linen => KnownColor.Linen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff00ff.
         /// </summary>
-        public static Color Magenta => Color.FromUInt32(0xffff00ff);
+        public static Color Magenta => KnownColor.Magenta.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff800000.
         /// </summary>
-        public static Color Maroon => Color.FromUInt32(0xff800000);
+        public static Color Maroon => KnownColor.Maroon.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff66cdaa.
         /// </summary>
-        public static Color MediumAquamarine => Color.FromUInt32(0xff66cdaa);
+        public static Color MediumAquamarine => KnownColor.MediumAquamarine.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff0000cd.
         /// </summary>
-        public static Color MediumBlue => Color.FromUInt32(0xff0000cd);
+        public static Color MediumBlue => KnownColor.MediumBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffba55d3.
         /// </summary>
-        public static Color MediumOrchid => Color.FromUInt32(0xffba55d3);
+        public static Color MediumOrchid => KnownColor.MediumOrchid.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff9370db.
         /// </summary>
-        public static Color MediumPurple => Color.FromUInt32(0xff9370db);
+        public static Color MediumPurple => KnownColor.MediumPurple.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff3cb371.
         /// </summary>
-        public static Color MediumSeaGreen => Color.FromUInt32(0xff3cb371);
+        public static Color MediumSeaGreen => KnownColor.MediumSeaGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff7b68ee.
         /// </summary>
-        public static Color MediumSlateBlue => Color.FromUInt32(0xff7b68ee);
+        public static Color MediumSlateBlue => KnownColor.MediumSlateBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00fa9a.
         /// </summary>
-        public static Color MediumSpringGreen => Color.FromUInt32(0xff00fa9a);
+        public static Color MediumSpringGreen => KnownColor.MediumSpringGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff48d1cc.
         /// </summary>
-        public static Color MediumTurquoise => Color.FromUInt32(0xff48d1cc);
+        public static Color MediumTurquoise => KnownColor.MediumTurquoise.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffc71585.
         /// </summary>
-        public static Color MediumVioletRed => Color.FromUInt32(0xffc71585);
+        public static Color MediumVioletRed => KnownColor.MediumVioletRed.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff191970.
         /// </summary>
-        public static Color MidnightBlue => Color.FromUInt32(0xff191970);
+        public static Color MidnightBlue => KnownColor.MidnightBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff5fffa.
         /// </summary>
-        public static Color MintCream => Color.FromUInt32(0xfff5fffa);
+        public static Color MintCream => KnownColor.MintCream.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffe4e1.
         /// </summary>
-        public static Color MistyRose => Color.FromUInt32(0xffffe4e1);
+        public static Color MistyRose => KnownColor.MistyRose.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffe4b5.
         /// </summary>
-        public static Color Moccasin => Color.FromUInt32(0xffffe4b5);
+        public static Color Moccasin => KnownColor.Moccasin.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffdead.
         /// </summary>
-        public static Color NavajoWhite => Color.FromUInt32(0xffffdead);
+        public static Color NavajoWhite => KnownColor.NavajoWhite.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff000080.
         /// </summary>
-        public static Color Navy => Color.FromUInt32(0xff000080);
+        public static Color Navy => KnownColor.Navy.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffdf5e6.
         /// </summary>
-        public static Color OldLace => Color.FromUInt32(0xfffdf5e6);
+        public static Color OldLace => KnownColor.OldLace.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff808000.
         /// </summary>
-        public static Color Olive => Color.FromUInt32(0xff808000);
+        public static Color Olive => KnownColor.Olive.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff6b8e23.
         /// </summary>
-        public static Color OliveDrab => Color.FromUInt32(0xff6b8e23);
+        public static Color OliveDrab => KnownColor.OliveDrab.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffa500.
         /// </summary>
-        public static Color Orange => Color.FromUInt32(0xffffa500);
+        public static Color Orange => KnownColor.Orange.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff4500.
         /// </summary>
-        public static Color OrangeRed => Color.FromUInt32(0xffff4500);
+        public static Color OrangeRed => KnownColor.OrangeRed.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffda70d6.
         /// </summary>
-        public static Color Orchid => Color.FromUInt32(0xffda70d6);
+        public static Color Orchid => KnownColor.Orchid.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffeee8aa.
         /// </summary>
-        public static Color PaleGoldenrod => Color.FromUInt32(0xffeee8aa);
+        public static Color PaleGoldenrod => KnownColor.PaleGoldenrod.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff98fb98.
         /// </summary>
-        public static Color PaleGreen => Color.FromUInt32(0xff98fb98);
+        public static Color PaleGreen => KnownColor.PaleGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffafeeee.
         /// </summary>
-        public static Color PaleTurquoise => Color.FromUInt32(0xffafeeee);
+        public static Color PaleTurquoise => KnownColor.PaleTurquoise.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffdb7093.
         /// </summary>
-        public static Color PaleVioletRed => Color.FromUInt32(0xffdb7093);
+        public static Color PaleVioletRed => KnownColor.PaleVioletRed.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffefd5.
         /// </summary>
-        public static Color PapayaWhip => Color.FromUInt32(0xffffefd5);
+        public static Color PapayaWhip => KnownColor.PapayaWhip.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffdab9.
         /// </summary>
-        public static Color PeachPuff => Color.FromUInt32(0xffffdab9);
+        public static Color PeachPuff => KnownColor.PeachPuff.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffcd853f.
         /// </summary>
-        public static Color Peru => Color.FromUInt32(0xffcd853f);
+        public static Color Peru => KnownColor.Peru.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffc0cb.
         /// </summary>
-        public static Color Pink => Color.FromUInt32(0xffffc0cb);
+        public static Color Pink => KnownColor.Pink.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffdda0dd.
         /// </summary>
-        public static Color Plum => Color.FromUInt32(0xffdda0dd);
+        public static Color Plum => KnownColor.Plum.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffb0e0e6.
         /// </summary>
-        public static Color PowderBlue => Color.FromUInt32(0xffb0e0e6);
+        public static Color PowderBlue => KnownColor.PowderBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff800080.
         /// </summary>
-        public static Color Purple => Color.FromUInt32(0xff800080);
+        public static Color Purple => KnownColor.Purple.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff0000.
         /// </summary>
-        public static Color Red => Color.FromUInt32(0xffff0000);
+        public static Color Red => KnownColor.Red.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffbc8f8f.
         /// </summary>
-        public static Color RosyBrown => Color.FromUInt32(0xffbc8f8f);
+        public static Color RosyBrown => KnownColor.RosyBrown.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff4169e1.
         /// </summary>
-        public static Color RoyalBlue => Color.FromUInt32(0xff4169e1);
+        public static Color RoyalBlue => KnownColor.RoyalBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff8b4513.
         /// </summary>
-        public static Color SaddleBrown => Color.FromUInt32(0xff8b4513);
+        public static Color SaddleBrown => KnownColor.SaddleBrown.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffa8072.
         /// </summary>
-        public static Color Salmon => Color.FromUInt32(0xfffa8072);
+        public static Color Salmon => KnownColor.Salmon.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff4a460.
         /// </summary>
-        public static Color SandyBrown => Color.FromUInt32(0xfff4a460);
+        public static Color SandyBrown => KnownColor.SandyBrown.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff2e8b57.
         /// </summary>
-        public static Color SeaGreen => Color.FromUInt32(0xff2e8b57);
+        public static Color SeaGreen => KnownColor.SeaGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffff5ee.
         /// </summary>
-        public static Color SeaShell => Color.FromUInt32(0xfffff5ee);
+        public static Color SeaShell => KnownColor.SeaShell.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffa0522d.
         /// </summary>
-        public static Color Sienna => Color.FromUInt32(0xffa0522d);
+        public static Color Sienna => KnownColor.Sienna.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffc0c0c0.
         /// </summary>
-        public static Color Silver => Color.FromUInt32(0xffc0c0c0);
+        public static Color Silver => KnownColor.Silver.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff87ceeb.
         /// </summary>
-        public static Color SkyBlue => Color.FromUInt32(0xff87ceeb);
+        public static Color SkyBlue => KnownColor.SkyBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff6a5acd.
         /// </summary>
-        public static Color SlateBlue => Color.FromUInt32(0xff6a5acd);
+        public static Color SlateBlue => KnownColor.SlateBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff708090.
         /// </summary>
-        public static Color SlateGray => Color.FromUInt32(0xff708090);
+        public static Color SlateGray => KnownColor.SlateGray.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fffffafa.
         /// </summary>
-        public static Color Snow => Color.FromUInt32(0xfffffafa);
+        public static Color Snow => KnownColor.Snow.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff00ff7f.
         /// </summary>
-        public static Color SpringGreen => Color.FromUInt32(0xff00ff7f);
+        public static Color SpringGreen => KnownColor.SpringGreen.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff4682b4.
         /// </summary>
-        public static Color SteelBlue => Color.FromUInt32(0xff4682b4);
+        public static Color SteelBlue => KnownColor.SteelBlue.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffd2b48c.
         /// </summary>
-        public static Color Tan => Color.FromUInt32(0xffd2b48c);
+        public static Color Tan => KnownColor.Tan.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff008080.
         /// </summary>
-        public static Color Teal => Color.FromUInt32(0xff008080);
+        public static Color Teal => KnownColor.Teal.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffd8bfd8.
         /// </summary>
-        public static Color Thistle => Color.FromUInt32(0xffd8bfd8);
+        public static Color Thistle => KnownColor.Thistle.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffff6347.
         /// </summary>
-        public static Color Tomato => Color.FromUInt32(0xffff6347);
+        public static Color Tomato => KnownColor.Tomato.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #00ffffff.
         /// </summary>
-        public static Color Transparent => Color.FromUInt32(0x00ffffff);
+        public static Color Transparent => KnownColor.Transparent.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff40e0d0.
         /// </summary>
-        public static Color Turquoise => Color.FromUInt32(0xff40e0d0);
+        public static Color Turquoise => KnownColor.Turquoise.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffee82ee.
         /// </summary>
-        public static Color Violet => Color.FromUInt32(0xffee82ee);
+        public static Color Violet => KnownColor.Violet.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff5deb3.
         /// </summary>
-        public static Color Wheat => Color.FromUInt32(0xfff5deb3);
+        public static Color Wheat => KnownColor.Wheat.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffffff.
         /// </summary>
-        public static Color White => Color.FromUInt32(0xffffffff);
+        public static Color White => KnownColor.White.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #fff5f5f5.
         /// </summary>
-        public static Color WhiteSmoke => Color.FromUInt32(0xfff5f5f5);
+        public static Color WhiteSmoke => KnownColor.WhiteSmoke.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ffffff00.
         /// </summary>
-        public static Color Yellow => Color.FromUInt32(0xffffff00);
+        public static Color Yellow => KnownColor.Yellow.ToColor();
 
         /// <summary>
         /// Gets a color with an ARGB value of #ff9acd32.
         /// </summary>
-        public static Color YellowGreen => Color.FromUInt32(0xff9acd32);
+        public static Color YellowGreen => KnownColor.YellowGreen.ToColor();
     }
 }

+ 224 - 0
src/Avalonia.Visuals/Media/KnownColors.cs

@@ -0,0 +1,224 @@
+using System;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace Avalonia.Media
+{
+    internal static class KnownColors
+    {
+        private static readonly IReadOnlyDictionary<string, KnownColor> _knownColorNames;
+        private static readonly IReadOnlyDictionary<uint, string> _knownColors;
+        private static readonly Dictionary<KnownColor, ISolidColorBrush> _knownBrushes;
+
+        static KnownColors()
+        {
+            var knownColorNames = new Dictionary<string, KnownColor>(StringComparer.OrdinalIgnoreCase);
+            var knownColors = new Dictionary<uint, string>();
+
+            foreach (var field in typeof(KnownColor).GetRuntimeFields())
+            {
+                if (field.FieldType != typeof(KnownColor)) continue;
+                var knownColor = (KnownColor)field.GetValue(null);
+                if (knownColor == KnownColor.None) continue;
+
+                knownColorNames.Add(field.Name, knownColor);
+
+                // some known colors have the same value, so use the first
+                if (!knownColors.ContainsKey((uint)knownColor))
+                {
+                    knownColors.Add((uint)knownColor, field.Name);
+                }
+            }
+
+            _knownColorNames = knownColorNames;
+            _knownColors = knownColors;
+            _knownBrushes = new Dictionary<KnownColor, ISolidColorBrush>();
+        }
+
+        public static ISolidColorBrush GetKnownBrush(string s)
+        {
+            var color = GetKnownColor(s);
+            return color != KnownColor.None ? color.ToBrush() : null;
+        }
+
+        public static KnownColor GetKnownColor(string s)
+        {
+            if (_knownColorNames.TryGetValue(s, out var color))
+            {
+                return color;
+            }
+
+            return KnownColor.None;
+        }
+
+        public static string GetKnownColorName(uint rgb)
+        {
+            return _knownColors.TryGetValue(rgb, out var name) ? name : null;
+        }
+
+        public static Color ToColor(this KnownColor color)
+        {
+            return Color.FromUInt32((uint)color);
+        }
+
+        public static ISolidColorBrush ToBrush(this KnownColor color)
+        {
+            lock (_knownBrushes)
+            {
+                if (!_knownBrushes.TryGetValue(color, out var brush))
+                {
+                    brush = new Immutable.ImmutableSolidColorBrush(color.ToColor());
+                    _knownBrushes.Add(color, brush);
+                }
+
+                return brush;
+            }
+        }
+    }
+
+    internal enum KnownColor : uint
+    {
+        None,
+        AliceBlue = 0xfff0f8ff,
+        AntiqueWhite = 0xfffaebd7,
+        Aqua = 0xff00ffff,
+        Aquamarine = 0xff7fffd4,
+        Azure = 0xfff0ffff,
+        Beige = 0xfff5f5dc,
+        Bisque = 0xffffe4c4,
+        Black = 0xff000000,
+        BlanchedAlmond = 0xffffebcd,
+        Blue = 0xff0000ff,
+        BlueViolet = 0xff8a2be2,
+        Brown = 0xffa52a2a,
+        BurlyWood = 0xffdeb887,
+        CadetBlue = 0xff5f9ea0,
+        Chartreuse = 0xff7fff00,
+        Chocolate = 0xffd2691e,
+        Coral = 0xffff7f50,
+        CornflowerBlue = 0xff6495ed,
+        Cornsilk = 0xfffff8dc,
+        Crimson = 0xffdc143c,
+        Cyan = 0xff00ffff,
+        DarkBlue = 0xff00008b,
+        DarkCyan = 0xff008b8b,
+        DarkGoldenrod = 0xffb8860b,
+        DarkGray = 0xffa9a9a9,
+        DarkGreen = 0xff006400,
+        DarkKhaki = 0xffbdb76b,
+        DarkMagenta = 0xff8b008b,
+        DarkOliveGreen = 0xff556b2f,
+        DarkOrange = 0xffff8c00,
+        DarkOrchid = 0xff9932cc,
+        DarkRed = 0xff8b0000,
+        DarkSalmon = 0xffe9967a,
+        DarkSeaGreen = 0xff8fbc8f,
+        DarkSlateBlue = 0xff483d8b,
+        DarkSlateGray = 0xff2f4f4f,
+        DarkTurquoise = 0xff00ced1,
+        DarkViolet = 0xff9400d3,
+        DeepPink = 0xffff1493,
+        DeepSkyBlue = 0xff00bfff,
+        DimGray = 0xff696969,
+        DodgerBlue = 0xff1e90ff,
+        Firebrick = 0xffb22222,
+        FloralWhite = 0xfffffaf0,
+        ForestGreen = 0xff228b22,
+        Fuchsia = 0xffff00ff,
+        Gainsboro = 0xffdcdcdc,
+        GhostWhite = 0xfff8f8ff,
+        Gold = 0xffffd700,
+        Goldenrod = 0xffdaa520,
+        Gray = 0xff808080,
+        Green = 0xff008000,
+        GreenYellow = 0xffadff2f,
+        Honeydew = 0xfff0fff0,
+        HotPink = 0xffff69b4,
+        IndianRed = 0xffcd5c5c,
+        Indigo = 0xff4b0082,
+        Ivory = 0xfffffff0,
+        Khaki = 0xfff0e68c,
+        Lavender = 0xffe6e6fa,
+        LavenderBlush = 0xfffff0f5,
+        LawnGreen = 0xff7cfc00,
+        LemonChiffon = 0xfffffacd,
+        LightBlue = 0xffadd8e6,
+        LightCoral = 0xfff08080,
+        LightCyan = 0xffe0ffff,
+        LightGoldenrodYellow = 0xfffafad2,
+        LightGreen = 0xff90ee90,
+        LightGray = 0xffd3d3d3,
+        LightPink = 0xffffb6c1,
+        LightSalmon = 0xffffa07a,
+        LightSeaGreen = 0xff20b2aa,
+        LightSkyBlue = 0xff87cefa,
+        LightSlateGray = 0xff778899,
+        LightSteelBlue = 0xffb0c4de,
+        LightYellow = 0xffffffe0,
+        Lime = 0xff00ff00,
+        LimeGreen = 0xff32cd32,
+        Linen = 0xfffaf0e6,
+        Magenta = 0xffff00ff,
+        Maroon = 0xff800000,
+        MediumAquamarine = 0xff66cdaa,
+        MediumBlue = 0xff0000cd,
+        MediumOrchid = 0xffba55d3,
+        MediumPurple = 0xff9370db,
+        MediumSeaGreen = 0xff3cb371,
+        MediumSlateBlue = 0xff7b68ee,
+        MediumSpringGreen = 0xff00fa9a,
+        MediumTurquoise = 0xff48d1cc,
+        MediumVioletRed = 0xffc71585,
+        MidnightBlue = 0xff191970,
+        MintCream = 0xfff5fffa,
+        MistyRose = 0xffffe4e1,
+        Moccasin = 0xffffe4b5,
+        NavajoWhite = 0xffffdead,
+        Navy = 0xff000080,
+        OldLace = 0xfffdf5e6,
+        Olive = 0xff808000,
+        OliveDrab = 0xff6b8e23,
+        Orange = 0xffffa500,
+        OrangeRed = 0xffff4500,
+        Orchid = 0xffda70d6,
+        PaleGoldenrod = 0xffeee8aa,
+        PaleGreen = 0xff98fb98,
+        PaleTurquoise = 0xffafeeee,
+        PaleVioletRed = 0xffdb7093,
+        PapayaWhip = 0xffffefd5,
+        PeachPuff = 0xffffdab9,
+        Peru = 0xffcd853f,
+        Pink = 0xffffc0cb,
+        Plum = 0xffdda0dd,
+        PowderBlue = 0xffb0e0e6,
+        Purple = 0xff800080,
+        Red = 0xffff0000,
+        RosyBrown = 0xffbc8f8f,
+        RoyalBlue = 0xff4169e1,
+        SaddleBrown = 0xff8b4513,
+        Salmon = 0xfffa8072,
+        SandyBrown = 0xfff4a460,
+        SeaGreen = 0xff2e8b57,
+        SeaShell = 0xfffff5ee,
+        Sienna = 0xffa0522d,
+        Silver = 0xffc0c0c0,
+        SkyBlue = 0xff87ceeb,
+        SlateBlue = 0xff6a5acd,
+        SlateGray = 0xff708090,
+        Snow = 0xfffffafa,
+        SpringGreen = 0xff00ff7f,
+        SteelBlue = 0xff4682b4,
+        Tan = 0xffd2b48c,
+        Teal = 0xff008080,
+        Thistle = 0xffd8bfd8,
+        Tomato = 0xffff6347,
+        Transparent = 0x00ffffff,
+        Turquoise = 0xff40e0d0,
+        Violet = 0xffee82ee,
+        Wheat = 0xfff5deb3,
+        White = 0xffffffff,
+        WhiteSmoke = 0xfff5f5f5,
+        Yellow = 0xffffff00,
+        YellowGreen = 0xff9acd32
+    }
+}

+ 6 - 10
src/Avalonia.Visuals/Point.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -173,17 +174,12 @@ namespace Avalonia
         /// <returns>The <see cref="Thickness"/>.</returns>
         public static Point Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToList();
-
-            if (parts.Count == 2)
-            {
-                return new Point(double.Parse(parts[0], culture), double.Parse(parts[1], culture));
-            }
-            else
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Point"))
             {
-                throw new FormatException("Invalid Point.");
+                return new Point(
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble()
+                );
             }
         }
 

+ 7 - 13
src/Avalonia.Visuals/Rect.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -490,21 +491,14 @@ namespace Avalonia
         /// <returns>The parsed <see cref="Rect"/>.</returns>
         public static Rect Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToList();
-
-            if (parts.Count == 4)
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Rect"))
             {
                 return new Rect(
-                    double.Parse(parts[0], culture),
-                    double.Parse(parts[1], culture),
-                    double.Parse(parts[2], culture),
-                    double.Parse(parts[3], culture));
-            }
-            else
-            {
-                throw new FormatException("Invalid Rect.");
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble()
+                );
             }
         }
     }

+ 11 - 15
src/Avalonia.Visuals/RelativePoint.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -157,37 +158,32 @@ namespace Avalonia
         /// <returns>The parsed <see cref="RelativePoint"/>.</returns>
         public static RelativePoint Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToList();
-
-            if (parts.Count == 2)
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid RelativePoint"))
             {
+                var x = tokenizer.ReadString();
+                var y = tokenizer.ReadString();
+
                 var unit = RelativeUnit.Absolute;
                 var scale = 1.0;
 
-                if (parts[0].EndsWith("%"))
+                if (x.EndsWith("%"))
                 {
-                    if (!parts[1].EndsWith("%"))
+                    if (!y.EndsWith("%"))
                     {
                         throw new FormatException("If one coordinate is relative, both must be.");
                     }
 
-                    parts[0] = parts[0].TrimEnd('%');
-                    parts[1] = parts[1].TrimEnd('%');
+                    x = x.TrimEnd('%');
+                    y = y.TrimEnd('%');
                     unit = RelativeUnit.Relative;
                     scale = 0.01;
                 }
 
                 return new RelativePoint(
-                    double.Parse(parts[0], culture) * scale,
-                    double.Parse(parts[1], culture) * scale,
+                    double.Parse(x, culture) * scale,
+                    double.Parse(y, culture) * scale,
                     unit);
             }
-            else
-            {
-                throw new FormatException("Invalid Point.");
-            }
         }
     }
 }

+ 29 - 26
src/Avalonia.Visuals/RelativeRect.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -12,6 +13,8 @@ namespace Avalonia
     /// </summary>
     public struct RelativeRect : IEquatable<RelativeRect>
     {
+        private static readonly char[] PercentChar = { '%' };
+
         /// <summary>
         /// A rectangle that represents 100% of an area.
         /// </summary>
@@ -159,7 +162,7 @@ namespace Avalonia
                     Rect.Width * size.Width,
                     Rect.Height * size.Height);
         }
-
+        
         /// <summary>
         /// Parses a <see cref="RelativeRect"/> string.
         /// </summary>
@@ -168,43 +171,43 @@ namespace Avalonia
         /// <returns>The parsed <see cref="RelativeRect"/>.</returns>
         public static RelativeRect Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToList();
-
-            if (parts.Count == 4)
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid RelativeRect"))
             {
+                var x = tokenizer.ReadString();
+                var y = tokenizer.ReadString();
+                var width = tokenizer.ReadString();
+                var height = tokenizer.ReadString();
+
                 var unit = RelativeUnit.Absolute;
                 var scale = 1.0;
 
-                if (parts[0].EndsWith("%"))
+                var xRelative = x.EndsWith("%", StringComparison.Ordinal);
+                var yRelative = y.EndsWith("%", StringComparison.Ordinal);
+                var widthRelative = width.EndsWith("%", StringComparison.Ordinal);
+                var heightRelative = height.EndsWith("%", StringComparison.Ordinal);
+
+                if (xRelative && yRelative && widthRelative && heightRelative)
                 {
-                    if (!parts[1].EndsWith("%") 
-                        || !parts[2].EndsWith("%")
-                        || !parts[3].EndsWith("%"))
-                    {
-                        throw new FormatException("If one coordinate is relative, all other must be too.");
-                    }
-
-                    parts[0] = parts[0].TrimEnd('%');
-                    parts[1] = parts[1].TrimEnd('%');
-                    parts[2] = parts[2].TrimEnd('%');
-                    parts[3] = parts[3].TrimEnd('%');
+                    x = x.TrimEnd(PercentChar);
+                    y = y.TrimEnd(PercentChar);
+                    width = width.TrimEnd(PercentChar);
+                    height = height.TrimEnd(PercentChar);
+
                     unit = RelativeUnit.Relative;
                     scale = 0.01;
                 }
+                else if (xRelative || yRelative || widthRelative || heightRelative)
+                {
+                    throw new FormatException("If one coordinate is relative, all must be.");
+                }
 
                 return new RelativeRect(
-                    double.Parse(parts[0], culture) * scale,
-                    double.Parse(parts[1], culture) * scale,
-                    double.Parse(parts[2], culture) * scale,
-                    double.Parse(parts[3], culture) * scale,
+                    double.Parse(x, culture) * scale,
+                    double.Parse(y, culture) * scale,
+                    double.Parse(width, culture) * scale,
+                    double.Parse(height, culture) * scale,
                     unit);
             }
-            else
-            {
-                throw new FormatException("Invalid RelativeRect.");
-            }
         }
     }
 }

+ 5 - 10
src/Avalonia.Visuals/Size.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -153,17 +154,11 @@ namespace Avalonia
         /// <returns>The <see cref="Size"/>.</returns>
         public static Size Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToList();
-
-            if (parts.Count == 2)
-            {
-                return new Size(double.Parse(parts[0], culture), double.Parse(parts[1], culture));
-            }
-            else
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Size"))
             {
-                throw new FormatException("Invalid Size.");
+                return new Size(
+                    tokenizer.ReadDouble(),
+                    tokenizer.ReadDouble());
             }
         }
 

+ 15 - 20
src/Avalonia.Visuals/Thickness.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Avalonia.Utilities;
 using System;
 using System.Globalization;
 using System.Linq;
@@ -168,28 +169,22 @@ namespace Avalonia
         /// <returns>The <see cref="Thickness"/>.</returns>
         public static Thickness Parse(string s, CultureInfo culture)
         {
-            var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(x => x.Trim())
-                .ToList();
-
-            switch (parts.Count)
+            using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Thickness"))
             {
-                case 1:
-                    var uniform = double.Parse(parts[0], culture);
-                    return new Thickness(uniform);
-                case 2:
-                    var horizontal = double.Parse(parts[0], culture);
-                    var vertical = double.Parse(parts[1], culture);
-                    return new Thickness(horizontal, vertical);
-                case 4:
-                    var left = double.Parse(parts[0], culture);
-                    var top = double.Parse(parts[1], culture);
-                    var right = double.Parse(parts[2], culture);
-                    var bottom = double.Parse(parts[3], culture);
-                    return new Thickness(left, top, right, bottom);
+                var a = tokenizer.ReadDouble();
+
+                if (tokenizer.TryReadDouble(out var b))
+                {
+                    if (tokenizer.TryReadDouble(out var c))
+                    {
+                        return new Thickness(a, b, c, tokenizer.ReadDouble());
+                    }
+
+                    return new Thickness(a, b);
+                }
+                
+                return new Thickness(a);
             }
-
-            throw new FormatException("Invalid Thickness.");
         }
 
         /// <summary>

+ 4 - 1
src/Gtk/Avalonia.Gtk3/CursorFactory.cs

@@ -32,7 +32,10 @@ namespace Avalonia.Gtk3
             {StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner},
             {StandardCursorType.TopRightCorner, CursorType.TopRightCorner},
             {StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner},
-            {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner}
+            {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner},
+            {StandardCursorType.DragCopy, CursorType.CenterPtr},
+            {StandardCursorType.DragMove, CursorType.Fleur},
+            {StandardCursorType.DragLink, CursorType.Cross},
         };
 
         private static readonly Dictionary<StandardCursorType, IPlatformHandle> Cache =

+ 2 - 2
src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFrameworks>netstandard2.0</TargetFrameworks>
     <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
@@ -19,4 +19,4 @@
     <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
   </ItemGroup>
   <Import Project="..\..\..\build\MonoMac.props" />
-</Project>
+</Project>

+ 4 - 0
src/OSX/Avalonia.MonoMac/Cursor.cs

@@ -51,6 +51,10 @@ namespace Avalonia.MonoMac
                 [StandardCursorType.TopSide] = NSCursor.ResizeUpCursor,
                 [StandardCursorType.UpArrow] = NSCursor.ResizeUpCursor,
                 [StandardCursorType.Wait] = NSCursor.ArrowCursor, //TODO
+                [StandardCursorType.DragMove] = NSCursor.DragCopyCursor, // TODO
+                [StandardCursorType.DragCopy] = NSCursor.DragCopyCursor,
+                [StandardCursorType.DragLink] = NSCursor.DragLinkCursor,
+
             };
         }
 

+ 124 - 0
src/OSX/Avalonia.MonoMac/DragSource.cs

@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
+using MonoMac;
+using MonoMac.AppKit;
+using MonoMac.CoreGraphics;
+using MonoMac.Foundation;
+using MonoMac.OpenGL;
+
+namespace Avalonia.MonoMac
+{
+    public class DragSource : NSDraggingSource, IPlatformDragSource
+    {
+        private const string NSPasteboardTypeString = "public.utf8-plain-text";
+        private const string NSPasteboardTypeFileUrl = "public.file-url";
+        
+        private readonly Subject<DragDropEffects> _result = new Subject<DragDropEffects>();
+        private readonly IInputManager _inputManager;
+        private DragDropEffects _allowedEffects;
+        
+        public override bool IgnoreModifierKeysWhileDragging => false;
+      
+        public DragSource()
+        {
+            _inputManager = AvaloniaLocator.Current.GetService<IInputManager>();
+        }
+
+        private string DataFormatToUTI(string s)
+        {
+            if (s == DataFormats.FileNames)
+                return NSPasteboardTypeFileUrl;
+            if (s == DataFormats.Text)
+                return NSPasteboardTypeString;
+            return s;
+        }
+        
+        private NSDraggingItem CreateDraggingItem(string format, object data)
+        {
+            var pasteboardItem = new NSPasteboardItem();
+            NSData nsData;
+            if (data is string s)
+            {
+                if (format == DataFormats.FileNames)
+                    s = new Uri(s).AbsoluteUri; // Ensure file uris...
+                nsData = NSData.FromString(s);
+            }
+            else if (data is Stream strm)
+                nsData = NSData.FromStream(strm);
+            else if (data is byte[] bytes)
+                nsData = NSData.FromArray(bytes);
+            else
+            {
+                BinaryFormatter bf = new BinaryFormatter();
+                using (var ms = new MemoryStream())
+                {
+                    bf.Serialize(ms, data);
+                    ms.Position = 0;
+                    nsData = NSData.FromStream(ms);
+                }
+            }
+            pasteboardItem.SetDataForType(nsData, DataFormatToUTI(format));
+
+            NSPasteboardWriting writing = new NSPasteboardWriting(pasteboardItem.Handle);
+  
+            return new NSDraggingItem(writing);
+        }
+
+        public IEnumerable<NSDraggingItem> CreateDraggingItems(string format, object data)
+        {
+            if (format == DataFormats.FileNames && data is IEnumerable<string> files)
+            {
+                foreach (var file in files)
+                    yield return CreateDraggingItem(format, file);
+
+                yield break;
+            }
+
+            yield return CreateDraggingItem(format, data);
+        }
+        
+        
+        public async Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+        {
+            // We need the TopLevelImpl + a mouse location so we just wait for the next event.
+            var mouseEv = await _inputManager.PreProcess.OfType<RawMouseEventArgs>().FirstAsync();
+            var view = ((mouseEv.Root as TopLevel)?.PlatformImpl as TopLevelImpl)?.View;
+            if (view == null)
+                return DragDropEffects.None;
+
+            // Prepare the source event:
+            var pt = view.TranslateLocalPoint(mouseEv.Position).ToMonoMacPoint();    
+            var ev = NSEvent.MouseEvent(NSEventType.LeftMouseDown, pt, 0, 0, 0, null, 0, 0, 0);
+
+            _allowedEffects = allowedEffects;
+            var items = data.GetDataFormats().SelectMany(fmt => CreateDraggingItems(fmt, data.Get(fmt))).ToArray();
+            view.BeginDraggingSession(items ,ev, this);
+
+            return await _result;
+        }
+        
+        public override NSDragOperation DraggingSourceOperationMaskForLocal(bool flag)
+        {
+            return DraggingInfo.ConvertDragOperation(_allowedEffects);
+        }
+            
+        public override void DraggedImageEndedAtOperation(NSImage image, CGPoint screenPoint, NSDragOperation operation)
+        {
+            _result.OnNext(DraggingInfo.ConvertDragOperation(operation));
+            _result.OnCompleted();
+        }
+    }
+}

+ 90 - 0
src/OSX/Avalonia.MonoMac/DraggingInfo.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Input;
+using MonoMac.AppKit;
+using MonoMac.Foundation;
+
+namespace Avalonia.MonoMac
+{
+    class DraggingInfo : IDataObject
+    { 
+        private readonly NSDraggingInfo _info;
+
+        public DraggingInfo(NSDraggingInfo info)
+        {
+            _info = info;
+        }
+        
+        internal static NSDragOperation ConvertDragOperation(DragDropEffects d)
+        {
+            NSDragOperation result = NSDragOperation.None;
+            if (d.HasFlag(DragDropEffects.Copy))
+                result |= NSDragOperation.Copy;
+            if (d.HasFlag(DragDropEffects.Link))
+                result |= NSDragOperation.Link;
+            if (d.HasFlag(DragDropEffects.Move))
+                result |= NSDragOperation.Move;
+            return result;
+        }
+        
+        internal static DragDropEffects ConvertDragOperation(NSDragOperation d)
+        {
+            DragDropEffects result = DragDropEffects.None;
+            if (d.HasFlag(NSDragOperation.Copy))
+                result |= DragDropEffects.Copy;
+            if (d.HasFlag(NSDragOperation.Link))
+                result |= DragDropEffects.Link;
+            if (d.HasFlag(NSDragOperation.Move))
+                result |= DragDropEffects.Move;
+            return result;
+        }
+
+        public Point Location => new Point(_info.DraggingLocation.X, _info.DraggingLocation.Y);
+        
+        public IEnumerable<string> GetDataFormats()
+        {
+            return _info.DraggingPasteboard.Types.Select(NSTypeToWellknownType);
+        }
+
+        private string NSTypeToWellknownType(string type)
+        {
+            if (type == NSPasteboard.NSStringType)
+                return DataFormats.Text;
+            if (type == NSPasteboard.NSFilenamesType)
+                return DataFormats.FileNames;
+            return type;
+        }
+
+        public string GetText()
+        {
+            return _info.DraggingPasteboard.GetStringForType(NSPasteboard.NSStringType);
+        }
+
+        public IEnumerable<string> GetFileNames()
+        {
+            using(var fileNames = (NSArray)_info.DraggingPasteboard.GetPropertyListForType(NSPasteboard.NSFilenamesType))
+            {
+                if (fileNames != null)
+                    return NSArray.StringArrayFromHandle(fileNames.Handle);
+            }
+
+            return Enumerable.Empty<string>();
+        }
+
+        public bool Contains(string dataFormat)
+        {
+            return GetDataFormats().Any(f => f == dataFormat);
+        }
+
+        public object Get(string dataFormat)
+        {
+            if (dataFormat == DataFormats.Text)
+                return GetText();
+            if (dataFormat == DataFormats.FileNames)
+                return GetFileNames();
+
+            return _info.DraggingPasteboard.GetDataForType(dataFormat).ToArray();
+        }
+    }
+}

+ 2 - 1
src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs

@@ -35,7 +35,8 @@ namespace Avalonia.MonoMac
                 .Bind<ISystemDialogImpl>().ToSingleton<SystemDialogsImpl>()
                 .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
                 .Bind<IRenderLoop>().ToConstant(s_renderLoop)
-                .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance);
+                .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
+                /*.Bind<IPlatformDragSource>().ToTransient<DragSource>()*/;
         }
 
         public static void Initialize()

+ 47 - 0
src/OSX/Avalonia.MonoMac/TopLevelImpl.cs

@@ -18,6 +18,7 @@ namespace Avalonia.MonoMac
     {
         public TopLevelView View { get; }
         private readonly IMouseDevice _mouse = AvaloniaLocator.Current.GetService<IMouseDevice>();
+        private readonly IDragDropDevice _dragDevice = AvaloniaLocator.Current.GetService<IDragDropDevice>();
         protected TopLevelImpl()
         {
             View = new TopLevelView(this);
@@ -53,6 +54,10 @@ namespace Avalonia.MonoMac
                 _tl = tl;
                 _mouse = AvaloniaLocator.Current.GetService<IMouseDevice>();
                 _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
+                
+                RegisterForDraggedTypes(new string[] {
+                    "public.data" // register for any kind of data.
+                });
             }
 
             protected override void Dispose(bool disposing)
@@ -149,6 +154,48 @@ namespace Avalonia.MonoMac
                 UpdateCursor();
             }
 
+            private NSDragOperation SendRawDragEvent(NSDraggingInfo sender, RawDragEventType type)
+            {
+                Action<RawInputEventArgs> input = _tl.Input;
+                IDragDropDevice dragDevice = _tl._dragDevice;
+                IInputRoot root = _tl?.InputRoot;
+                if (root == null || dragDevice == null || input == null)
+                    return NSDragOperation.None;
+                
+                var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask);
+                DraggingInfo info = new DraggingInfo(sender);
+                var pt = TranslateLocalPoint(info.Location);
+                var args = new RawDragEvent(dragDevice, type, root, pt, info, dragOp);
+                input(args);
+                return DraggingInfo.ConvertDragOperation(args.Effects);
+            }
+
+            public override NSDragOperation DraggingEntered(NSDraggingInfo sender)
+            {
+                return SendRawDragEvent(sender, RawDragEventType.DragEnter);
+            }
+
+            public override NSDragOperation DraggingUpdated(NSDraggingInfo sender)
+            {
+                return SendRawDragEvent(sender, RawDragEventType.DragOver);
+            }
+
+            public override void DraggingExited(NSDraggingInfo sender)
+            {
+                SendRawDragEvent(sender, RawDragEventType.DragLeave);
+            }
+
+            public override bool PrepareForDragOperation(NSDraggingInfo sender)
+            {
+                return SendRawDragEvent(sender, RawDragEventType.DragOver) != NSDragOperation.None;
+            }
+
+            public override bool PerformDragOperation(NSDraggingInfo sender)
+            {
+                return SendRawDragEvent(sender, RawDragEventType.Drop) != NSDragOperation.None;
+            }
+            
+
             public override void SetFrameSize(CGSize newSize)
             {
                 lock (SyncRoot)

+ 7 - 4
src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs

@@ -103,7 +103,7 @@ namespace Avalonia.Direct2D1
         /// Converts a pen to a Direct2D stroke style.
         /// </summary>
         /// <param name="pen">The pen to convert.</param>
-        /// <param name="target">The render target.</param>
+        /// <param name="renderTarget">The render target.</param>
         /// <returns>The Direct2D brush.</returns>
         public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.Pen pen, SharpDX.Direct2D1.RenderTarget renderTarget)
         {
@@ -114,7 +114,7 @@ namespace Avalonia.Direct2D1
         /// Converts a pen to a Direct2D stroke style.
         /// </summary>
         /// <param name="pen">The pen to convert.</param>
-        /// <param name="target">The render target.</param>
+        /// <param name="factory">The factory associated with this resource.</param>
         /// <returns>The Direct2D brush.</returns>
         public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.Pen pen, Factory factory)
         {
@@ -127,13 +127,16 @@ namespace Avalonia.Direct2D1
                 EndCap = pen.EndLineCap.ToDirect2D(),
                 DashCap = pen.DashCap.ToDirect2D()
             };
-            var dashes = new float[0];
+            float[] dashes = null;
             if (pen.DashStyle?.Dashes != null && pen.DashStyle.Dashes.Count > 0)
             {
                 properties.DashStyle = DashStyle.Custom;
                 properties.DashOffset = (float)pen.DashStyle.Offset;
-                dashes = pen.DashStyle?.Dashes.Select(x => (float)x).ToArray();
+                dashes = pen.DashStyle.Dashes.Select(x => (float)x).ToArray();
             }
+
+            dashes = dashes ?? Array.Empty<float>();
+
             return new StrokeStyle(factory, properties, dashes);
         }
 

+ 80 - 0
src/Windows/Avalonia.Win32/ClipboardFormats.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{   
+    static class ClipboardFormats
+    {
+        private const int MAX_FORMAT_NAME_LENGTH = 260;
+
+        class ClipboardFormat
+        {
+            public short Format { get; private set; }
+            public string Name { get; private set; }
+            public short[] Synthesized { get; private set; }
+
+            public ClipboardFormat(string name, short format, params short[] synthesized)
+            {
+                Format = format;
+                Name = name;
+                Synthesized = synthesized;
+            }
+        }
+
+        private static readonly List<ClipboardFormat> FormatList = new List<ClipboardFormat>()
+        {
+            new ClipboardFormat(DataFormats.Text, (short)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, (short)UnmanagedMethods.ClipboardFormat.CF_TEXT),
+            new ClipboardFormat(DataFormats.FileNames, (short)UnmanagedMethods.ClipboardFormat.CF_HDROP),
+        };
+
+
+        private static string QueryFormatName(short format)
+        {
+            StringBuilder sb = new StringBuilder(MAX_FORMAT_NAME_LENGTH);
+            if (UnmanagedMethods.GetClipboardFormatName(format, sb, sb.Capacity) > 0)
+                return sb.ToString();
+            return null;
+        }
+
+        public static string GetFormat(short format)
+        {
+            lock (FormatList)
+            {
+                var pd = FormatList.FirstOrDefault(f => f.Format == format || Array.IndexOf(f.Synthesized, format) >= 0);
+                if (pd == null)
+                {
+                    string name = QueryFormatName(format);
+                    if (string.IsNullOrEmpty(name))
+                        name = string.Format("Unknown_Format_{0}", format);
+                    pd = new ClipboardFormat(name, format);
+                    FormatList.Add(pd);
+                }
+                return pd.Name;
+            }
+        }
+
+        public static short GetFormat(string format)
+        {
+            lock (FormatList)
+            {
+                var pd = FormatList.FirstOrDefault(f => StringComparer.OrdinalIgnoreCase.Equals(f.Name, format));
+                if (pd == null)
+                {
+                    int id = UnmanagedMethods.RegisterClipboardFormat(format);
+                    if (id == 0)
+                        throw new Win32Exception();
+                    pd = new ClipboardFormat(format, (short)id);
+                    FormatList.Add(pd);
+                }
+                return pd.Format;
+            }
+        }
+        
+
+    }
+}

+ 27 - 0
src/Windows/Avalonia.Win32/CursorFactory.cs

@@ -9,6 +9,7 @@ using System.Text;
 using System.Threading.Tasks;
 using Avalonia.Input;
 using Avalonia.Platform;
+using System.Runtime.InteropServices;
 
 namespace Avalonia.Win32
 {
@@ -20,6 +21,27 @@ namespace Avalonia.Win32
         {
         }
 
+        static CursorFactory()
+        {
+            LoadModuleCursor(StandardCursorType.DragMove, "ole32.dll", 2);
+            LoadModuleCursor(StandardCursorType.DragCopy, "ole32.dll", 3);
+            LoadModuleCursor(StandardCursorType.DragLink, "ole32.dll", 4);
+        }
+
+        private static void LoadModuleCursor(StandardCursorType cursorType, string module, int id)
+        {
+            IntPtr mh = UnmanagedMethods.GetModuleHandle(module);
+            if (mh != IntPtr.Zero)
+            {
+                IntPtr cursor = UnmanagedMethods.LoadCursor(mh, new IntPtr(id));
+                if (cursor != IntPtr.Zero)
+                {
+                    PlatformHandle phCursor = new PlatformHandle(cursor, PlatformConstants.CursorHandleType);
+                    Cache.Add(cursorType, phCursor);
+                }
+            }
+        }
+
         private static readonly Dictionary<StandardCursorType, int> CursorTypeMapping = new Dictionary
             <StandardCursorType, int>
         {
@@ -47,6 +69,11 @@ namespace Avalonia.Win32
             //Using SizeNorthEastSouthWest
             {StandardCursorType.TopRightCorner, 32643},
             {StandardCursorType.BottomLeftCorner, 32643},
+
+            // Fallback, should have been loaded from ole32.dll
+            {StandardCursorType.DragMove, 32516},
+            {StandardCursorType.DragCopy, 32516},
+            {StandardCursorType.DragLink, 32516},
         };
 
         private static readonly Dictionary<StandardCursorType, IPlatformHandle> Cache =

+ 361 - 0
src/Windows/Avalonia.Win32/DataObject.cs

@@ -0,0 +1,361 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Win32.Interop;
+using IDataObject = Avalonia.Input.IDataObject;
+using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+
+namespace Avalonia.Win32
+{
+    class DataObject : IDataObject, IOleDataObject
+    {
+        // Compatibility with WinForms + WPF...
+        internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
+
+        class FormatEnumerator : IEnumFORMATETC
+        {
+            private FORMATETC[] _formats;
+            private int _current;
+
+            private FormatEnumerator(FORMATETC[] formats, int current)
+            {
+                _formats = formats;
+                _current = current;
+            }
+
+            public FormatEnumerator(IDataObject dataobj)
+            {
+                _formats = dataobj.GetDataFormats().Select(ConvertToFormatEtc).ToArray();
+                _current = 0;
+            }
+
+            private FORMATETC ConvertToFormatEtc(string aFormatName)
+            {
+                FORMATETC result = default(FORMATETC);
+                result.cfFormat = ClipboardFormats.GetFormat(aFormatName);
+                result.dwAspect = DVASPECT.DVASPECT_CONTENT;
+                result.ptd = IntPtr.Zero;
+                result.lindex = -1;
+                result.tymed = TYMED.TYMED_HGLOBAL;
+                return result;
+            }
+
+            public void Clone(out IEnumFORMATETC newEnum)
+            {
+                newEnum = new FormatEnumerator(_formats, _current);
+            }
+
+            public int Next(int celt, FORMATETC[] rgelt, int[] pceltFetched)
+            {
+                if (rgelt == null)
+                    return unchecked((int)UnmanagedMethods.HRESULT.E_INVALIDARG);
+
+                int i = 0;
+                while (i < celt && _current < _formats.Length)
+                {
+                    rgelt[i] = _formats[_current];
+                    _current++;
+                    i++;
+                }
+                if (pceltFetched != null)
+                    pceltFetched[0] = i;
+
+                if (i != celt)
+                    return unchecked((int)UnmanagedMethods.HRESULT.S_FALSE);
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            }
+
+            public int Reset()
+            {
+                _current = 0;
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            }
+
+            public int Skip(int celt)
+            {
+                _current += Math.Min(celt, int.MaxValue - _current);
+                if (_current >= _formats.Length)
+                    return unchecked((int)UnmanagedMethods.HRESULT.S_FALSE);
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            }
+        }
+
+        private const int DV_E_TYMED = unchecked((int)0x80040069);
+        private const int DV_E_DVASPECT = unchecked((int)0x8004006B);
+        private const int DV_E_FORMATETC = unchecked((int)0x80040064);
+        private const int OLE_E_ADVISENOTSUPPORTED = unchecked((int)0x80040003);
+        private const int STG_E_MEDIUMFULL = unchecked((int)0x80030070);
+        private const int GMEM_ZEROINIT = 0x0040;
+        private const int GMEM_MOVEABLE = 0x0002;
+
+
+        IDataObject _wrapped;
+        
+        public DataObject(IDataObject wrapped)
+        {
+            _wrapped = wrapped;
+        }
+
+        #region IDataObject
+        bool IDataObject.Contains(string dataFormat)
+        {
+            return _wrapped.Contains(dataFormat);
+        }
+
+        IEnumerable<string> IDataObject.GetDataFormats()
+        {
+            return _wrapped.GetDataFormats();
+        }
+
+        IEnumerable<string> IDataObject.GetFileNames()
+        {
+            return _wrapped.GetFileNames();
+        }
+
+        string IDataObject.GetText()
+        {
+            return _wrapped.GetText();
+        }
+
+        object IDataObject.Get(string dataFormat)
+        {
+            return _wrapped.Get(dataFormat);
+        }
+        #endregion
+
+        #region IOleDataObject
+
+        int IOleDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection)
+        {
+            if (_wrapped is IOleDataObject ole)
+                return ole.DAdvise(ref pFormatetc, advf, adviseSink, out connection);
+            connection = 0;
+            return OLE_E_ADVISENOTSUPPORTED;
+        }
+
+        void IOleDataObject.DUnadvise(int connection)
+        {
+            if (_wrapped is IOleDataObject ole)
+                ole.DUnadvise(connection);
+            Marshal.ThrowExceptionForHR(OLE_E_ADVISENOTSUPPORTED);
+        }
+
+        int IOleDataObject.EnumDAdvise(out IEnumSTATDATA enumAdvise)
+        {
+            if (_wrapped is IOleDataObject ole)
+                return ole.EnumDAdvise(out enumAdvise);
+
+            enumAdvise = null;
+            return OLE_E_ADVISENOTSUPPORTED;
+        }
+
+        IEnumFORMATETC IOleDataObject.EnumFormatEtc(DATADIR direction)
+        {
+            if (_wrapped is IOleDataObject ole)
+                return ole.EnumFormatEtc(direction);
+            if (direction == DATADIR.DATADIR_GET)
+                return new FormatEnumerator(_wrapped);
+            throw new NotSupportedException();
+        }
+
+        int IOleDataObject.GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut)
+        {
+            if (_wrapped is IOleDataObject ole)
+                return ole.GetCanonicalFormatEtc(ref formatIn, out formatOut);
+
+            formatOut = new FORMATETC();
+            formatOut.ptd = IntPtr.Zero;
+            return unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL);
+        }
+
+        void IOleDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium)
+        {
+            if (_wrapped is IOleDataObject ole)
+            {
+                ole.GetData(ref format, out medium);
+                return;
+            }
+            if(!format.tymed.HasFlag(TYMED.TYMED_HGLOBAL))
+                Marshal.ThrowExceptionForHR(DV_E_TYMED);
+
+            if (format.dwAspect != DVASPECT.DVASPECT_CONTENT)
+                Marshal.ThrowExceptionForHR(DV_E_DVASPECT);
+
+            string fmt = ClipboardFormats.GetFormat(format.cfFormat);
+            if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt))
+                Marshal.ThrowExceptionForHR(DV_E_FORMATETC);
+
+            medium = default(STGMEDIUM);
+            medium.tymed = TYMED.TYMED_HGLOBAL;
+            int result = WriteDataToHGlobal(fmt, ref medium.unionmember);
+            Marshal.ThrowExceptionForHR(result);
+        }
+
+        void IOleDataObject.GetDataHere(ref FORMATETC format, ref STGMEDIUM medium)
+        {
+            if (_wrapped is IOleDataObject ole)
+            {
+                ole.GetDataHere(ref format, ref medium);
+                return;
+            }
+
+            if (medium.tymed != TYMED.TYMED_HGLOBAL || !format.tymed.HasFlag(TYMED.TYMED_HGLOBAL))
+                Marshal.ThrowExceptionForHR(DV_E_TYMED);
+
+            if (format.dwAspect != DVASPECT.DVASPECT_CONTENT)
+                Marshal.ThrowExceptionForHR(DV_E_DVASPECT);
+
+            string fmt = ClipboardFormats.GetFormat(format.cfFormat);
+            if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt))
+                Marshal.ThrowExceptionForHR(DV_E_FORMATETC);
+
+            if (medium.unionmember == IntPtr.Zero)
+                Marshal.ThrowExceptionForHR(STG_E_MEDIUMFULL);
+
+            int result = WriteDataToHGlobal(fmt, ref medium.unionmember);
+            Marshal.ThrowExceptionForHR(result);
+        }
+
+        int IOleDataObject.QueryGetData(ref FORMATETC format)
+        {
+            if (_wrapped is IOleDataObject ole)
+                return ole.QueryGetData(ref format);
+            if (format.dwAspect != DVASPECT.DVASPECT_CONTENT)
+                return DV_E_DVASPECT;
+            if (!format.tymed.HasFlag(TYMED.TYMED_HGLOBAL))
+                return DV_E_TYMED;
+
+            string dataFormat = ClipboardFormats.GetFormat(format.cfFormat);
+            if (!string.IsNullOrEmpty(dataFormat) && _wrapped.Contains(dataFormat))
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            return DV_E_FORMATETC;
+        }
+        
+        void IOleDataObject.SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release)
+        {
+            if (_wrapped is IOleDataObject ole)
+            {
+                ole.SetData(ref formatIn, ref medium, release);
+                return;
+            }
+            Marshal.ThrowExceptionForHR(unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL));
+        }
+
+        private int WriteDataToHGlobal(string dataFormat, ref IntPtr hGlobal)
+        {
+            object data = _wrapped.Get(dataFormat);
+            if (dataFormat == DataFormats.Text || data is string)
+                return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data));
+            if (dataFormat == DataFormats.FileNames && data is IEnumerable<string> files)
+                return WriteFileListToHGlobal(ref hGlobal, files);
+            if (data is Stream stream)
+            {
+                byte[] buffer = new byte[stream.Length - stream.Position];
+                stream.Read(buffer, 0, buffer.Length);
+                return WriteBytesToHGlobal(ref hGlobal, buffer);
+            }
+            if (data is IEnumerable<byte> bytes)
+            {
+                var byteArr = bytes is byte[] ? (byte[])bytes : bytes.ToArray();
+                return WriteBytesToHGlobal(ref hGlobal, byteArr);
+            }
+            return WriteBytesToHGlobal(ref hGlobal, SerializeObject(data));
+        }
+
+        private byte[] SerializeObject(object data)
+        {
+            using (var ms = new MemoryStream())
+            {
+                ms.Write(SerializedObjectGUID, 0, SerializedObjectGUID.Length);
+                BinaryFormatter binaryFormatter = new BinaryFormatter();
+                binaryFormatter.Serialize(ms, data);
+                return ms.ToArray();
+            }
+        }
+
+        private int WriteBytesToHGlobal(ref IntPtr hGlobal, byte[] data)
+        {
+            int required = data.Length;
+            if (hGlobal == IntPtr.Zero)
+                hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, required);
+
+            long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+            if (required > available)
+                return STG_E_MEDIUMFULL;
+
+            IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+            try
+            {
+                Marshal.Copy(data, 0, ptr, data.Length);
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            }
+            finally
+            {
+                UnmanagedMethods.GlobalUnlock(hGlobal);
+            }
+        }
+
+        private int WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable<string> files)
+        {
+            if (!files?.Any() ?? false)
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+
+            char[] filesStr = (string.Join("\0", files) + "\0\0").ToCharArray();
+            _DROPFILES df = new _DROPFILES();
+            df.pFiles = Marshal.SizeOf<_DROPFILES>();
+            df.fWide = true;
+            
+            int required = (filesStr.Length * sizeof(char)) + Marshal.SizeOf<_DROPFILES>();
+            if (hGlobal == IntPtr.Zero)
+                hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, required);
+
+            long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+            if (required > available)
+                return STG_E_MEDIUMFULL;
+
+            IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+            try
+            {
+                Marshal.StructureToPtr(df, ptr, false);
+
+                Marshal.Copy(filesStr, 0, ptr + Marshal.SizeOf<_DROPFILES>(), filesStr.Length);
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            }
+            finally
+            {
+                UnmanagedMethods.GlobalUnlock(hGlobal);
+            }
+        }
+
+        private int WriteStringToHGlobal(ref IntPtr hGlobal, string data)
+        {
+            int required = (data.Length + 1) * sizeof(char);
+            if (hGlobal == IntPtr.Zero)
+                hGlobal = UnmanagedMethods.GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, required);
+
+            long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+            if (required > available)
+                return STG_E_MEDIUMFULL;
+            
+            IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+            try
+            {
+                char[] chars = (data + '\0').ToCharArray();
+                Marshal.Copy(chars, 0, ptr, chars.Length);
+                return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+            }
+            finally
+            {
+                UnmanagedMethods.GlobalUnlock(hGlobal);
+            }
+        }
+
+        #endregion
+    }
+}

+ 27 - 0
src/Windows/Avalonia.Win32/DragSource.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Threading;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+    class DragSource : IPlatformDragSource
+    {
+        public Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
+        {
+            Dispatcher.UIThread.VerifyAccess();
+
+            OleDragSource src = new OleDragSource();
+            DataObject dataObject = new DataObject(data);
+            int allowed = (int)OleDropTarget.ConvertDropEffect(allowedEffects);
+
+            int[] finalEffect = new int[1];
+            UnmanagedMethods.DoDragDrop(dataObject, src, allowed, finalEffect);
+
+            return Task.FromResult(OleDropTarget.ConvertDropEffect((DropEffect)finalEffect[0]));}
+    }
+}

+ 99 - 3
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@@ -5,6 +5,7 @@ using System;
 using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
 using System.Text;
 
 // ReSharper disable InconsistentNaming
@@ -951,6 +952,32 @@ namespace Avalonia.Win32.Interop
         [DllImport("msvcrt.dll", EntryPoint="memcpy", SetLastError = false, CallingConvention=CallingConvention.Cdecl)]
         public static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, UIntPtr count); 
         
+        [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+        public static extern HRESULT RegisterDragDrop(IntPtr hwnd, IDropTarget target);
+        
+        [DllImport("ole32.dll", EntryPoint = "OleInitialize")]
+        public static extern HRESULT OleInitialize(IntPtr val);
+
+        [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+        internal static extern void ReleaseStgMedium(ref STGMEDIUM medium);
+
+        [DllImport("user32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
+        public static extern int GetClipboardFormatName(int format, StringBuilder lpString, int cchMax);
+
+        [DllImport("user32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
+        public static extern int RegisterClipboardFormat(string format);
+
+        [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)]
+        public static extern IntPtr GlobalSize(IntPtr hGlobal);
+
+        [DllImport("shell32.dll", BestFitMapping = false, CharSet = CharSet.Auto)]
+        public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
+
+        [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
+        public static extern void DoDragDrop(IDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect);
+
+
+
         public enum MONITOR
         {
             MONITOR_DEFAULTTONULL = 0x00000000,
@@ -990,10 +1017,28 @@ namespace Avalonia.Win32.Interop
             MDT_DEFAULT = MDT_EFFECTIVE_DPI
         } 
 
-        public enum ClipboardFormat
+        public enum ClipboardFormat 
         {
+            /// <summary>
+            /// Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data. Use this format for ANSI text.
+            /// </summary>
             CF_TEXT = 1,
-            CF_UNICODETEXT = 13
+            /// <summary>
+            /// A handle to a bitmap
+            /// </summary>
+            CF_BITMAP = 2,
+            /// <summary>
+            /// A memory object containing a BITMAPINFO structure followed by the bitmap bits.
+            /// </summary>
+            CF_DIB = 3,
+            /// <summary>
+            /// Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.
+            /// </summary>
+            CF_UNICODETEXT = 13,
+            /// <summary>
+            /// A handle to type HDROP that identifies a list of files. 
+            /// </summary>
+            CF_HDROP = 15,
         }
 
         public struct MSG
@@ -1136,7 +1181,9 @@ namespace Avalonia.Win32.Interop
             S_FALSE = 0x0001,
             S_OK = 0x0000,
             E_INVALIDARG = 0x80070057,
-            E_OUTOFMEMORY = 0x8007000E
+            E_OUTOFMEMORY = 0x8007000E,
+            E_NOTIMPL = 0x80004001,
+            E_UNEXPECTED = 0x8000FFFF,
         }
 
         public enum Icons
@@ -1300,4 +1347,53 @@ namespace Avalonia.Win32.Interop
         uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
         
     }
+    
+    [Flags]
+    internal enum DropEffect : int
+    {
+        None = 0,
+        Copy = 1,
+        Move = 2,
+        Link = 4,
+        Scroll = -2147483648,
+    }
+    
+    
+    
+    [ComImport]
+    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+    [Guid("00000122-0000-0000-C000-000000000046")]
+    internal interface IDropTarget
+    {
+        [PreserveSig]
+        UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+        [PreserveSig]
+        UnmanagedMethods.HRESULT DragOver([MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+        [PreserveSig]
+        UnmanagedMethods.HRESULT DragLeave();
+        [PreserveSig]
+        UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+    }
+
+    [ComImport]
+    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+    [Guid("00000121-0000-0000-C000-000000000046")]
+    internal interface IDropSource
+    {
+        [PreserveSig]
+        int QueryContinueDrag(int fEscapePressed, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState);
+        [PreserveSig]
+        int GiveFeedback([MarshalAs(UnmanagedType.U4)] [In] int dwEffect);
+    }
+
+
+    [StructLayoutAttribute(LayoutKind.Sequential)]
+    internal struct _DROPFILES
+    {
+        public Int32 pFiles;
+        public Int32 X;
+        public Int32 Y;
+        public bool fNC;
+        public bool fWide;
+    }
 }

+ 47 - 0
src/Windows/Avalonia.Win32/OleContext.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Threading;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+    class OleContext
+    {
+        private static OleContext fCurrent;
+
+        internal static OleContext Current
+        {
+            get
+            {
+                if (!IsValidOleThread())
+                    return null;
+
+                if (fCurrent == null)
+                    fCurrent = new OleContext();
+                return fCurrent;
+            }
+        }
+
+
+        private OleContext()
+        {
+            if (UnmanagedMethods.OleInitialize(IntPtr.Zero) != UnmanagedMethods.HRESULT.S_OK)
+                throw new SystemException("Failed to initialize OLE");
+        }
+
+        private static bool IsValidOleThread()
+        {
+            return Dispatcher.UIThread.CheckAccess() &&
+                   Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
+        }
+
+        internal bool RegisterDragDrop(IPlatformHandle hwnd, IDropTarget target)
+        {
+            if (hwnd?.HandleDescriptor != "HWND" || target == null)
+                return false;
+
+            return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, target) == UnmanagedMethods.HRESULT.S_OK;
+        }
+    }
+}

+ 171 - 0
src/Windows/Avalonia.Win32/OleDataObject.cs

@@ -0,0 +1,171 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Win32.Interop;
+using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
+
+namespace Avalonia.Win32
+{
+    class OleDataObject : Avalonia.Input.IDataObject
+    {
+        private IDataObject _wrapped;
+
+        public OleDataObject(IDataObject wrapped)
+        {
+            _wrapped = wrapped;
+        }
+
+        public bool Contains(string dataFormat)
+        {
+            return GetDataFormatsCore().Any(df => StringComparer.OrdinalIgnoreCase.Equals(df, dataFormat));
+        }
+
+        public IEnumerable<string> GetDataFormats()
+        {
+            return GetDataFormatsCore().Distinct();
+        }
+
+        public string GetText()
+        {
+            return GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT) as string;
+        }
+
+        public IEnumerable<string> GetFileNames()
+        {
+            return GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT) as IEnumerable<string>;
+        }
+
+        public object Get(string dataFormat)
+        {
+            return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT);
+        }
+
+        private object GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
+        {
+            FORMATETC formatEtc = new FORMATETC();
+            formatEtc.cfFormat = ClipboardFormats.GetFormat(format);
+            formatEtc.dwAspect = aspect;
+            formatEtc.lindex = -1;
+            formatEtc.tymed = TYMED.TYMED_HGLOBAL;
+            if (_wrapped.QueryGetData(ref formatEtc) == 0)
+            {
+                _wrapped.GetData(ref formatEtc, out STGMEDIUM medium);
+                try
+                {
+                    if (medium.unionmember != IntPtr.Zero && medium.tymed == TYMED.TYMED_HGLOBAL)
+                    {
+                        if (format == DataFormats.Text)
+                            return ReadStringFromHGlobal(medium.unionmember);
+                        if (format == DataFormats.FileNames)
+                            return ReadFileNamesFromHGlobal(medium.unionmember);
+
+                        byte[] data = ReadBytesFromHGlobal(medium.unionmember);
+
+                        if (IsSerializedObject(data))
+                        {
+                            using (var ms = new MemoryStream(data))
+                            {
+                                ms.Position = DataObject.SerializedObjectGUID.Length;
+                                BinaryFormatter binaryFormatter = new BinaryFormatter();
+                                return binaryFormatter.Deserialize(ms);
+                            }
+                        }
+                        return data;
+                    }
+                }
+                finally
+                {
+                    UnmanagedMethods.ReleaseStgMedium(ref medium);
+                }
+            }
+            return null;
+        }
+
+        private bool IsSerializedObject(byte[] data)
+        {
+            if (data.Length < DataObject.SerializedObjectGUID.Length)
+                return false;
+            for (int i = 0; i < DataObject.SerializedObjectGUID.Length; i++)
+                if (data[i] != DataObject.SerializedObjectGUID[i])
+                    return false;
+            return true;
+        }
+
+        private static IEnumerable<string> ReadFileNamesFromHGlobal(IntPtr hGlobal)
+        {
+            List<string> files = new List<string>();
+            int fileCount = UnmanagedMethods.DragQueryFile(hGlobal, -1, null, 0);
+            if (fileCount > 0)
+            {
+                for (int i = 0; i < fileCount; i++)
+                {
+                    int pathLen = UnmanagedMethods.DragQueryFile(hGlobal, i, null, 0);
+                    StringBuilder sb = new StringBuilder(pathLen+1);
+
+                    if (UnmanagedMethods.DragQueryFile(hGlobal, i, sb, sb.Capacity) == pathLen)
+                    {
+                        files.Add(sb.ToString());
+                    }
+                }
+            }
+            return files;
+        }
+
+        private static string ReadStringFromHGlobal(IntPtr hGlobal)
+        {
+            IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
+            try
+            {
+                return Marshal.PtrToStringAuto(ptr);
+            }
+            finally
+            {
+                UnmanagedMethods.GlobalUnlock(hGlobal);
+            }
+        }
+
+        private static byte[] ReadBytesFromHGlobal(IntPtr hGlobal)
+        {
+            IntPtr source = UnmanagedMethods.GlobalLock(hGlobal);
+            try
+            {
+                int size = (int)UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
+                byte[] data = new byte[size];
+                Marshal.Copy(source, data, 0, size);
+                return data;
+            }
+            finally
+            {
+                UnmanagedMethods.GlobalUnlock(hGlobal);
+            }
+        }
+
+        private IEnumerable<string> GetDataFormatsCore()
+        {
+            var enumFormat = _wrapped.EnumFormatEtc(DATADIR.DATADIR_GET);
+            if (enumFormat != null)
+            {
+                enumFormat.Reset();
+                FORMATETC[] formats = new FORMATETC[1];
+                int[] fetched = { 1 };
+                while (fetched[0] > 0)
+                {
+                    fetched[0] = 0;
+                    if (enumFormat.Next(1, formats, fetched) == 0 && fetched[0] > 0)
+                    {
+                        if (formats[0].ptd != IntPtr.Zero)
+                            Marshal.FreeCoTaskMem(formats[0].ptd);
+                        
+                        yield return ClipboardFormats.GetFormat(formats[0].cfFormat);
+                    }
+                }
+            }
+        }
+    }
+}

+ 39 - 0
src/Windows/Avalonia.Win32/OleDragSource.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+    class OleDragSource : IDropSource
+    {
+        private const int DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102;
+        private const int DRAGDROP_S_DROP = 0x00040100;
+        private const int DRAGDROP_S_CANCEL = 0x00040101;
+
+        private const int KEYSTATE_LEFTMB = 1;
+        private const int KEYSTATE_MIDDLEMB = 16;
+        private const int KEYSTATE_RIGHTMB = 2;
+        private static readonly int[] MOUSE_BUTTONS = new int[] { KEYSTATE_LEFTMB, KEYSTATE_MIDDLEMB, KEYSTATE_RIGHTMB };
+
+        public int QueryContinueDrag(int fEscapePressed, int grfKeyState)
+        {
+            if (fEscapePressed != 0)
+                return DRAGDROP_S_CANCEL;
+
+            int pressedMouseButtons = MOUSE_BUTTONS.Where(mb => (grfKeyState & mb) == mb).Count();
+
+            if (pressedMouseButtons >= 2)
+                return DRAGDROP_S_CANCEL;
+            if (pressedMouseButtons == 0)
+                return DRAGDROP_S_DROP;
+
+            return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
+        }
+
+        public int GiveFeedback(int dwEffect)
+        {
+            return DRAGDROP_S_USEDEFAULTCURSORS;
+        }
+    }
+}

+ 160 - 0
src/Windows/Avalonia.Win32/OleDropTarget.cs

@@ -0,0 +1,160 @@
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Win32.Interop;
+using IDataObject = Avalonia.Input.IDataObject;
+using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
+
+namespace Avalonia.Win32
+{
+    class OleDropTarget : IDropTarget
+    {
+        private readonly IInputElement _target;
+        private readonly ITopLevelImpl _tl;
+        private readonly IDragDropDevice _dragDevice;
+        
+        private IDataObject _currentDrag = null;
+
+        public OleDropTarget(ITopLevelImpl tl, IInputElement target)
+        {
+            _dragDevice = AvaloniaLocator.Current.GetService<IDragDropDevice>();
+            _tl = tl;
+            _target = target;
+        }
+
+        public static DropEffect ConvertDropEffect(DragDropEffects operation)
+        {
+            DropEffect result = DropEffect.None;
+            if (operation.HasFlag(DragDropEffects.Copy))
+                result |= DropEffect.Copy;
+            if (operation.HasFlag(DragDropEffects.Move))
+                result |= DropEffect.Move;
+            if (operation.HasFlag(DragDropEffects.Link))
+                result |= DropEffect.Link;
+            return result;
+        }
+
+        public static DragDropEffects ConvertDropEffect(DropEffect effect)
+        {
+            DragDropEffects result = DragDropEffects.None;
+            if (effect.HasFlag(DropEffect.Copy))
+                result |= DragDropEffects.Copy;
+            if (effect.HasFlag(DropEffect.Move))
+                result |= DragDropEffects.Move;
+            if (effect.HasFlag(DropEffect.Link))
+                result |= DragDropEffects.Link;
+            return result;
+        }
+        
+        UnmanagedMethods.HRESULT IDropTarget.DragEnter(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect)
+        {
+            var dispatch = _tl?.Input;
+            if (dispatch == null)
+            {
+                pdwEffect = DropEffect.None;
+                return UnmanagedMethods.HRESULT.S_OK;
+            }
+            _currentDrag = pDataObj as IDataObject;
+            if (_currentDrag == null)
+                _currentDrag = new OleDataObject(pDataObj);
+            var args = new RawDragEvent(
+                _dragDevice,
+                RawDragEventType.DragEnter, 
+                _target, 
+                GetDragLocation(pt), 
+                _currentDrag, 
+                ConvertDropEffect(pdwEffect)
+            );
+            dispatch(args);
+            pdwEffect = ConvertDropEffect(args.Effects);
+            
+            return UnmanagedMethods.HRESULT.S_OK;
+        }
+
+        UnmanagedMethods.HRESULT IDropTarget.DragOver(int grfKeyState, long pt, ref DropEffect pdwEffect)
+        {
+            var dispatch = _tl?.Input;
+            if (dispatch == null)
+            {
+                pdwEffect = DropEffect.None;
+                return UnmanagedMethods.HRESULT.S_OK;
+            }
+            
+            var args = new RawDragEvent(
+                _dragDevice,
+                RawDragEventType.DragOver, 
+                _target, 
+                GetDragLocation(pt), 
+                _currentDrag, 
+                ConvertDropEffect(pdwEffect)
+            );
+            dispatch(args);
+            pdwEffect = ConvertDropEffect(args.Effects);
+            
+            return UnmanagedMethods.HRESULT.S_OK;  
+        }
+
+        UnmanagedMethods.HRESULT IDropTarget.DragLeave()
+        {
+            try
+            {
+                _tl?.Input(new RawDragEvent(
+                    _dragDevice,  
+                    RawDragEventType.DragLeave, 
+                    _target, 
+                    default(Point), 
+                    null, 
+                    DragDropEffects.None
+                ));
+                return UnmanagedMethods.HRESULT.S_OK;
+            }
+            finally
+            {
+                _currentDrag = null;
+            }
+        }
+
+        UnmanagedMethods.HRESULT IDropTarget.Drop(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect)
+        {
+            try
+            {
+                var dispatch = _tl?.Input;
+                if (dispatch == null)
+                {
+                    pdwEffect = DropEffect.None;
+                    return UnmanagedMethods.HRESULT.S_OK;
+                }
+
+                _currentDrag = pDataObj as IDataObject;
+                if (_currentDrag == null)
+                    _currentDrag= new OleDataObject(pDataObj);
+                
+                var args = new RawDragEvent(
+                    _dragDevice, 
+                    RawDragEventType.Drop, 
+                    _target, 
+                    GetDragLocation(pt), 
+                    _currentDrag, 
+                    ConvertDropEffect(pdwEffect)
+                );
+                dispatch(args);
+                pdwEffect = ConvertDropEffect(args.Effects);
+            
+                return UnmanagedMethods.HRESULT.S_OK;  
+            }
+            finally
+            {
+                _currentDrag = null;
+            }
+        }
+
+        private Point GetDragLocation(long dragPoint)
+        {
+            int x = (int)dragPoint;
+            int y = (int)(dragPoint >> 32);
+
+            Point screenPt = new Point(x, y);
+            return _target.PointToClient(screenPt);
+        }
+    }
+}

+ 3 - 0
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -86,6 +86,9 @@ namespace Avalonia.Win32
                 .Bind<IWindowingPlatform>().ToConstant(s_instance)
                 .Bind<IPlatformIconLoader>().ToConstant(s_instance);
 
+            if (OleContext.Current != null)
+                AvaloniaLocator.CurrentMutable.Bind<IPlatformDragSource>().ToSingleton<DragSource>();
+
             UseDeferredRendering = deferredRendering;
             _uiThread = UnmanagedMethods.GetCurrentThreadId();
         }

+ 9 - 0
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -34,6 +34,7 @@ namespace Avalonia.Win32
         private double _scaling = 1;
         private WindowState _showWindowState;
         private FramebufferManager _framebuffer;
+        private OleDropTarget _dropTarget;
 #if USE_MANAGED_DRAG
         private readonly ManagedWindowResizeDragHelper _managedDrag;
 #endif
@@ -310,6 +311,7 @@ namespace Avalonia.Win32
         public void SetInputRoot(IInputRoot inputRoot)
         {
             _owner = inputRoot;
+            CreateDropTarget();
         }
 
         public void SetTitle(string title)
@@ -699,6 +701,13 @@ namespace Avalonia.Win32
             }
         }
 
+        private void CreateDropTarget()
+        {
+            OleDropTarget odt = new OleDropTarget(this, _owner);
+            if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false)
+                _dropTarget = odt;
+        }
+
         private Point DipFromLParam(IntPtr lParam)
         {
             return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling;

+ 4 - 3
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@@ -8,6 +8,7 @@ using Avalonia.Markup.Xaml.Data;
 using Avalonia.Markup.Xaml.Styling;
 using Avalonia.Markup.Xaml.Templates;
 using Avalonia.Media;
+using Avalonia.Media.Immutable;
 using Avalonia.Styling;
 using Avalonia.UnitTests;
 using System.Collections;
@@ -359,8 +360,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
 
             var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
             var bk = control.Background;
-            Assert.IsType<SolidColorBrush>(bk);
-            Assert.Equal(Colors.White, (bk as SolidColorBrush).Color);
+            Assert.IsType<ImmutableSolidColorBrush>(bk);
+            Assert.Equal(Colors.White, (bk as ISolidColorBrush).Color);
         }
 
         [Fact]
@@ -496,7 +497,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
 
             Assert.NotNull(brush);
 
-            Assert.Equal(Colors.White, ((SolidColorBrush)brush).Color);
+            Assert.Equal(Colors.White, ((ISolidColorBrush)brush).Color);
 
             style.TryGetResource("Double", out var d);
 

+ 14 - 4
tests/Avalonia.Visuals.UnitTests/Media/BrushTests.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Visuals.UnitTests.Media
         [Fact]
         public void Parse_Parses_RGB_Hash_Brush()
         {
-            var result = (SolidColorBrush)Brush.Parse("#ff8844");
+            var result = (ISolidColorBrush)Brush.Parse("#ff8844");
 
             Assert.Equal(0xff, result.Color.R);
             Assert.Equal(0x88, result.Color.G);
@@ -23,7 +23,7 @@ namespace Avalonia.Visuals.UnitTests.Media
         [Fact]
         public void Parse_Parses_ARGB_Hash_Brush()
         {
-            var result = (SolidColorBrush)Brush.Parse("#40ff8844");
+            var result = (ISolidColorBrush)Brush.Parse("#40ff8844");
 
             Assert.Equal(0xff, result.Color.R);
             Assert.Equal(0x88, result.Color.G);
@@ -34,7 +34,7 @@ namespace Avalonia.Visuals.UnitTests.Media
         [Fact]
         public void Parse_Parses_Named_Brush_Lowercase()
         {
-            var result = (SolidColorBrush)Brush.Parse("red");
+            var result = (ISolidColorBrush)Brush.Parse("red");
 
             Assert.Equal(0xff, result.Color.R);
             Assert.Equal(0x00, result.Color.G);
@@ -45,7 +45,7 @@ namespace Avalonia.Visuals.UnitTests.Media
         [Fact]
         public void Parse_Parses_Named_Brush_Uppercase()
         {
-            var result = (SolidColorBrush)Brush.Parse("RED");
+            var result = (ISolidColorBrush)Brush.Parse("RED");
 
             Assert.Equal(0xff, result.Color.R);
             Assert.Equal(0x00, result.Color.G);
@@ -53,6 +53,16 @@ namespace Avalonia.Visuals.UnitTests.Media
             Assert.Equal(0xff, result.Color.A);
         }
 
+        [Fact]
+        public void Parse_ToString_Named_Brush_Roundtrip()
+        {
+            const string expectedName = "Red";
+            var brush = (ISolidColorBrush)Brush.Parse(expectedName);
+            var name = brush.ToString();
+
+            Assert.Equal(expectedName, name);
+        }
+
         [Fact]
         public void Parse_Hex_Value_Doesnt_Accept_Too_Few_Chars()
         {

+ 8 - 0
tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using System.Globalization;
 using Xunit;
 
@@ -25,5 +26,12 @@ namespace Avalonia.Visuals.UnitTests
 
             Assert.Equal(new RelativeRect(0.1, 0.2, 0.4, 0.7, RelativeUnit.Relative), result, Compare);
         }
+
+        [Fact]
+        public void Parse_Should_Throw_Mixed_Values()
+        {
+            Assert.Throws<FormatException>(() =>
+                RelativeRect.Parse("10%, 20%, 40, 70%", CultureInfo.InvariantCulture));
+        }
     }
 }