Bläddra i källkod

Initial commit

Interop and PlatformThreadingInterface seem to be working, initial work on IWindowImpl
Nikita Tsukanov 7 år sedan
incheckning
39f57c38d4
97 ändrade filer med 4107 tillägg och 0 borttagningar
  1. 41 0
      .gitignore
  2. 31 0
      Avalonia.Native.sln
  3. 14 0
      NuGet.Config
  4. 22 0
      samples/ControlCatalog/App.config
  5. 19 0
      samples/ControlCatalog/App.xaml
  6. 13 0
      samples/ControlCatalog/App.xaml.cs
  7. BIN
      samples/ControlCatalog/Assets/Fonts/SourceSansPro-Bold.ttf
  8. BIN
      samples/ControlCatalog/Assets/Fonts/SourceSansPro-BoldItalic.ttf
  9. BIN
      samples/ControlCatalog/Assets/Fonts/SourceSansPro-Italic.ttf
  10. BIN
      samples/ControlCatalog/Assets/Fonts/SourceSansPro-Regular.ttf
  11. BIN
      samples/ControlCatalog/Assets/delicate-arch-896885_640.jpg
  12. BIN
      samples/ControlCatalog/Assets/github_icon.png
  13. BIN
      samples/ControlCatalog/Assets/hirsch-899118_640.jpg
  14. BIN
      samples/ControlCatalog/Assets/maple-leaf-888807_640.jpg
  15. BIN
      samples/ControlCatalog/Assets/test_icon.ico
  16. 21 0
      samples/ControlCatalog/ControlCatalog.csproj
  17. 33 0
      samples/ControlCatalog/DecoratedWindow.xaml
  18. 53 0
      samples/ControlCatalog/DecoratedWindow.xaml.cs
  19. 32 0
      samples/ControlCatalog/MainView.xaml
  20. 37 0
      samples/ControlCatalog/MainView.xaml.cs
  21. 6 0
      samples/ControlCatalog/MainWindow.xaml
  22. 28 0
      samples/ControlCatalog/MainWindow.xaml.cs
  23. 59 0
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  24. 145 0
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  25. 32 0
      samples/ControlCatalog/Pages/BorderPage.xaml
  26. 18 0
      samples/ControlCatalog/Pages/BorderPage.xaml.cs
  27. 36 0
      samples/ControlCatalog/Pages/ButtonPage.xaml
  28. 18 0
      samples/ControlCatalog/Pages/ButtonPage.xaml.cs
  29. 24 0
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
  30. 54 0
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
  31. 47 0
      samples/ControlCatalog/Pages/CalendarPage.xaml
  32. 28 0
      samples/ControlCatalog/Pages/CalendarPage.xaml.cs
  33. 35 0
      samples/ControlCatalog/Pages/CanvasPage.xaml
  34. 18 0
      samples/ControlCatalog/Pages/CanvasPage.xaml.cs
  35. 41 0
      samples/ControlCatalog/Pages/CarouselPage.xaml
  36. 51 0
      samples/ControlCatalog/Pages/CarouselPage.xaml.cs
  37. 28 0
      samples/ControlCatalog/Pages/CheckBoxPage.xaml
  38. 18 0
      samples/ControlCatalog/Pages/CheckBoxPage.xaml.cs
  39. 36 0
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  40. 18 0
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  41. 46 0
      samples/ControlCatalog/Pages/DatePickerPage.xaml
  42. 36 0
      samples/ControlCatalog/Pages/DatePickerPage.xaml.cs
  43. 12 0
      samples/ControlCatalog/Pages/DialogsPage.xaml
  44. 46 0
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  45. 19 0
      samples/ControlCatalog/Pages/DragAndDropPage.xaml
  46. 71 0
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  47. 31 0
      samples/ControlCatalog/Pages/DropDownPage.xaml
  48. 18 0
      samples/ControlCatalog/Pages/DropDownPage.xaml.cs
  49. 32 0
      samples/ControlCatalog/Pages/ExpanderPage.xaml
  50. 18 0
      samples/ControlCatalog/Pages/ExpanderPage.xaml.cs
  51. 43 0
      samples/ControlCatalog/Pages/ImagePage.xaml
  52. 41 0
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  53. 26 0
      samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml
  54. 18 0
      samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml.cs
  55. 13 0
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  56. 25 0
      samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
  57. 35 0
      samples/ControlCatalog/Pages/MenuPage.xaml
  58. 18 0
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  59. 24 0
      samples/ControlCatalog/Pages/ProgressBarPage.xaml
  60. 18 0
      samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs
  61. 40 0
      samples/ControlCatalog/Pages/RadioButtonPage.xaml
  62. 18 0
      samples/ControlCatalog/Pages/RadioButtonPage.xaml.cs
  63. 66 0
      samples/ControlCatalog/Pages/ScreenPage.cs
  64. 21 0
      samples/ControlCatalog/Pages/SliderPage.xaml
  65. 18 0
      samples/ControlCatalog/Pages/SliderPage.xaml.cs
  66. 43 0
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  67. 18 0
      samples/ControlCatalog/Pages/TextBoxPage.xaml.cs
  68. 41 0
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  69. 18 0
      samples/ControlCatalog/Pages/ToolTipPage.xaml.cs
  70. 19 0
      samples/ControlCatalog/Pages/TreeViewPage.xaml
  71. 40 0
      samples/ControlCatalog/Pages/TreeViewPage.xaml.cs
  72. 65 0
      samples/ControlCatalog/Program.cs
  73. 52 0
      samples/ControlCatalog/SideBar.xaml
  74. 4 0
      src/Avalonia.Native.OSX/.gitignore
  75. 276 0
      src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  76. 7 0
      src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  77. 91 0
      src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
  78. 12 0
      src/Avalonia.Native.OSX/common.h
  79. 93 0
      src/Avalonia.Native.OSX/main.mm
  80. 178 0
      src/Avalonia.Native.OSX/platformthreading.mm
  81. 199 0
      src/Avalonia.Native.OSX/window.mm
  82. 1 0
      src/Avalonia.Native/.gitignore
  83. 15 0
      src/Avalonia.Native/Avalonia.Native.csproj
  84. 147 0
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  85. 68 0
      src/Avalonia.Native/CallbackBase.cs
  86. 21 0
      src/Avalonia.Native/Cursor.cs
  87. 128 0
      src/Avalonia.Native/DynLoader.cs
  88. 48 0
      src/Avalonia.Native/IconLoader.cs
  89. 27 0
      src/Avalonia.Native/Mappings.xml
  90. 98 0
      src/Avalonia.Native/PlatformThreadingInterface.cs
  91. 48 0
      src/Avalonia.Native/Stubs.cs
  92. 55 0
      src/Avalonia.Native/WindowImpl.cs
  93. 192 0
      src/Avalonia.Native/WindowImplBase.cs
  94. 2 0
      src/Avalonia.Native/regen.sh
  95. 2 0
      src/headers/avalonia-native-guids.h
  96. 90 0
      src/headers/avalonia-native.h
  97. 200 0
      src/headers/com.h

+ 41 - 0
.gitignore

@@ -0,0 +1,41 @@
+# Autosave files
+*~
+
+# build
+[Oo]bj/
+[Bb]in/
+packages/
+TestResults/
+
+# globs
+Makefile.in
+*.DS_Store
+*.sln.cache
+*.suo
+*.cache
+*.pidb
+*.userprefs
+*.usertasks
+config.log
+config.make
+config.status
+aclocal.m4
+install-sh
+autom4te.cache/
+*.user
+*.tar.gz
+tarballs/
+test-results/
+Thumbs.db
+.vs/
+
+# Mac bundle stuff
+*.dmg
+*.app
+
+# resharper
+*_Resharper.*
+*.Resharper
+
+# dotCover
+*.dotCover

+ 31 - 0
Avalonia.Native.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{250A6353-593D-47E2-A630-E91D882078A9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{F9329DCC-62EC-489F-8C13-4FFBF1760E94}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3902AEF7-EA78-44F4-93A9-765DB31C53E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D5FA1304-DD4F-419E-89ED-AAD1E5FDE020}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F9329DCC-62EC-489F-8C13-4FFBF1760E94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F9329DCC-62EC-489F-8C13-4FFBF1760E94}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F9329DCC-62EC-489F-8C13-4FFBF1760E94}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F9329DCC-62EC-489F-8C13-4FFBF1760E94}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D5FA1304-DD4F-419E-89ED-AAD1E5FDE020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D5FA1304-DD4F-419E-89ED-AAD1E5FDE020}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D5FA1304-DD4F-419E-89ED-AAD1E5FDE020}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D5FA1304-DD4F-419E-89ED-AAD1E5FDE020}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{F9329DCC-62EC-489F-8C13-4FFBF1760E94} = {250A6353-593D-47E2-A630-E91D882078A9}
+		{D5FA1304-DD4F-419E-89ED-AAD1E5FDE020} = {3902AEF7-EA78-44F4-93A9-765DB31C53E5}
+	EndGlobalSection
+EndGlobal

+ 14 - 0
NuGet.Config

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageRestore>
+    <add key="enabled" value="True" />
+    <add key="automatic" value="True" />
+  </packageRestore>
+  <packageSources>
+    <add key="NuGet 3 (plain)" value="http://api.nuget.org/v3/index.json" />
+    <add key="Avalonia Nightly" value="https://www.myget.org/F/avalonia-ci/api/v2" />
+  </packageSources>
+  <bindingRedirects>
+    <add key="skip" value="False" />
+  </bindingRedirects>
+</configuration>

+ 22 - 0
samples/ControlCatalog/App.config

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+    </startup>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>

+ 19 - 0
samples/ControlCatalog/App.xaml

@@ -0,0 +1,19 @@
+<Application xmlns="https://github.com/avaloniaui">
+  <Application.Styles>
+    <StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
+    <StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
+
+    <Style Selector="TextBlock.h1">
+      <Setter Property="Foreground" Value="#212121"/>
+      <Setter Property="FontSize" Value="20"/>
+      <Setter Property="FontWeight" Value="Medium"/>
+    </Style>
+
+    <Style Selector="TextBlock.h2">
+      <Setter Property="Foreground" Value="#727272"/>
+      <Setter Property="FontSize" Value="13"/>
+    </Style>
+
+    <StyleInclude Source="resm:ControlCatalog.SideBar.xaml"/>
+  </Application.Styles>
+</Application>

+ 13 - 0
samples/ControlCatalog/App.xaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog
+{
+    public class App : Application
+    {
+        public override void Initialize()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

BIN
samples/ControlCatalog/Assets/Fonts/SourceSansPro-Bold.ttf


BIN
samples/ControlCatalog/Assets/Fonts/SourceSansPro-BoldItalic.ttf


BIN
samples/ControlCatalog/Assets/Fonts/SourceSansPro-Italic.ttf


BIN
samples/ControlCatalog/Assets/Fonts/SourceSansPro-Regular.ttf


BIN
samples/ControlCatalog/Assets/delicate-arch-896885_640.jpg


BIN
samples/ControlCatalog/Assets/github_icon.png


BIN
samples/ControlCatalog/Assets/hirsch-899118_640.jpg


BIN
samples/ControlCatalog/Assets/maple-leaf-888807_640.jpg


BIN
samples/ControlCatalog/Assets/test_icon.ico


+ 21 - 0
samples/ControlCatalog/ControlCatalog.csproj

@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Avalonia.Desktop" Version="0.6.2-build6191-beta" />
+    <EmbeddedResource Include="**/*.xaml" />
+    <EmbeddedResource Include="**/*.png" />
+    <EmbeddedResource Include="**/*.jpg" />
+    <EmbeddedResource Include="**/*.ico" />
+
+
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Avalonia.Native\Avalonia.Native.csproj" />
+  </ItemGroup>
+</Project>

+ 33 - 0
samples/ControlCatalog/DecoratedWindow.xaml

@@ -0,0 +1,33 @@
+<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
+        Title="Avalonia Control Gallery"
+        Icon="resm:ControlCatalog.Assets.test_icon.ico"
+        xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False">
+    <Grid RowDefinitions="5,*,5" ColumnDefinitions="5,*,5">
+        <DockPanel  Grid.Column="1"  Grid.Row="1" >
+            <Grid Name="TitleBar" Background="LightBlue" DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto">
+                <TextBlock VerticalAlignment="Center" Margin="5,0,0,0">Title</TextBlock>
+                <StackPanel Grid.Column="2" Orientation="Horizontal">
+                    <StackPanel.Styles>
+                        <Style Selector="Button">
+                            <Setter Property="Margin" Value="2"/>
+                        </Style>
+                    </StackPanel.Styles>
+                    <Button Name="MinimizeButton">_</Button>
+                    <Button Name="MaximizeButton">[ ]</Button>
+                    <Button Name="CloseButton">X</Button>
+                </StackPanel>
+            </Grid>
+            <Border Background="White" Margin="5">
+                <TextBlock>Hello world!</TextBlock>
+            </Border>
+        </DockPanel>
+        <Border Name="TopLeft" Background="Red"/>
+        <Border Name="TopRight" Background="Red" Grid.Column="2" />
+        <Border Name="BottomLeft" Background="Red" Grid.Row="2" />
+        <Border Name="BottomRight" Background="Red"  Grid.Row="2" Grid.Column="2"/>
+        <Border Name="Top" Background="Blue" Grid.Column="1" />
+        <Border Name="Right" Background="Blue" Grid.Row="1"  Grid.Column="2" />
+        <Border Name="Bottom" Background="Blue" Grid.Row="2" Grid.Column="1"  />
+        <Border Name="Left" Background="Blue"  Grid.Row="1" />
+    </Grid>
+</Window>

+ 53 - 0
samples/ControlCatalog/DecoratedWindow.xaml.cs

@@ -0,0 +1,53 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using System;
+using Avalonia.Input;
+
+namespace ControlCatalog
+{
+    public class DecoratedWindow : Window
+    {
+        public DecoratedWindow()
+        {
+            this.InitializeComponent();
+            this.AttachDevTools();
+        }
+
+        void SetupSide(string name, StandardCursorType cursor, WindowEdge edge)
+        {
+            var ctl = this.FindControl<Control>(name);
+            ctl.Cursor = new Cursor(cursor);
+            ctl.PointerPressed += delegate
+            {
+                PlatformImpl?.BeginResizeDrag(edge);
+            };
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+            this.FindControl<Control>("TitleBar").PointerPressed += delegate
+            {
+                PlatformImpl?.BeginMoveDrag();
+            };
+            SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West);
+            SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East);
+            SetupSide("Top", StandardCursorType.TopSide, WindowEdge.North);
+            SetupSide("Bottom", StandardCursorType.BottomSize, WindowEdge.South);
+            SetupSide("TopLeft", StandardCursorType.TopLeftCorner, WindowEdge.NorthWest);
+            SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast);
+            SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest);
+            SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast);
+            this.FindControl<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; };
+            this.FindControl<Button>("MaximizeButton").Click += delegate
+            {
+                WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
+            };
+            this.FindControl<Button>("CloseButton").Click += delegate
+            {
+                Close();
+            };
+        }
+    }
+}

+ 32 - 0
samples/ControlCatalog/MainView.xaml

@@ -0,0 +1,32 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+        xmlns:pages="clr-namespace:ControlCatalog.Pages"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <TabControl Classes="sidebar" Name="Sidebar">
+    <TabControl.PageTransition>
+      <CrossFade Duration="0.25"/>
+    </TabControl.PageTransition>
+    <TabItem Header="AutoCompleteBox"><pages:AutoCompleteBoxPage/></TabItem>
+    <TabItem Header="Border"><pages:BorderPage/></TabItem>
+    <TabItem Header="Button"><pages:ButtonPage/></TabItem>
+    <TabItem Header="ButtonSpinner"><pages:ButtonSpinnerPage/></TabItem>
+    <TabItem Header="Calendar"><pages:CalendarPage/></TabItem>
+    <TabItem Header="Canvas"><pages:CanvasPage/></TabItem>
+    <TabItem Header="Carousel"><pages:CarouselPage/></TabItem>
+    <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>
+    <TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
+    <TabItem Header="ListBox"><pages:ListBoxPage/></TabItem>
+    <TabItem Header="Menu"><pages:MenuPage/></TabItem>
+    <TabItem Header="ProgressBar"><pages:ProgressBarPage/></TabItem>
+    <TabItem Header="RadioButton"><pages:RadioButtonPage/></TabItem>
+    <TabItem Header="Slider"><pages:SliderPage/></TabItem>
+    <TabItem Header="TextBox"><pages:TextBoxPage/></TabItem>
+    <TabItem Header="ToolTip"><pages:ToolTipPage/></TabItem>
+    <TabItem Header="TreeView"><pages:TreeViewPage/></TabItem>
+  </TabControl>
+</UserControl>

+ 37 - 0
samples/ControlCatalog/MainView.xaml.cs

@@ -0,0 +1,37 @@
+using System.Collections;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Platform;
+using ControlCatalog.Pages;
+
+namespace ControlCatalog
+{
+    public class MainView : UserControl
+    {
+        public MainView()
+        {
+            this.InitializeComponent();
+            if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsDesktop)
+            {
+                IList tabItems = ((IList)this.FindControl<TabControl>("Sidebar").Items);
+                tabItems.Add(new TabItem()
+                {
+                    Header = "Dialogs",
+                    Content = new DialogsPage()
+                });
+                tabItems.Add(new TabItem()
+                {
+                    Header = "Screens",
+                    Content = new ScreenPage()
+                });
+
+            }
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 6 - 0
samples/ControlCatalog/MainWindow.xaml

@@ -0,0 +1,6 @@
+<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
+        Title="Avalonia Control Gallery"
+        Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog"
+        xmlns:local="clr-namespace:ControlCatalog">
+    <local:MainView/>
+</Window>

+ 28 - 0
samples/ControlCatalog/MainWindow.xaml.cs

@@ -0,0 +1,28 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using System;
+
+namespace ControlCatalog
+{
+    public class MainWindow : Window
+    {
+        public MainWindow()
+        {
+            this.InitializeComponent();
+            this.AttachDevTools();
+            //Renderer.DrawFps = true;
+            //Renderer.DrawDirtyRects = Renderer.DrawFps = true;
+        }
+
+        private void InitializeComponent()
+        {
+            // TODO: iOS does not support dynamically loading assemblies
+            // so we must refer to this resource DLL statically. For
+            // now I am doing that here. But we need a better solution!!
+            var theme = new Avalonia.Themes.Default.DefaultTheme();
+            theme.TryGetResource("Button", out _);
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 59 - 0
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@@ -0,0 +1,59 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">AutoCompleteBox</TextBlock>
+    <TextBlock Classes="h2">A control into which the user can input text</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="8">
+      <StackPanel Orientation="Vertical">
+        <TextBlock Text="MinimumPrefixLength: 1"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         MinimumPrefixLength="1"/>
+        <TextBlock Text="MinimumPrefixLength: 3"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         MinimumPrefixLength="3"/>
+        <TextBlock Text="MinimumPopulateDelay: 1 Second"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         MinimumPopulateDelay="1"/>
+        <TextBlock Text="MaxDropDownHeight: 60"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         MaxDropDownHeight="60"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         Watermark="Watermark"/>
+        <TextBlock Text="Disabled"/>
+        <AutoCompleteBox Width="200"
+                         IsEnabled="False"/>
+      </StackPanel>
+      
+
+      <StackPanel Orientation="Vertical">
+        
+        <TextBlock Text="ValueMemeberSelector"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         ValueMemberSelector="Capital"/>
+        <TextBlock Text="ValueMemberBinding"/>
+        <AutoCompleteBox Width="200"
+                         Margin="0,0,0,8"
+                         ValueMemberBinding="{Binding Capital}"/>
+        <TextBlock Text="Multi-Binding"/>
+        <AutoCompleteBox Name="MultiBindingBox"
+                         Width="200"
+                         Margin="0,0,0,8"
+                         FilterMode="Contains"/>
+        <TextBlock Text="Async Populate"/>
+        <AutoCompleteBox Name="AsyncBox"
+                         Width="200"
+                         Margin="0,0,0,8"
+                         FilterMode="None"/>
+      </StackPanel>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 145 - 0
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@@ -0,0 +1,145 @@
+using Avalonia.Controls;
+using Avalonia.LogicalTree;
+using Avalonia.Markup;
+using Avalonia.Markup.Xaml;
+using Avalonia.Markup.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Data.Converters;
+using Avalonia.Data;
+
+namespace ControlCatalog.Pages
+{
+    public class AutoCompleteBoxPage : UserControl
+    {
+        public class StateData
+        {
+            public string Name { get; private set; }
+            public string Abbreviation { get; private set; }
+            public string Capital { get; private set; }
+
+            public StateData(string name, string abbreviatoin, string capital)
+            {
+                Name = name;
+                Abbreviation = abbreviatoin;
+                Capital = capital;
+            }
+
+            public override string ToString()
+            {
+                return Name;
+            }
+        }
+
+        private StateData[] BuildAllStates()
+        {
+            return new StateData[]
+            {
+                new StateData("Alabama","AL","Montgomery"),
+                new StateData("Alaska","AK","Juneau"),
+                new StateData("Arizona","AZ","Phoenix"),
+                new StateData("Arkansas","AR","Little Rock"),
+                new StateData("California","CA","Sacramento"),
+                new StateData("Colorado","CO","Denver"),
+                new StateData("Connecticut","CT","Hartford"),
+                new StateData("Delaware","DE","Dover"),
+                new StateData("Florida","FL","Tallahassee"),
+                new StateData("Georgia","GA","Atlanta"),
+                new StateData("Hawaii","HI","Honolulu"),
+                new StateData("Idaho","ID","Boise"),
+                new StateData("Illinois","IL","Springfield"),
+                new StateData("Indiana","IN","Indianapolis"),
+                new StateData("Iowa","IA","Des Moines"),
+                new StateData("Kansas","KS","Topeka"),
+                new StateData("Kentucky","KY","Frankfort"),
+                new StateData("Louisiana","LA","Baton Rouge"),
+                new StateData("Maine","ME","Augusta"),
+                new StateData("Maryland","MD","Annapolis"),
+                new StateData("Massachusetts","MA","Boston"),
+                new StateData("Michigan","MI","Lansing"),
+                new StateData("Minnesota","MN","St. Paul"),
+                new StateData("Mississippi","MS","Jackson"),
+                new StateData("Missouri","MO","Jefferson City"),
+                new StateData("Montana","MT","Helena"),
+                new StateData("Nebraska","NE","Lincoln"),
+                new StateData("Nevada","NV","Carson City"),
+                new StateData("New Hampshire","NH","Concord"),
+                new StateData("New Jersey","NJ","Trenton"),
+                new StateData("New Mexico","NM","Santa Fe"),
+                new StateData("New York","NY","Albany"),
+                new StateData("North Carolina","NC","Raleigh"),
+                new StateData("North Dakota","ND","Bismarck"),
+                new StateData("Ohio","OH","Columbus"),
+                new StateData("Oklahoma","OK","Oklahoma City"),
+                new StateData("Oregon","OR","Salem"),
+                new StateData("Pennsylvania","PA","Harrisburg"),
+                new StateData("Rhode Island","RI","Providence"),
+                new StateData("South Carolina","SC","Columbia"),
+                new StateData("South Dakota","SD","Pierre"),
+                new StateData("Tennessee","TN","Nashville"),
+                new StateData("Texas","TX","Austin"),
+                new StateData("Utah","UT","Salt Lake City"),
+                new StateData("Vermont","VT","Montpelier"),
+                new StateData("Virginia","VA","Richmond"),
+                new StateData("Washington","WA","Olympia"),
+                new StateData("West Virginia","WV","Charleston"),
+                new StateData("Wisconsin","WI","Madison"),
+                new StateData("Wyoming","WY","Cheyenne"),
+            };
+        }
+        public StateData[] States { get; private set; }
+        
+        public AutoCompleteBoxPage()
+        {
+            this.InitializeComponent();
+
+            States = BuildAllStates();
+
+            foreach (AutoCompleteBox box in GetAllAutoCompleteBox())
+            {
+                box.Items = States;
+            }
+
+            var converter = new FuncMultiValueConverter<string, string>(parts =>
+            {
+                return String.Format("{0} ({1})", parts.ToArray());
+            });
+            var binding = new MultiBinding { Converter = converter };
+            binding.Bindings.Add(new Binding("Name"));
+            binding.Bindings.Add(new Binding("Abbreviation"));
+
+            var multibindingBox = this.FindControl<AutoCompleteBox>("MultiBindingBox");
+            multibindingBox.ValueMemberBinding = binding;
+
+            var asyncBox = this.FindControl<AutoCompleteBox>("AsyncBox");
+            asyncBox.AsyncPopulator = PopulateAsync;
+        }
+        private IEnumerable<AutoCompleteBox> GetAllAutoCompleteBox()
+        {
+            return
+                this.GetLogicalDescendants()
+                    .OfType<AutoCompleteBox>();
+        }
+
+        private bool StringContains(string str, string query)
+        {
+            return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
+        }
+        private async Task<IEnumerable<object>> PopulateAsync(string searchText, CancellationToken cancellationToken)
+        {
+            await Task.Delay(TimeSpan.FromSeconds(1.5), cancellationToken);
+
+            return
+                States.Where(data => StringContains(data.Name, searchText) || StringContains(data.Capital, searchText))
+                      .ToList();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 32 - 0
samples/ControlCatalog/Pages/BorderPage.xaml

@@ -0,0 +1,32 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Border</TextBlock>
+    <TextBlock Classes="h2">A control which decorates a child with a border and background</TextBlock>
+
+    <StackPanel Orientation="Vertical"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <Border BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="2" Padding="16">
+        <TextBlock>Border</TextBlock>
+      </Border>
+      <Border Background="{DynamicResource ThemeAccentBrush2}" 
+              BorderBrush="{DynamicResource ThemeAccentBrush}" 
+              BorderThickness="4" 
+              Padding="16">
+        <TextBlock>Border and Background</TextBlock>
+      </Border>
+      <Border BorderBrush="{DynamicResource ThemeAccentBrush}"
+              BorderThickness="4" 
+              CornerRadius="8"
+              Padding="16">
+        <TextBlock>Rounded Corners</TextBlock>
+      </Border>
+      <Border Background="{DynamicResource ThemeAccentBrush2}"
+              CornerRadius="8"
+              Padding="16">
+        <TextBlock>Rounded Corners</TextBlock>
+      </Border>
+    </StackPanel>    
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/BorderPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class BorderPage : UserControl
+    {
+        public BorderPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 36 - 0
samples/ControlCatalog/Pages/ButtonPage.xaml

@@ -0,0 +1,36 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Button</TextBlock>
+    <TextBlock Classes="h2">A button control</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <StackPanel Orientation="Vertical" Spacing="8" Width="150">
+        <Button>Button</Button>
+        <Button Foreground="White">Foreground</Button>
+        <Button Background="{DynamicResource ThemeAccentBrush}">Background</Button>
+        <Button IsEnabled="False">Disabled</Button>
+        <Button Content="Re-themed">
+          <Button.Styles>
+            <Style>
+              <Style.Resources>
+                <SolidColorBrush x:Key="ThemeBorderMidBrush">Red</SolidColorBrush>
+                <SolidColorBrush x:Key="ThemeControlDarkBrush">DarkRed</SolidColorBrush>
+              </Style.Resources>
+            </Style>
+          </Button.Styles>          
+        </Button>
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical" Spacing="8" Width="150">
+        <Button BorderThickness="0">No Border</Button>
+        <Button BorderBrush="{DynamicResource ThemeAccentBrush}">Border Color</Button>
+        <Button BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="4">Thick Border</Button>
+        <Button BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="4" IsEnabled="False">Disabled</Button>
+      </StackPanel>
+    </StackPanel>    
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/ButtonPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ButtonPage : UserControl
+    {
+        public ButtonPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 24 - 0
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml

@@ -0,0 +1,24 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">ButtonSpinner</TextBlock>
+    <TextBlock Classes="h2">The ButtonSpinner control allows you to add button spinners to any element and then respond to the Spin event to manipulate that element.</TextBlock>
+
+    <StackPanel Orientation="Vertical" Spacing="8" Width="200" Margin="0,20,0,0">
+      <CheckBox Name="allowSpinCheck" IsChecked="True">AllowSpin</CheckBox>
+      <CheckBox Name="showSpinCheck" IsChecked="True">ShowButtonSpinner</CheckBox>
+      <ButtonSpinner Spin="OnSpin" Height="30"
+                     AllowSpin="{Binding #allowSpinCheck.IsChecked}"
+                     ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
+        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
+      </ButtonSpinner>
+      <ButtonSpinner Spin="OnSpin" Height="30" ButtonSpinnerLocation="Left"
+                     AllowSpin="{Binding #allowSpinCheck.IsChecked}"
+                     ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
+        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
+      </ButtonSpinner>
+    </StackPanel>
+  </StackPanel>
+
+</UserControl>

+ 54 - 0
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs

@@ -0,0 +1,54 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ButtonSpinnerPage : UserControl
+    {
+        public ButtonSpinnerPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        private void OnSpin(object sender, SpinEventArgs e)
+        {
+            var spinner = (ButtonSpinner)sender;
+            var txtBox = (TextBlock)spinner.Content;
+
+            int value = Array.IndexOf(_mountains, txtBox.Text);
+            if (e.Direction == SpinDirection.Increase)
+                value++;
+            else
+                value--;
+
+            if (value < 0)
+                value = _mountains.Length - 1;
+            else if (value >= _mountains.Length)
+                value = 0;
+
+            txtBox.Text = _mountains[value];
+        }
+
+        private readonly string[] _mountains = new[]
+        {
+            "Everest",
+            "K2 (Mount Godwin Austen)",
+            "Kangchenjunga",
+            "Lhotse",
+            "Makalu",
+            "Cho Oyu",
+            "Dhaulagiri",
+            "Manaslu",
+            "Nanga Parbat",
+            "Annapurna"
+        };
+    }
+}

+ 47 - 0
samples/ControlCatalog/Pages/CalendarPage.xaml

@@ -0,0 +1,47 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Calendar</TextBlock>
+    <TextBlock Classes="h2">A calendar control for selecting dates</TextBlock>
+        
+    <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <StackPanel Orientation="Vertical">
+        <TextBlock Text="SelectionMode: None"/>
+        <Calendar SelectionMode="None"
+                  Margin="0,0,0,8"/>
+
+        <TextBlock Text="SelectionMode: SingleDate"/>
+        <Calendar SelectionMode="SingleDate"
+                  Margin="0,0,0,8"/>
+
+        <TextBlock Text="Disabled"/>
+        <Calendar IsEnabled="False"
+                  SelectionMode="SingleDate"/>
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical">
+        <TextBlock Text="SelectionMode: SingleRange"/>
+        <Calendar SelectionMode="SingleRange"
+                  Margin="0,0,0,8"/>
+
+        <TextBlock Text="SelectionMode: MultipleRange"/>
+        <Calendar SelectionMode="MultipleRange"/>
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical">
+        <TextBlock Text="DisplayDates"/>
+        <Calendar Name="DisplayDatesCalendar"
+                  SelectionMode="SingleDate"
+                  Margin="0,0,0,8"/>
+
+        <TextBlock Text="BlackoutDates"/>
+        <Calendar Name="BlackoutDatesCalendar"
+                  SelectionMode="SingleDate" />
+      </StackPanel>
+      
+    </StackPanel> 
+  </StackPanel>
+</UserControl>

+ 28 - 0
samples/ControlCatalog/Pages/CalendarPage.xaml.cs

@@ -0,0 +1,28 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using System;
+
+namespace ControlCatalog.Pages
+{
+    public class CalendarPage : UserControl
+    {
+        public CalendarPage()
+        {
+            this.InitializeComponent();
+
+            var today = DateTime.Today; 
+            var cal1 = this.FindControl<Calendar>("DisplayDatesCalendar");
+            cal1.DisplayDateStart = today.AddDays(-25);
+            cal1.DisplayDateEnd = today.AddDays(25);
+
+            var cal2 = this.FindControl<Calendar>("BlackoutDatesCalendar");
+            cal2.BlackoutDates.AddDatesInPast();
+            cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6)));
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 35 - 0
samples/ControlCatalog/Pages/CanvasPage.xaml

@@ -0,0 +1,35 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Canvas</TextBlock>
+    <TextBlock Classes="h2">A panel which lays out its children by explicit coordinates</TextBlock>
+    <Canvas Background="Yellow" Width="300" Height="400">
+      <Rectangle Fill="Blue" Width="63" Height="41" Canvas.Left="40" Canvas.Top="31">
+        <Rectangle.OpacityMask>
+          <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
+            <LinearGradientBrush.GradientStops>
+              <GradientStop Offset="0" Color="Black"/>
+              <GradientStop Offset="1" Color="Transparent"/>
+            </LinearGradientBrush.GradientStops>
+          </LinearGradientBrush>
+        </Rectangle.OpacityMask>     
+      </Rectangle>
+      <Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="88" Canvas.Top="100"/>
+      <Path Fill="Orange" Data="M 0,0 c 0,0 50,0 50,-50 c 0,0 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
+      <Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">
+        <Path.Data>
+          <PathGeometry>
+            <PathFigure StartPoint="0,0" IsClosed="True">
+              <QuadraticBezierSegment Point1="50,0" Point2="50,-50" />
+              <QuadraticBezierSegment Point1="100,-50" Point2="100,0" />
+              <LineSegment Point="50,0" />
+              <LineSegment Point="50,50" />
+            </PathFigure>
+          </PathGeometry>
+        </Path.Data>
+      </Path>
+      <Line StartPoint="120,185" EndPoint="30,115" Stroke="Red" StrokeThickness="2"/>
+      <Polygon Points="75,0 120,120 0,45 150,45 30,120" Stroke="DarkBlue" StrokeThickness="1" Fill="Violet" Canvas.Left="150" Canvas.Top="31"/>
+      <Polyline Points="0,0 65,0 78,-26 91,39 104,-39 117,13 130,0 195,0" Stroke="Brown" Canvas.Left="30" Canvas.Top="350"/>
+    </Canvas>
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/CanvasPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class CanvasPage : UserControl
+    {
+        public CanvasPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 41 - 0
samples/ControlCatalog/Pages/CarouselPage.xaml

@@ -0,0 +1,41 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Carousel</TextBlock>
+    <TextBlock Classes="h2">An items control that displays its items as pages that fill the control.</TextBlock>
+
+    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 16 0 0" Spacing="8">
+      <Button Name="left" VerticalAlignment="Center" Padding="20">
+        <Path Data="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" Fill="Black"/>
+      </Button>
+      <Carousel Name="carousel">
+        <Carousel.PageTransition>
+          <PageSlide Duration="0.25" Orientation="Vertical" />
+        </Carousel.PageTransition>
+        <Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"/>
+        <Image Source="resm:ControlCatalog.Assets.hirsch-899118_640.jpg"/>
+        <Image Source="resm:ControlCatalog.Assets.maple-leaf-888807_640.jpg"/>
+      </Carousel>
+      <Button Name="right" VerticalAlignment="Center" Padding="20">
+        <Path Data="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" Fill="Black"/>
+      </Button>
+    </StackPanel>
+
+    <StackPanel Orientation="Horizontal" Spacing="4">
+      <TextBlock VerticalAlignment="Center">Transition</TextBlock>
+      <DropDown Name="transition" SelectedIndex="1" VerticalAlignment="Center">
+        <DropDownItem>None</DropDownItem>
+        <DropDownItem>Slide</DropDownItem>
+        <DropDownItem>Crossfade</DropDownItem>
+      </DropDown>
+    </StackPanel>
+
+    <StackPanel Orientation="Horizontal" Spacing="4">
+      <TextBlock VerticalAlignment="Center">Orientation</TextBlock>
+      <DropDown Name="orientation" SelectedIndex="1" VerticalAlignment="Center">
+        <DropDownItem>Horizontal</DropDownItem>
+        <DropDownItem>Vertical</DropDownItem>
+      </DropDown>
+    </StackPanel>
+    
+  </StackPanel>
+</UserControl>

+ 51 - 0
samples/ControlCatalog/Pages/CarouselPage.xaml.cs

@@ -0,0 +1,51 @@
+using System;
+using Avalonia.Animation;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class CarouselPage : UserControl
+    {
+        private Carousel _carousel;
+        private Button _left;
+        private Button _right;
+        private DropDown _transition;
+        private DropDown _orientation;
+
+        public CarouselPage()
+        {
+            this.InitializeComponent();
+            _left.Click += (s, e) => _carousel.Previous();
+            _right.Click += (s, e) => _carousel.Next();
+            _transition.SelectionChanged += TransitionChanged;
+            _orientation.SelectionChanged += TransitionChanged;
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+            _carousel = this.FindControl<Carousel>("carousel");
+            _left = this.FindControl<Button>("left");
+            _right = this.FindControl<Button>("right");
+            _transition = this.FindControl<DropDown>("transition");
+            _orientation = this.FindControl<DropDown>("orientation");
+        }
+
+        private void TransitionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            switch (_transition.SelectedIndex)
+            {
+                case 0:
+                    _carousel.PageTransition = null;
+                    break;
+                case 1:
+                    _carousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), _orientation.SelectedIndex == 0 ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical);
+                    break;
+                case 2:
+                    _carousel.PageTransition = new CrossFade(TimeSpan.FromSeconds(0.25));
+                    break;
+            }
+        }
+    }
+}

+ 28 - 0
samples/ControlCatalog/Pages/CheckBoxPage.xaml

@@ -0,0 +1,28 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">CheckBox</TextBlock>
+    <TextBlock Classes="h2">A check box control</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <StackPanel Orientation="Vertical"
+                  Spacing="16">
+        <CheckBox>Unchecked</CheckBox>
+        <CheckBox IsChecked="True">Checked</CheckBox>
+        <CheckBox IsChecked="{x:Null}">Indeterminate</CheckBox>
+        <CheckBox IsChecked="True" IsEnabled="False">Disabled</CheckBox>
+      </StackPanel>
+      <StackPanel Orientation="Vertical"
+                  HorizontalAlignment="Center"
+                  Spacing="16">
+        <CheckBox IsChecked="False" IsThreeState="True">Three State: Unchecked</CheckBox>
+        <CheckBox IsChecked="True" IsThreeState="True">Three State: Checked</CheckBox>
+        <CheckBox IsChecked="{x:Null}" IsThreeState="True">Three State: Indeterminate</CheckBox>
+        <CheckBox IsChecked="{x:Null}" IsThreeState="True" IsEnabled="False">Three State: Disabled</CheckBox>
+      </StackPanel>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/CheckBoxPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class CheckBoxPage : UserControl
+    {
+        public CheckBoxPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 36 - 0
samples/ControlCatalog/Pages/ContextMenuPage.xaml

@@ -0,0 +1,36 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+    <StackPanel Orientation="Vertical" Spacing="4">
+        <TextBlock Classes="h1">Context Menu</TextBlock>
+        <TextBlock Classes="h2">A right click menu that can be applied to any control.</TextBlock>
+
+        <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="16">
+            <Border Background="{DynamicResource ThemeAccentBrush}"
+              Padding="48,48,48,48">
+                <Border.ContextMenu>
+                    <ContextMenu>
+                        <MenuItem Header="Standard _Menu Item"/>
+                        <Separator/>
+                        <MenuItem Header="Menu with _Submenu">
+                            <MenuItem Header="Submenu _1"/>
+                            <MenuItem Header="Submenu _2"/>
+                        </MenuItem>
+                        <MenuItem Header="Menu Item with _Icon">
+                            <MenuItem.Icon>
+                                <Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
+                            </MenuItem.Icon>
+                        </MenuItem>
+                        <MenuItem Header="Menu Item with _Checkbox">
+                            <MenuItem.Icon>
+                                <CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
+                            </MenuItem.Icon>
+                        </MenuItem>
+                    </ContextMenu>
+                </Border.ContextMenu>
+                <TextBlock Text="Right Click Here"/>
+            </Border>
+        </StackPanel>
+    </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ContextMenuPage : UserControl
+    {
+        public ContextMenuPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 46 - 0
samples/ControlCatalog/Pages/DatePickerPage.xaml

@@ -0,0 +1,46 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">DatePicker</TextBlock>
+    <TextBlock Classes="h2">A control for selecting dates with a calendar drop-down</TextBlock>
+        
+    <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <StackPanel Orientation="Vertical"
+                  Width="200">
+        <TextBlock Text="SelectedDateFormat: Short"/>
+        <DatePicker Name="DatePicker1"
+                    SelectedDateFormat="Short"
+                    Margin="0,0,0,8"/>
+
+        <TextBlock Text="SelectedDateFormat: Long"/>
+        <DatePicker Name="DatePicker2"
+                    SelectedDateFormat="Long"
+                    Margin="0,0,0,8"/>
+
+        <TextBlock Text="SelectedDateFormat: Custom"/>
+        <DatePicker Name="DatePicker3"
+                    SelectedDateFormat="Custom"
+                    CustomDateFormatString="ddd, MMM d"
+                    Margin="0,0,0,8"/>
+
+        <TextBlock Text="Blackout Dates"/>
+        <DatePicker Name="DatePicker4"
+                    Margin="0,0,0,8"/>
+
+        <DatePicker Margin="0,0,0,8"
+                    Watermark="Watermark"/>
+        <DatePicker Margin="0,0,0,8"
+                    Name="DatePicker5"
+                    Watermark="Floating Watermark"
+                    UseFloatingWatermark="True"/>
+                
+        <TextBlock Text="Disabled"/>
+        <DatePicker IsEnabled="False"/>
+      </StackPanel>
+
+    </StackPanel> 
+  </StackPanel>
+</UserControl>

+ 36 - 0
samples/ControlCatalog/Pages/DatePickerPage.xaml.cs

@@ -0,0 +1,36 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using System;
+
+namespace ControlCatalog.Pages
+{
+    public class DatePickerPage : UserControl
+    {
+        public DatePickerPage()
+        {
+            InitializeComponent();
+            
+            var dp1 = this.FindControl<DatePicker>("DatePicker1");
+            var dp2 = this.FindControl<DatePicker>("DatePicker2");
+            var dp3 = this.FindControl<DatePicker>("DatePicker3");
+            var dp4 = this.FindControl<DatePicker>("DatePicker4");
+            var dp5 = this.FindControl<DatePicker>("DatePicker5");
+
+            dp1.SelectedDate = DateTime.Today;
+            dp2.SelectedDate = DateTime.Today.AddDays(10);
+            dp3.SelectedDate = DateTime.Today.AddDays(20);
+            dp5.SelectedDate = DateTime.Today;
+
+            dp4.TemplateApplied += (s, e) =>
+            {
+                dp4.BlackoutDates.AddDatesInPast();
+            };
+            
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 12 - 0
samples/ControlCatalog/Pages/DialogsPage.xaml

@@ -0,0 +1,12 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4" Margin="4">
+      <Button Name="OpenFile">Open File</Button>
+      <Button Name="SaveFile">Save File</Button>
+      <Button Name="SelectFolder">Select Folder</Button>
+      <StackPanel Orientation="Horizontal">
+          <CheckBox Name="IsModal" IsChecked="True"/>
+          <TextBlock>Modal to window</TextBlock>
+      </StackPanel>
+      <Button Name="DecoratedWindow">Decorated window</Button>
+  </StackPanel>
+</UserControl>

+ 46 - 0
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -0,0 +1,46 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+#pragma warning disable 4014
+
+namespace ControlCatalog.Pages
+{
+    public class DialogsPage : UserControl
+    {
+        public DialogsPage()
+        {
+            this.InitializeComponent();
+            this.FindControl<Button>("OpenFile").Click += delegate
+            {
+                new OpenFileDialog()
+                {
+                    Title = "Open file"
+                }.ShowAsync(GetWindow());
+            };
+            this.FindControl<Button>("SaveFile").Click += delegate
+            {
+                new SaveFileDialog()
+                {
+                    Title = "Save file"
+                }.ShowAsync(GetWindow());
+            };
+            this.FindControl<Button>("SelectFolder").Click += delegate
+            {
+                new OpenFolderDialog()
+                {
+                    Title = "Select folder"
+                }.ShowAsync(GetWindow());
+            };
+            this.FindControl<Button>("DecoratedWindow").Click += delegate
+            {
+                new DecoratedWindow().Show();
+            };
+        }
+
+        Window GetWindow() => this.FindControl<CheckBox>("IsModal").IsChecked.Value ? (Window)this.VisualRoot : null;
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

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

@@ -0,0 +1,19 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+    <StackPanel Orientation="Vertical" Spacing="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"
+                Spacing="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");
+        }
+    }
+}

+ 31 - 0
samples/ControlCatalog/Pages/DropDownPage.xaml

@@ -0,0 +1,31 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">DropDown</TextBlock>
+    <TextBlock Classes="h2">A drop-down list.</TextBlock>
+
+    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 16 0 0" Spacing="8">
+      <DropDown SelectedIndex="0">
+        <DropDownItem>Inline Items</DropDownItem>
+        <DropDownItem>Inline Item 2</DropDownItem>
+        <DropDownItem>Inline Item 3</DropDownItem>
+        <DropDownItem>Inline Item 4</DropDownItem>
+      </DropDown>
+
+      <DropDown SelectedIndex="0">
+        <DropDownItem>
+          <Panel>
+            <Rectangle Fill="{DynamicResource ThemeAccentBrush}"/>
+            <TextBlock Margin="8">Control Items</TextBlock>
+          </Panel>
+        </DropDownItem>
+        <DropDownItem>
+          <Ellipse Width="50" Height="50" Fill="Yellow"/>
+        </DropDownItem>
+        <DropDownItem>
+          <TextBox Text="TextBox"/>
+        </DropDownItem>
+      </DropDown>
+    </StackPanel>
+
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/DropDownPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class DropDownPage : UserControl
+    {
+        public DropDownPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 32 - 0
samples/ControlCatalog/Pages/ExpanderPage.xaml

@@ -0,0 +1,32 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Expander</TextBlock>
+    <TextBlock Classes="h2">Expands to show nested content</TextBlock>
+
+    <StackPanel Orientation="Vertical"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <Expander Header="Expand Up" ExpandDirection="Up">
+        <StackPanel>
+          <TextBlock>Expanded content</TextBlock>
+        </StackPanel>
+      </Expander>
+      <Expander Header="Expand Down" ExpandDirection="Down">
+        <StackPanel>
+          <TextBlock>Expanded content</TextBlock>
+        </StackPanel>
+      </Expander>
+      <Expander Header="Expand Left" ExpandDirection="Left">
+        <StackPanel>
+          <TextBlock>Expanded content</TextBlock>
+        </StackPanel>
+      </Expander>
+      <Expander Header="Expand Right" ExpandDirection="Right">
+        <StackPanel>
+          <TextBlock>Expanded content</TextBlock>
+        </StackPanel>
+      </Expander>
+    </StackPanel>    
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/ExpanderPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ExpanderPage : UserControl
+    {
+        public ExpanderPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 43 - 0
samples/ControlCatalog/Pages/ImagePage.xaml

@@ -0,0 +1,43 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Image</TextBlock>
+    <TextBlock Classes="h2">Displays an image</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <StackPanel Orientation="Vertical">
+        <TextBlock>No Stretch</TextBlock>
+        <Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
+               Width="100" Height="200"
+               Stretch="None"/>
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical">
+        <TextBlock>Fill</TextBlock>
+        <Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
+               Width="100" Height="200"
+               Stretch="Fill"/>
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical">
+        <TextBlock>Uniform</TextBlock>
+        <Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
+                Width="100" Height="200"
+                Stretch="Uniform"/>
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical">
+        <TextBlock>UniformToFill</TextBlock>
+        <Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
+               Width="100" Height="200"
+               Stretch="UniformToFill"/>
+      </StackPanel>
+    </StackPanel>
+    <StackPanel Orientation="Vertical">
+      <TextBlock>Window Icon as an Image</TextBlock>
+      <Image Name="Icon" Width="100" Height="200" Stretch="None" />
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 41 - 0
samples/ControlCatalog/Pages/ImagePage.xaml.cs

@@ -0,0 +1,41 @@
+using System.IO;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media.Imaging;
+
+namespace ControlCatalog.Pages
+{
+    public class ImagePage : UserControl
+    {
+        private Image iconImage;
+        public ImagePage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+            iconImage = this.Get<Image>("Icon");
+        }
+
+        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+        {
+            base.OnAttachedToVisualTree(e);
+            if (iconImage.Source == null)
+            {
+                var windowRoot = e.Root as Window;
+                if (windowRoot != null)
+                {
+                    using (var stream = new MemoryStream())
+                    {
+                        windowRoot.Icon.Save(stream);
+                        stream.Seek(0, SeekOrigin.Begin);
+                        iconImage.Source = new Bitmap(stream);
+                    }
+                }
+            }
+        }
+    }
+}

+ 26 - 0
samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml

@@ -0,0 +1,26 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <DockPanel>
+    <Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto" Margin="16" DockPanel.Dock="Top">
+      <TextBlock Grid.Column="0" Grid.Row="0">Rotation</TextBlock>
+      <Slider Name="rotation" Maximum="360" Grid.Column="1" Grid.Row="0"/>
+    </Grid>
+
+    <Grid ColumnDefinitions="24,Auto,24" 
+          RowDefinitions="24,Auto,24"
+          HorizontalAlignment="Center"
+          VerticalAlignment="Center">
+      <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="1" Grid.Row="0"/>
+      <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="0" Grid.Row="1"/>
+      <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="2" Grid.Row="1"/>
+      <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="1" Grid.Row="2"/>
+
+      <LayoutTransformControl Name="layoutTransform" Grid.Column="1" Grid.Row="1">
+        <LayoutTransformControl.LayoutTransform>
+          <RotateTransform Angle="{Binding #rotation.Value}"/>
+        </LayoutTransformControl.LayoutTransform>
+        <TextBlock>Layout Transform</TextBlock>
+      </LayoutTransformControl>
+    </Grid>
+  </DockPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class LayoutTransformControlPage : UserControl
+    {
+        public LayoutTransformControlPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 13 - 0
samples/ControlCatalog/Pages/ListBoxPage.xaml

@@ -0,0 +1,13 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">ListBox</TextBlock>
+    <TextBlock Classes="h2">Hosts a collection of ListBoxItem.</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="16">
+      <ListBox Items="{Binding}" Width="250" Height="350"></ListBox>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 25 - 0
samples/ControlCatalog/Pages/ListBoxPage.xaml.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ListBoxPage : UserControl
+    {
+        public ListBoxPage()
+        {
+            this.InitializeComponent();
+            DataContext = Enumerable.Range(1, 10).Select(i => $"Item {i}" )
+                .ToArray();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+    }
+}

+ 35 - 0
samples/ControlCatalog/Pages/MenuPage.xaml

@@ -0,0 +1,35 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Menu</TextBlock>
+    <TextBlock Classes="h2">A window menu</TextBlock>
+
+        <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="16">
+            <Menu>
+                <MenuItem Header="_First">
+                    <MenuItem Header="Standard _Menu Item"/>
+                    <Separator/>
+                    <MenuItem Header="Menu with _Submenu">
+                        <MenuItem Header="Submenu _1"/>
+                        <MenuItem Header="Submenu _2"/>
+                    </MenuItem>
+                    <MenuItem Header="Menu Item with _Icon">
+                        <MenuItem.Icon>
+                            <Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
+                        </MenuItem.Icon>
+                    </MenuItem>
+                    <MenuItem Header="Menu Item with _Checkbox">
+                        <MenuItem.Icon>
+                            <CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
+                        </MenuItem.Icon>
+                    </MenuItem>
+                </MenuItem>
+                <MenuItem Header="_Second">
+                    <MenuItem Header="Second _Menu Item"/>
+                </MenuItem>
+            </Menu>
+        </StackPanel>
+    </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/MenuPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class MenuPage : UserControl
+    {
+        public MenuPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 24 - 0
samples/ControlCatalog/Pages/ProgressBarPage.xaml

@@ -0,0 +1,24 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">ProgressBar</TextBlock>
+    <TextBlock Classes="h2">A progress bar control</TextBlock>
+
+    <StackPanel>
+      <StackPanel Orientation="Horizontal"
+                  Margin="0,16,0,0"
+                  HorizontalAlignment="Center"
+                  Spacing="16">
+        <StackPanel Spacing="16">
+          <ProgressBar Value="{Binding #hprogress.Value}" />
+          <ProgressBar IsIndeterminate="True"/>
+        </StackPanel>
+        <ProgressBar Value="{Binding #vprogress.Value}" Orientation="Vertical" />
+        <ProgressBar Orientation="Vertical" IsIndeterminate="True" />
+      </StackPanel>
+      <StackPanel Margin="16">
+        <Slider Name="hprogress" Maximum="100" Value="40"/>
+        <Slider Name="vprogress" Maximum="100" Value="60"/>
+      </StackPanel>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ProgressBarPage : UserControl
+    {
+        public ProgressBarPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 40 - 0
samples/ControlCatalog/Pages/RadioButtonPage.xaml

@@ -0,0 +1,40 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">RadioButton</TextBlock>
+    <TextBlock Classes="h2">Allows the selection of a single option of many</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+                Margin="0,16,0,0"
+                HorizontalAlignment="Center"
+                Spacing="16">
+      <StackPanel Orientation="Vertical"
+                  Spacing="16">
+        <RadioButton IsChecked="True">Option 1</RadioButton>
+        <RadioButton>Option 2</RadioButton>
+        <RadioButton IsChecked="{x:Null}">Option 3</RadioButton>
+        <RadioButton IsEnabled="False">Disabled</RadioButton>
+      </StackPanel>
+      <StackPanel Orientation="Vertical"
+                  Spacing="16">
+        <RadioButton IsChecked="True" IsThreeState="True">Three States: Option 1</RadioButton>
+        <RadioButton IsChecked="False" IsThreeState="True">Three States: Option 2</RadioButton>
+        <RadioButton IsChecked="{x:Null}" IsThreeState="True">Three States: Option 3</RadioButton>
+        <RadioButton IsChecked="{x:Null}" IsThreeState="True" IsEnabled="False">Disabled</RadioButton>
+      </StackPanel>
+      <StackPanel Orientation="Vertical"
+                  Spacing="16">
+        <RadioButton GroupName="A" IsChecked="True">Group A: Option 1</RadioButton>
+        <RadioButton GroupName="A" IsEnabled="False">Group A: Disabled</RadioButton>
+        <RadioButton GroupName="B">Group B: Option 1</RadioButton>
+        <RadioButton GroupName="B" IsChecked="{x:Null}">Group B: Option 3</RadioButton>
+      </StackPanel>
+      <StackPanel Orientation="Vertical"
+                  Spacing="16">
+        <RadioButton GroupName="A" IsChecked="True">Group A: Option 2</RadioButton>
+        <RadioButton GroupName="B">Group B: Option 2</RadioButton>
+        <RadioButton GroupName="B" IsChecked="{x:Null}">Group B: Option 4</RadioButton>
+      </StackPanel>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/RadioButtonPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class RadioButtonPage : UserControl
+    {
+        public RadioButtonPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 66 - 0
samples/ControlCatalog/Pages/ScreenPage.cs

@@ -0,0 +1,66 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using Avalonia.Platform;
+
+namespace ControlCatalog.Pages
+{
+    public class ScreenPage : UserControl
+    {
+        private double _leftMost;
+
+        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+        {
+            base.OnAttachedToVisualTree(e);
+            Window w = (Window)VisualRoot;
+            w.PositionChanged += (sender, args) => InvalidateVisual();
+        }
+
+        public override void Render(DrawingContext context)
+        {
+            base.Render(context);
+            Window w = (Window)VisualRoot;
+            Screen[] screens = w.Screens.All;
+
+            Pen p = new Pen(Brushes.Black);
+            if (screens != null)
+                foreach (Screen screen in screens)
+                {
+                    if (screen.Bounds.X / 10f < _leftMost)
+                    {
+                        _leftMost = screen.Bounds.X / 10f;
+                        InvalidateVisual();
+                        return;
+                    }
+
+                    Rect boundsRect = new Rect(screen.Bounds.X / 10f + Math.Abs(_leftMost), screen.Bounds.Y / 10f, screen.Bounds.Width / 10f,
+                                      screen.Bounds.Height / 10f);
+                    Rect workingAreaRect = new Rect(screen.WorkingArea.X / 10f + Math.Abs(_leftMost), screen.WorkingArea.Y / 10f, screen.WorkingArea.Width / 10f,
+                                       screen.WorkingArea.Height / 10f);
+                    context.DrawRectangle(p, boundsRect);
+                    context.DrawRectangle(p, workingAreaRect);
+                    
+                    FormattedText text = new FormattedText()
+                    {
+                        Typeface = Typeface.Default
+                    };
+
+                    text.Text = $"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}";
+                    context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height), text);
+                    
+                    text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
+                    context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
+                    
+                    text.Text = $"Primary: {screen.Primary}";
+                    context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
+                    
+                    text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new Rect(w.Position, w.Bounds.Size)))}";
+                    context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
+                }
+
+            context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10, w.Bounds.Width / 10, w.Bounds.Height / 10));
+        }
+    }
+}

+ 21 - 0
samples/ControlCatalog/Pages/SliderPage.xaml

@@ -0,0 +1,21 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">Slider</TextBlock>
+    <TextBlock Classes="h2">A control that lets the user select from a range of values by moving a Thumb control along a Track.</TextBlock>
+
+    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 16 0 0" Spacing="16">
+      <Slider Value="0"
+              Minimum="0"
+              Maximum="100"
+              Width="300"/>
+      <Slider Value="0"
+              Minimum="0"
+              Maximum="100"
+              Orientation="Vertical"
+              IsSnapToTickEnabled="True"
+              TickFrequency="10"
+              Height="300"/>
+    </StackPanel>
+
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/SliderPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class SliderPage : UserControl
+    {
+        public SliderPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 43 - 0
samples/ControlCatalog/Pages/TextBoxPage.xaml

@@ -0,0 +1,43 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">TextBox</TextBlock>
+    <TextBlock Classes="h2">A control into which the user can input text</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="16">
+      <StackPanel Orientation="Vertical" Spacing="8">
+        <TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
+        <TextBox Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/>
+        <TextBox Width="200" Watermark="Watermark" />
+        <TextBox Width="200"
+                 Watermark="Floating Watermark"
+                 UseFloatingWatermark="True"
+                 Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
+
+        <TextBox Width="200"
+                 Watermark="Password Box"
+                 UseFloatingWatermark="True"
+                 PasswordChar="*"
+                 Text="Password" />
+        <TextBox Width="200" Text="Left aligned text" TextAlignment="Left" />
+        <TextBox Width="200" Text="Center aligned text" TextAlignment="Center" />
+        <TextBox Width="200" Text="Right aligned text" TextAlignment="Right" />
+      </StackPanel>
+
+      <StackPanel Orientation="Vertical" Spacing="8">
+        <TextBox AcceptsReturn="True" TextWrapping="Wrap" Width="200" Height="125"
+                 Text="Multiline TextBox with TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
+        <TextBox AcceptsReturn="True" Width="200" Height="125"
+                 Text="Multiline TextBox with no TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
+      </StackPanel>
+        <StackPanel Orientation="Vertical" Spacing="8">
+            <TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/>
+                <TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/>
+                <TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-Italic.ttf?assembly=ControlCatalog#Source Sans Pro"/>
+                <TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-*.ttf?assembly=ControlCatalog#Source Sans Pro"/>
+        </StackPanel>
+      </StackPanel>
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/TextBoxPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class TextBoxPage : UserControl
+    {
+        public TextBoxPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 41 - 0
samples/ControlCatalog/Pages/ToolTipPage.xaml

@@ -0,0 +1,41 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+    <StackPanel Orientation="Vertical"
+                Spacing="4">
+        <TextBlock Classes="h1">ToolTip</TextBlock>
+        <TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
+
+        <Grid RowDefinitions="Auto,Auto"
+              ColumnDefinitions="Auto,Auto"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center">
+            <Border Grid.Column="0"
+                    Grid.Row="1"
+                    Background="{DynamicResource ThemeAccentBrush}"
+                    Margin="5"
+                    Padding="50"
+                    ToolTip.Tip="This is a ToolTip">
+                <TextBlock>Hover Here</TextBlock>
+            </Border>
+            <CheckBox Grid.Column="1"
+                      Margin="5"
+                      Grid.Row="0"
+                      IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"
+                      Content="ToolTip Open" />
+            <Border Name="Border"
+                    Grid.Column="1"
+                    Grid.Row="1"
+                    Background="{DynamicResource ThemeAccentBrush}"
+                    Margin="5"
+                    Padding="50"
+                    ToolTip.Placement="Bottom">
+                <ToolTip.Tip>
+                    <StackPanel>
+                        <TextBlock Classes="h1">ToolTip</TextBlock>
+                        <TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
+                    </StackPanel>
+                </ToolTip.Tip>
+                <TextBlock>ToolTip bottom placement</TextBlock>
+            </Border>
+        </Grid>
+    </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/ToolTipPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ToolTipPage : UserControl
+    {
+        public ToolTipPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

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

@@ -0,0 +1,19 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Spacing="4">
+    <TextBlock Classes="h1">TreeView</TextBlock>
+    <TextBlock Classes="h2">Displays a hierachical tree of data.</TextBlock>
+
+    <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="16">
+      <TreeView Items="{Binding}" Width="250" Height="350">
+        <TreeView.ItemTemplate>
+          <TreeDataTemplate ItemsSource="{Binding Children}">
+            <TextBlock Text="{Binding Header}"/>
+          </TreeDataTemplate>
+        </TreeView.ItemTemplate>
+      </TreeView>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 40 - 0
samples/ControlCatalog/Pages/TreeViewPage.xaml.cs

@@ -0,0 +1,40 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class TreeViewPage : UserControl
+    {
+        public TreeViewPage()
+        {
+            this.InitializeComponent();
+            DataContext = new Node().Children;
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        public class Node
+        {
+            private IList<Node> _children;
+            public string Header { get; private set; }
+            public IList<Node> Children
+            {
+                get
+                {
+                    if (_children == null)
+                    {
+                        _children = Enumerable.Range(1, 10).Select(i => new Node() {Header = $"Item {i}"})
+                            .ToArray();
+                    }
+                    return _children;
+                }
+            }
+        }
+    }
+}

+ 65 - 0
samples/ControlCatalog/Program.cs

@@ -0,0 +1,65 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using Avalonia;
+using Avalonia.Skia;
+using Avalonia.Threading;
+
+namespace ControlCatalog.NetCore
+{
+    static class Program
+    {
+        
+        static void Main(string[] args)
+        {
+            if (args.Contains("--wait-for-attach"))
+            {
+                Console.WriteLine("Attach debugger and use 'Set next statement'");
+                while (true)
+                {
+                    Thread.Sleep(100);
+                    if (Debugger.IsAttached)
+                        break;
+                }
+            }
+            BuildAvaloniaApp().Start<MainWindow>();
+            return;
+            var app = BuildAvaloniaApp().SetupWithoutStarting().Instance;
+            var src = new CancellationTokenSource();
+            int cnt = 0;
+            DispatcherTimer timer = null;
+            timer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, delegate
+            {
+                cnt++;
+                Console.WriteLine("Tick " + cnt);
+                if (cnt == 3)
+                {
+                    timer.Stop();
+                    Dispatcher.UIThread.InvokeAsync(() =>
+                    {
+                        Console.WriteLine("Invoked");
+                        src.Cancel();
+                    });
+                }
+            });
+            timer.Start();
+
+            app.Run(src.Token);
+
+        }
+
+        /// <summary>
+        /// This method is needed for IDE previewer infrastructure
+        /// </summary>
+        public static AppBuilder BuildAvaloniaApp()
+        {
+            var libraryPath = Path.Combine(Directory.GetCurrentDirectory(),
+                                           "../../src/Avalonia.Native.OSX/build/Avalonia.Native.OSX/Build/Products/Debug/libAvalonia.Native.OSX.dylib");
+
+            return AppBuilder.Configure<App>().UseAvaloniaNative(libraryPath).UseSkia();
+        }
+
+    }
+}

+ 52 - 0
samples/ControlCatalog/SideBar.xaml

@@ -0,0 +1,52 @@
+<Styles xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
+  <Style Selector="TabControl.sidebar">
+    <Setter Property="Template">
+      <ControlTemplate>
+        <DockPanel>
+          <ScrollViewer MinWidth="190" Background="{DynamicResource ThemeAccentBrush}" DockPanel.Dock="Left">
+            <TabStrip Name="PART_TabStrip"
+                      MemberSelector="{x:Static TabControl.HeaderSelector}"
+                      Items="{TemplateBinding Items}"
+                      SelectedIndex="{TemplateBinding SelectedIndex, Mode=TwoWay}">
+              <TabStrip.ItemsPanel>
+                <ItemsPanelTemplate>
+                  <StackPanel Orientation="Vertical"/>
+                </ItemsPanelTemplate>
+              </TabStrip.ItemsPanel>
+            </TabStrip>
+          </ScrollViewer>
+          <Carousel Name="PART_Content"
+                    Margin="8 0 0 0"
+                    MemberSelector="{x:Static TabControl.ContentSelector}"
+                    Items="{TemplateBinding Items}"
+                    SelectedIndex="{TemplateBinding SelectedIndex}"
+                    PageTransition="{TemplateBinding PageTransition}"
+                    Grid.Row="1"/>
+        </DockPanel>
+      </ControlTemplate>
+    </Setter>
+  </Style>
+
+  <Style Selector="TabControl.sidebar TabStripItem">
+    <Setter Property="Foreground" Value="White"/>
+    <Setter Property="FontSize" Value="14"/>
+    <Setter Property="Margin" Value="0"/>
+    <Setter Property="Padding" Value="16"/>
+    <Setter Property="Opacity" Value="0.5"/>
+    <Setter Property="Transitions">
+      <Transitions>
+        <DoubleTransition Property="Opacity" Duration="0:0:0.2"/>
+      </Transitions>
+    </Setter>
+  </Style>
+
+  <Style Selector="TabControl.sidebar TabStripItem:pointerover">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="TabControl.sidebar TabStripItem:selected">
+    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+</Styles>

+ 4 - 0
src/Avalonia.Native.OSX/.gitignore

@@ -0,0 +1,4 @@
+build
+
+Avalonia.Native.OSX.xcodeproj/xcuserdata
+Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcuserdata

+ 276 - 0
src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@@ -0,0 +1,276 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
+		AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
+		AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
+		AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+		AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
+		AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = "<group>"; };
+		AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+		AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libAvalonia.Native.OSX.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+		AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platformthreading.mm; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		AB7A61EC2147C814003C5833 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		AB661C1C2148230E00291242 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				AB661C1D2148230F00291242 /* AppKit.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		AB7A61E62147C814003C5833 = {
+			isa = PBXGroup;
+			children = (
+				AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */,
+				AB661C212148288600291242 /* common.h */,
+				AB661C1F2148286E00291242 /* window.mm */,
+				AB00E4F62147CA920032A60A /* main.mm */,
+				AB7A61F02147C815003C5833 /* Products */,
+				AB661C1C2148230E00291242 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		AB7A61F02147C815003C5833 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		AB7A61ED2147C814003C5833 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		AB7A61EE2147C814003C5833 /* Avalonia.Native.OSX */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = AB7A61F82147C815003C5833 /* Build configuration list for PBXNativeTarget "Avalonia.Native.OSX" */;
+			buildPhases = (
+				AB7A61EB2147C814003C5833 /* Sources */,
+				AB7A61EC2147C814003C5833 /* Frameworks */,
+				AB7A61ED2147C814003C5833 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Avalonia.Native.OSX;
+			productName = Avalonia.Native.OSX;
+			productReference = AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */;
+			productType = "com.apple.product-type.library.dynamic";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		AB7A61E72147C814003C5833 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0830;
+				ORGANIZATIONNAME = Avalonia;
+				TargetAttributes = {
+					AB7A61EE2147C814003C5833 = {
+						CreatedOnToolsVersion = 8.3.2;
+						ProvisioningStyle = Automatic;
+					};
+				};
+			};
+			buildConfigurationList = AB7A61EA2147C814003C5833 /* Build configuration list for PBXProject "Avalonia.Native.OSX" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = AB7A61E62147C814003C5833;
+			productRefGroup = AB7A61F02147C815003C5833 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				AB7A61EE2147C814003C5833 /* Avalonia.Native.OSX */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		AB7A61EB2147C814003C5833 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
+				AB00E4F72147CA920032A60A /* main.mm in Sources */,
+				AB661C202148286E00291242 /* window.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		AB7A61F62147C815003C5833 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.12;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		AB7A61F72147C815003C5833 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.12;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		AB7A61F92147C815003C5833 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXECUTABLE_PREFIX = lib;
+				HEADER_SEARCH_PATHS = ../headers;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		AB7A61FA2147C815003C5833 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXECUTABLE_PREFIX = lib;
+				HEADER_SEARCH_PATHS = ../headers;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		AB7A61EA2147C814003C5833 /* Build configuration list for PBXProject "Avalonia.Native.OSX" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				AB7A61F62147C815003C5833 /* Debug */,
+				AB7A61F72147C815003C5833 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		AB7A61F82147C815003C5833 /* Build configuration list for PBXNativeTarget "Avalonia.Native.OSX" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				AB7A61F92147C815003C5833 /* Debug */,
+				AB7A61FA2147C815003C5833 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = AB7A61E72147C814003C5833 /* Project object */;
+}

+ 7 - 0
src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:Avalonia.Native.OSX.xcodeproj">
+   </FileRef>
+</Workspace>

+ 91 - 0
src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0830"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "AB7A61EE2147C814003C5833"
+               BuildableName = "libAvalonia.Native.OSX.dylib"
+               BlueprintName = "Avalonia.Native.OSX"
+               ReferencedContainer = "container:Avalonia.Native.OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "YES"
+      customWorkingDirectory = "$PROJECT_DIR/../../samples/ControlCatalog"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <PathRunnable
+         runnableDebuggingMode = "0"
+         FilePath = "/usr/local/share/dotnet/dotnet">
+      </PathRunnable>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "AB7A61EE2147C814003C5833"
+            BuildableName = "libAvalonia.Native.OSX.dylib"
+            BlueprintName = "Avalonia.Native.OSX"
+            ReferencedContainer = "container:Avalonia.Native.OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <CommandLineArguments>
+         <CommandLineArgument
+            argument = "bin/Debug/netcoreapp2.0/ControlCatalog.dll"
+            isEnabled = "YES">
+         </CommandLineArgument>
+      </CommandLineArguments>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "AB7A61EE2147C814003C5833"
+            BuildableName = "libAvalonia.Native.OSX.dylib"
+            BlueprintName = "Avalonia.Native.OSX"
+            ReferencedContainer = "container:Avalonia.Native.OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 12 - 0
src/Avalonia.Native.OSX/common.h

@@ -0,0 +1,12 @@
+#ifndef common_h
+#define common_h
+#include "com.h"
+#include "avalonia-native.h"
+#include <stdio.h>
+#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
+#include <pthread.h>
+
+extern IAvnPlatformThreadingInterface* CreatePlatformThreading();
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events);
+#endif

+ 93 - 0
src/Avalonia.Native.OSX/main.mm

@@ -0,0 +1,93 @@
+//This file will contain actual IID structures
+#define COM_GUIDS_MATERIALIZE
+#include "common.h"
+
+static BOOL ShowInDock = 1;
+
+static void SetActivationPolicy()
+{
+    [[NSApplication sharedApplication] setActivationPolicy: (ShowInDock ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory)];
+}
+
+class MacOptions : public ComSingleObject<IAvnMacOptions, &IID_IAvnMacOptions>
+{
+public:
+    virtual HRESULT SetShowInDock(int show)
+    {
+        ShowInDock = show;
+        SetActivationPolicy();
+        return S_OK;
+    }
+};
+
+
+
+/// See "Using POSIX Threads in a Cocoa Application" section here:
+/// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/20000738-125024
+@interface ThreadingInitializer : NSObject
+- (void) do;
+@end
+@implementation ThreadingInitializer
+
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+
+- (void) runOnce
+{
+    pthread_mutex_lock(&mutex);
+    pthread_cond_signal(&cond);
+    pthread_mutex_unlock(&mutex);
+}
+
+- (void) do
+{
+    pthread_mutex_init(&mutex, NULL);
+    pthread_cond_init(&cond, NULL);
+    [[[NSThread alloc] initWithTarget:self selector:@selector(runOnce) object:nil] start];
+    pthread_mutex_lock(&mutex);
+    pthread_cond_wait(&cond, &mutex);
+    pthread_mutex_unlock(&mutex);
+    pthread_cond_destroy(&cond);
+    pthread_mutex_destroy(&mutex);
+}
+
+
+@end
+
+
+class AvaloniaNative : public ComSingleObject<IAvaloniaNativeFactory, &IID_IAvaloniaNativeFactory>
+{
+    
+public:
+    virtual HRESULT Initialize()
+    {
+        @autoreleasepool{
+            [[ThreadingInitializer new] do];
+            return S_OK;
+        }
+    };
+    
+    virtual IAvnMacOptions* GetMacOptions()
+    {
+        return (IAvnMacOptions*)new MacOptions();
+    }
+    
+    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv)
+    {
+        if(cb == nullptr || ppv == nullptr)
+            return E_POINTER;
+        *ppv = CreateAvnWindow(cb);
+        return S_OK;
+    };
+    
+    virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv)
+    {
+        *ppv = CreatePlatformThreading();
+        return S_OK;
+    };
+};
+
+extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()
+{
+    return new AvaloniaNative();
+};

+ 178 - 0
src/Avalonia.Native.OSX/platformthreading.mm

@@ -0,0 +1,178 @@
+#include "common.h"
+
+class PlatformThreadingInterface;
+@interface Signaler : NSObject
+-(void) setParent: (PlatformThreadingInterface*)parent;
+-(void) signal: (int) priority;
+-(Signaler*) init;
+@end
+
+
+@interface ActionCallback : NSObject
+- (ActionCallback*) initWithCallback: (IAvnActionCallback*) callback;
+- (void) action;
+@end
+
+@implementation ActionCallback
+{
+    ComPtr<IAvnActionCallback> _callback;
+
+}
+- (ActionCallback*) initWithCallback: (IAvnActionCallback*) callback
+{
+    _callback = callback;
+    return self;
+}
+
+- (void) action
+{
+    _callback->Run();
+}
+
+
+@end
+
+class TimerWrapper : public ComUnknownObject
+{
+    NSTimer* _timer;
+public:
+    TimerWrapper(IAvnActionCallback* callback, int ms)
+    {
+        auto cb = [[ActionCallback alloc] initWithCallback:callback];
+        _timer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(double)ms/1000 target:cb selector:@selector(action) userInfo:nullptr repeats:true];
+    }
+                  
+    virtual ~TimerWrapper()
+    {
+         [_timer invalidate];
+    }
+};
+
+
+
+class PlatformThreadingInterface : public ComSingleObject<IAvnPlatformThreadingInterface, &IID_IAvnPlatformThreadingInterface>
+{
+private:
+    Signaler* _signaler;
+    
+    class LoopCancellation : public ComSingleObject<IAvnLoopCancellation, &IID_IAvnLoopCancellation>
+    {
+    public:
+        bool Cancelled = 0;
+        virtual void Cancel()
+        {
+            Cancelled = 1;
+        }
+    };
+    
+public:
+    ComPtr<IAvnSignaledCallback> SignaledCallback;
+
+    PlatformThreadingInterface()
+    {
+        _signaler = [Signaler new];
+        [_signaler setParent:this];
+    }
+    
+    ~PlatformThreadingInterface()
+    {
+        if(_signaler)
+            [_signaler setParent: NULL];
+        _signaler = NULL;
+    }
+    
+    virtual bool GetCurrentThreadIsLoopThread()
+    {
+        return [[NSThread currentThread] isMainThread];
+    }
+    virtual void SetSignaledCallback(IAvnSignaledCallback* cb)
+    {
+        SignaledCallback = cb;
+    }
+    virtual IAvnLoopCancellation* CreateLoopCancellation()
+    {
+        return new LoopCancellation();
+    }
+    
+    virtual void RunLoop(IAvnLoopCancellation* cancel)
+    {
+        @autoreleasepool {
+            auto can = dynamic_cast<LoopCancellation*>(cancel);
+            [[NSApplication sharedApplication] activateIgnoringOtherApps:true];
+            while(true)
+            {
+                NSEvent* ev = [[NSApplication sharedApplication]
+                               nextEventMatchingMask:NSEventMaskAny
+                               untilDate: [NSDate distantFuture]
+                               inMode:NSDefaultRunLoopMode
+                               dequeue:true];
+                if(can != NULL && can->Cancelled)
+                    return;
+                if(ev != NULL)
+                    [[NSApplication sharedApplication] sendEvent:ev];
+            }
+        }
+    }
+    
+    virtual void Signal(int priority)
+    {
+        [_signaler signal:priority];
+    }
+    
+    virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback)
+    {
+        @autoreleasepool {
+            
+            return new TimerWrapper(callback, ms);
+        }
+    }
+};
+
+@implementation Signaler
+
+PlatformThreadingInterface* _parent = 0;
+bool _signaled = 0;
+NSArray<NSString*>* _modes;
+
+-(Signaler*) init
+{
+    if(self = [super init])
+    {
+        _modes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode, nil];
+    }
+    return self;
+}
+
+-(void) perform
+{
+    @synchronized (self) {
+        if(_parent != NULL && _parent->SignaledCallback != NULL)
+            _parent->SignaledCallback->Signaled(0, false);
+    }
+}
+
+-(void) setParent:(PlatformThreadingInterface *)parent
+{
+    @synchronized (self) {
+        _parent = parent;
+    }
+}
+
+-(void) signal: (int) priority
+{
+
+    @synchronized (self) {
+        if(_signaled)
+            return;
+        _signaled = true;
+        [self performSelector:@selector(perform) onThread:[NSThread mainThread] withObject:NULL waitUntilDone:false modes:_modes];
+    }
+    
+}
+@end
+
+
+extern IAvnPlatformThreadingInterface* CreatePlatformThreading()
+{
+    return new PlatformThreadingInterface();
+}

+ 199 - 0
src/Avalonia.Native.OSX/window.mm

@@ -0,0 +1,199 @@
+#include "common.h"
+
+class WindowBaseImpl;
+
+@interface AvnView : NSView
+-(AvnView*)  initWithParent: (WindowBaseImpl*) parent;
+@end
+
+@interface AvnWindow : NSWindow <NSWindowDelegate>
+-(AvnWindow*) initWithParent: (WindowBaseImpl*) parent;
+-(void) setCanBecomeKeyAndMain;
+@end
+
+
+
+
+class WindowBaseImpl : public ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>
+{
+public:
+    AvnView* View;
+    AvnWindow* Window;
+    ComPtr<IAvnWindowBaseEvents> BaseEvents;
+    WindowBaseImpl(IAvnWindowBaseEvents* events)
+    {
+        BaseEvents = events;
+        View = [[AvnView alloc] initWithParent:this];
+        Window = [[AvnWindow alloc] initWithParent:this];
+        [Window setStyleMask:NSWindowStyleMaskBorderless];
+        [Window setBackingType:NSBackingStoreBuffered];
+        [Window setContentView: View];
+    }
+    
+    virtual HRESULT Show()
+    {
+        [Window makeKeyAndOrderFront:Window];
+        return S_OK;
+    }
+    
+    virtual HRESULT Close()
+    {
+        [Window close];
+        return S_OK;
+    }
+    
+    virtual HRESULT GetClientSize(AvnSize* ret)
+    {
+        if(ret == nullptr)
+            return E_POINTER;
+        auto frame = [View frame];
+        ret->Width = frame.size.width;
+        ret->Height = frame.size.height;
+        return S_OK;
+    }
+    
+    virtual HRESULT Resize(double x, double y)
+    {
+        [Window setContentSize:NSSize{x, y}];
+        return S_OK;
+    }
+    
+protected:
+    virtual NSWindowStyleMask GetStyle()
+    {
+        return NSWindowStyleMaskBorderless;
+    }
+    
+    void UpdateStyle()
+    {
+        [Window setStyleMask:GetStyle()];
+    }
+    
+    
+};
+
+
+@implementation AvnView
+{
+    ComPtr<WindowBaseImpl> _parent;
+}
+
+-(AvnView*)  initWithParent: (WindowBaseImpl*) parent
+{
+    self = [super init];
+    _parent = parent;
+    return self;
+}
+
+- (BOOL)isOpaque
+{
+    return true;
+}
+
+-(void)setFrameSize:(NSSize)newSize
+{
+    [super setFrameSize:newSize];
+    _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+    auto logicalSize = [self frame].size;
+    auto pixelSize = [self convertSizeToBacking:logicalSize];
+    int w = pixelSize.width;
+    int h = pixelSize.height;
+    int stride = w * 4;
+    void*ptr = malloc(h * stride);
+    _parent->BaseEvents->SoftwareDraw(ptr, stride, w, h, AvnSize{logicalSize.width, logicalSize.height});
+    
+    auto colorSpace = CGColorSpaceCreateDeviceRGB();
+    auto bctx = CGBitmapContextCreate(ptr, w, h, 8, stride, colorSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);
+    auto image = CGBitmapContextCreateImage(bctx);
+    CGContextRelease(bctx);
+    CGColorSpaceRelease(colorSpace);
+    
+    auto ctx = [NSGraphicsContext currentContext];
+    
+    [ctx saveGraphicsState];
+    auto cgc = [ctx CGContext];
+    
+    CGContextDrawImage(cgc, CGRect{0,0, logicalSize.width, logicalSize.height}, image);
+    CGImageRelease(image);
+    
+    [ctx restoreGraphicsState];
+    free(ptr);
+}
+@end
+
+
+@implementation AvnWindow
+{
+    ComPtr<WindowBaseImpl> _parent;
+    bool _canBecomeKeyAndMain;
+}
+
+-(void) setCanBecomeKeyAndMain
+{
+    _canBecomeKeyAndMain = true;
+}
+
+-(AvnWindow*)  initWithParent: (WindowBaseImpl*) parent
+{
+    self = [super init];
+    _parent = parent;
+    [self setDelegate:self];
+    return self;
+}
+
+-(BOOL)canBecomeKeyWindow
+{
+    return _canBecomeKeyAndMain;
+}
+
+-(BOOL)canBecomeMainWindow
+{
+    return _canBecomeKeyAndMain;
+}
+
+-(void)becomeKeyWindow
+{
+    [super becomeKeyWindow];
+    _parent->BaseEvents->Activated();
+}
+
+-(void)resignKeyWindow
+{
+    _parent->BaseEvents->Deactivated();
+    [super resignKeyWindow];
+}
+
+@end
+
+
+class WindowImpl : public WindowBaseImpl, public IAvnWindow
+{
+    BEGIN_INTERFACE_MAP()
+    INHERIT_INTERFACE_MAP(WindowBaseImpl)
+    INTERFACE_MAP_ENTRY(IAvnWindow, IID_IAvnWindow)
+    END_INTERFACE_MAP()
+    ComPtr<IAvnWindowEvents> WindowEvents;
+    WindowImpl(IAvnWindowEvents* events) : WindowBaseImpl(events)
+    {
+        WindowEvents = events;
+        [Window setCanBecomeKeyAndMain];
+        UpdateStyle();
+    }
+    
+protected:
+    virtual NSWindowStyleMask GetStyle()
+    {
+        return NSWindowStyleMaskBorderless | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
+    }
+};
+
+
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events)
+{
+    IAvnWindow* ptr = dynamic_cast<IAvnWindow*>(new WindowImpl(events));
+    return ptr;
+}

+ 1 - 0
src/Avalonia.Native/.gitignore

@@ -0,0 +1 @@
+Generated

+ 15 - 0
src/Avalonia.Native/Avalonia.Native.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <CastXmlPath>/usr/local/bin/castxml</CastXmlPath>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <SharpGenGeneratedCodeFolder>$(MSBuildThisFileDirectory)/Generated</SharpGenGeneratedCodeFolder>
+  </PropertyGroup>
+    <ItemGroup>
+        <PackageReference Include="SharpGenTools.Sdk" Version="1.1.2" PrivateAssets="all" />
+        <PackageReference Include="SharpGen.Runtime.Com" Version="1.1.0" />
+        <PackageReference Include="Avalonia" Version="0.6.2-build6191-beta" />
+        <SharpGenMapping Include="Mappings.xml" />
+    </ItemGroup>
+</Project>

+ 147 - 0
src/Avalonia.Native/AvaloniaNativePlatform.cs

@@ -0,0 +1,147 @@
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Native;
+using Avalonia.Native.Interop;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+
+namespace Avalonia.Native
+{
+    class AvaloniaNativePlatform : IPlatformSettings, IWindowingPlatform
+    {
+        private readonly IAvaloniaNativeFactory _factory;
+
+        [DllImport("libAvaloniaNative")]
+        static extern IntPtr CreateAvaloniaNative();
+
+        internal static readonly MouseDevice MouseDevice = new MouseDevice();
+        internal static readonly KeyboardDevice KeyboardDevice = new KeyboardDevice();
+
+        public Size DoubleClickSize => new Size(4, 4);
+
+        public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(500); //TODO
+
+        public static void Initialize(IntPtr factory, Action<AvaloniaNativeOptions> configure)
+        {
+            new AvaloniaNativePlatform(new IAvaloniaNativeFactory(factory))
+                .DoInitialize(configure);
+        }
+
+        delegate IntPtr CreateAvaloniaNativeDelegate();
+
+        public static void Initialize(string library, Action<AvaloniaNativeOptions> configure)
+        {
+            var loader = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+                                           ? (IDynLoader)new Win32Loader() : new UnixLoader();
+            var lib = loader.LoadLibrary(library);
+            var proc = loader.GetProcAddress(lib, "CreateAvaloniaNative", false);
+            var d = Marshal.GetDelegateForFunctionPointer<CreateAvaloniaNativeDelegate>(proc);
+
+
+            Initialize(d(), configure);
+        }
+
+        public static void Initialize(Action<AvaloniaNativeOptions> configure)
+        {
+            Initialize(CreateAvaloniaNative(), configure);
+        }
+
+        private AvaloniaNativePlatform(IAvaloniaNativeFactory factory)
+        {
+            _factory = factory;
+        }
+
+        void DoInitialize(Action<AvaloniaNativeOptions> configure)
+        {
+            var opts = new AvaloniaNativeOptions(_factory);
+            configure?.Invoke(opts);
+            _factory.Initialize();
+
+
+            AvaloniaLocator.CurrentMutable
+                .Bind<IStandardCursorFactory>().ToTransient<CursorFactoryStub>()
+                .Bind<IPlatformIconLoader>().ToSingleton<IconLoader>()
+
+                .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
+                .Bind<IMouseDevice>().ToConstant(MouseDevice)
+                .Bind<IPlatformSettings>().ToConstant(this)
+                .Bind<IWindowingPlatform>().ToConstant(this)
+                .Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
+                .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
+                .Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
+                .Bind<IPlatformThreadingInterface>().ToConstant(new PlatformThreadingInterface(_factory.CreatePlatformThreadingInterface()));
+        }
+
+        public IWindowImpl CreateWindow()
+        {
+            return new WindowImpl(_factory);
+        }
+
+        public IEmbeddableWindowImpl CreateEmbeddableWindow()
+        {
+            throw new NotImplementedException();
+        }
+
+        public IPopupImpl CreatePopup()
+        {
+            throw new NotImplementedException();
+        }
+    }
+
+    public class AvaloniaNativeMacOptions
+    {
+        private readonly IAvnMacOptions _opts;
+        private bool _showInDock;
+        internal AvaloniaNativeMacOptions(IAvnMacOptions opts)
+        {
+            _opts = opts;
+            ShowInDock = true;
+        }
+
+        public bool ShowInDock 
+        { 
+            get => _showInDock;
+            set
+            {
+                _showInDock = value;
+                _opts.ShowInDock = value ? 1 : 0;
+            }
+        }
+    }
+
+    public class AvaloniaNativeOptions
+    {
+        public AvaloniaNativeMacOptions MacOptions { get; set; }
+        internal AvaloniaNativeOptions(IAvaloniaNativeFactory factory)
+        {
+            var mac = factory.GetMacOptions();
+            if (mac != null)
+                MacOptions = new AvaloniaNativeMacOptions(mac);
+        }
+
+    }
+}
+
+namespace Avalonia
+{
+
+    public static class AvaloniaNativePlatformExtensions
+    {
+        public static T UseAvaloniaNative<T>(this T builder,
+                                             string libraryPath = null,
+                                             Action<AvaloniaNativeOptions> configure = null)
+                                             where T : AppBuilderBase<T>, new()
+        {
+            if (libraryPath == null)
+                builder.UseWindowingSubsystem(() => AvaloniaNativePlatform.Initialize(configure));
+            else
+                builder.UseWindowingSubsystem(() => AvaloniaNativePlatform.Initialize(libraryPath, configure));
+            return builder;
+        }
+    }
+}

+ 68 - 0
src/Avalonia.Native/CallbackBase.cs

@@ -0,0 +1,68 @@
+using System;
+using SharpGen.Runtime;
+
+namespace Avalonia.Native
+{
+    public class CallbackBase : SharpGen.Runtime.IUnknown
+    {
+        uint _refCount;
+        bool _disposed;
+        object _lock = new object();
+        private ShadowContainer _shadow;
+
+        public CallbackBase()
+        {
+            _refCount = 1;
+        }
+
+        public ShadowContainer Shadow
+        {
+            get => _shadow;
+            set
+            {
+                lock (_lock)
+                {
+                    if (_disposed && value != null)
+                        throw new ObjectDisposedException("CallbackBase");
+                    _shadow = value;
+                }
+            }
+        }
+
+        public uint AddRef()
+        {
+            lock (_lock)
+                return ++_refCount;
+        }
+
+        public void Dispose()
+        {
+            lock (_lock)
+                if (!_disposed)
+                {
+                    _disposed = true;
+                    Release();
+                }
+        }
+
+        public uint Release()
+        {
+            lock (_lock)
+            {
+                _refCount--;
+                if (_refCount == 0)
+                {
+                    Shadow?.Dispose();
+                    Shadow = null;
+                    Destroyed();
+                }
+                return _refCount;
+            }
+        }
+
+        protected virtual void Destroyed()
+        {
+
+        }
+    }
+}

+ 21 - 0
src/Avalonia.Native/Cursor.cs

@@ -0,0 +1,21 @@
+using System;
+using Avalonia.Input;
+using Avalonia.Platform;
+
+namespace Avalonia.Native
+{
+    class Cursor : IPlatformHandle
+    {
+        public IntPtr Handle => IntPtr.Zero;
+
+        public string HandleDescriptor => "STUB";
+    }
+
+    class CursorFactoryStub : IStandardCursorFactory
+    {
+        public IPlatformHandle GetCursor(StandardCursorType cursorType)
+        {
+            return new Cursor();
+        }
+    }
+}

+ 128 - 0
src/Avalonia.Native/DynLoader.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Runtime.InteropServices;
+
+/*
+ * Source code imported from https://github.com/kekekeks/evhttp-sharp
+ * Source is provided under MIT license for Avalonia project and derived works
+ */
+
+
+namespace Avalonia.Native
+{
+    internal interface IDynLoader
+    {
+        IntPtr LoadLibrary(string dll);
+        IntPtr GetProcAddress(IntPtr dll, string proc, bool optional);
+
+    }
+
+    class UnixLoader : IDynLoader
+    {
+        // ReSharper disable InconsistentNaming
+        static class LinuxImports
+        {
+            [DllImport("libdl.so.2")]
+            private static extern IntPtr dlopen(string path, int flags);
+
+            [DllImport("libdl.so.2")]
+            private static extern IntPtr dlsym(IntPtr handle, string symbol);
+
+            [DllImport("libdl.so.2")]
+            private static extern IntPtr dlerror();
+
+            public static void Init()
+            {
+                DlOpen = dlopen;
+                DlSym = dlsym;
+                DlError = dlerror;
+            }
+        }
+        static class OsXImports
+        {
+
+
+            [DllImport("/usr/lib/libSystem.dylib")]
+            private static extern IntPtr dlopen(string path, int flags);
+
+            [DllImport("/usr/lib/libSystem.dylib")]
+            private static extern IntPtr dlsym(IntPtr handle, string symbol);
+
+            [DllImport("/usr/lib/libSystem.dylib")]
+            private static extern IntPtr dlerror();
+
+            public static void Init()
+            {
+                DlOpen = dlopen;
+                DlSym = dlsym;
+                DlError = dlerror;
+            }
+
+        }
+
+
+        [DllImport("libc")]
+        static extern int uname(IntPtr buf);
+
+        static UnixLoader()
+        {
+            var buffer = Marshal.AllocHGlobal(0x1000);
+            uname(buffer);
+            var unixName = Marshal.PtrToStringAnsi(buffer);
+            Marshal.FreeHGlobal(buffer);
+            if (unixName == "Darwin")
+                OsXImports.Init();
+            else
+                LinuxImports.Init();
+        }
+
+        private static Func<string, int, IntPtr> DlOpen;
+        private static Func<IntPtr, string, IntPtr> DlSym;
+        private static Func<IntPtr> DlError;
+        // ReSharper restore InconsistentNaming
+
+        static string DlErrorString() => Marshal.PtrToStringAnsi(DlError());
+
+        public IntPtr LoadLibrary(string dll)
+        {
+            var handle = DlOpen(dll, 1);
+            if (handle == IntPtr.Zero)
+                throw new Exception(DlErrorString());
+            return handle;
+        }
+
+        public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional)
+        {
+            var ptr = DlSym(dll, proc);
+            if (ptr == IntPtr.Zero && !optional)
+                throw new Exception(DlErrorString());
+            return ptr;
+        }
+    }
+
+    internal class Win32Loader : IDynLoader
+    {
+        [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
+        private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
+
+        [DllImport("kernel32", EntryPoint = "LoadLibraryW", SetLastError = true, CharSet = CharSet.Unicode)]
+        private static extern IntPtr LoadLibrary(string lpszLib);
+
+        IntPtr IDynLoader.LoadLibrary(string dll)
+        {
+            var handle = LoadLibrary(dll);
+            if (handle != IntPtr.Zero)
+                return handle;
+            var err = Marshal.GetLastWin32Error();
+
+            throw new Exception("Error loading " + dll + " error " + err);
+        }
+
+        IntPtr IDynLoader.GetProcAddress(IntPtr dll, string proc, bool optional)
+        {
+            var ptr = GetProcAddress(dll, proc);
+            if (ptr == IntPtr.Zero && !optional)
+                throw new Exception("Error " + Marshal.GetLastWin32Error());
+            return ptr;
+        }
+    }
+}

+ 48 - 0
src/Avalonia.Native/IconLoader.cs

@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using Avalonia.Platform;
+
+namespace Avalonia.Native
+{
+    // OSX doesn't have a concept of *window* icon. 
+    // Icons in the title bar are only shown if there is 
+    // an opened file (on disk) associated with the current window
+    // see http://stackoverflow.com/a/7038671/2231814
+    class IconLoader : IPlatformIconLoader
+    {
+        class IconStub : IWindowIconImpl
+        {
+            private readonly IBitmapImpl _bitmap;
+
+            public IconStub(IBitmapImpl bitmap)
+            {
+                _bitmap = bitmap;
+            }
+
+            public void Save(Stream outputStream)
+            {
+                _bitmap.Save(outputStream);
+            }
+        }
+
+        public IWindowIconImpl LoadIcon(string fileName)
+        {
+            return new IconStub(
+                AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().LoadBitmap(fileName));
+        }
+
+        public IWindowIconImpl LoadIcon(Stream stream)
+        {
+            return new IconStub(
+                AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().LoadBitmap(stream));
+        }
+
+        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            var ms = new MemoryStream();
+            bitmap.Save(ms);
+            ms.Seek(0, SeekOrigin.Begin);
+            return LoadIcon(ms);
+        }
+    }
+}

+ 27 - 0
src/Avalonia.Native/Mappings.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config id="AvaloniaNative" xmlns="urn:SharpGen.Config">
+    <assembly>Avalonia.Native</assembly>
+    <namespace>Avalonia.Native.Interop</namespace>
+    <depends>SharpGen.Runtime.COM</depends>
+    <sdk name="StdLib" version="4.2.1"/>
+    <include-dir>$(THIS_CONFIG_PATH)/../headers</include-dir>
+    <include file="avalonia-native.h" 
+             namespace="Avalonia.Native.Interop"
+             attach="true"
+             pre="#define COM_GUIDS_MATERIALIZE\n"/>
+    <include file="com.h" 
+             namespace="Avalonia.Native.Interop"
+             attach="true"
+             pre="#define COM_GUIDS_MATERIALIZE\n"/>
+    <bindings>
+        <bind from="HRESULT" to="SharpGen.Runtime.Result"/>
+        <bind from="HRESULT" to="SharpGen.Runtime.Result"/>
+    </bindings>
+    <mapping>
+        <remove function=".*" />
+        <map interface="*.Events" callback="true" autogen-shadow="true"/>
+        <map interface="*.Callback" callback="true" autogen-shadow="true"/>
+        <map param=".*::.*::ppv" return="true"/>
+        <map param=".*::.*::ret" return="true"/>
+    </mapping>
+</config>

+ 98 - 0
src/Avalonia.Native/PlatformThreadingInterface.cs

@@ -0,0 +1,98 @@
+using System;
+using System.Threading;
+using Avalonia.Native.Interop;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using SharpGen.Runtime;
+
+namespace Avalonia.Native
+{
+    public class PlatformThreadingInterface : IPlatformThreadingInterface
+    {
+        class TimerCallback : CallbackBase, IAvnActionCallback
+        {
+            readonly Action _tick;
+
+            public TimerCallback(Action tick)
+            {
+                _tick = tick;
+            }
+
+            public void Run()
+            {
+                _tick();
+            }
+        }
+
+        class SignaledCallback : CallbackBase, IAvnSignaledCallback
+        {
+            readonly PlatformThreadingInterface _parent;
+
+            public SignaledCallback(PlatformThreadingInterface parent)
+            {
+                _parent = parent;
+            }
+
+            public void Signaled(int priority, bool priorityContainsMeaningfulValue)
+            {
+                _parent.Signaled?.Invoke(priorityContainsMeaningfulValue ? (DispatcherPriority?)priority : null);
+            }
+        }
+
+        readonly IAvnPlatformThreadingInterface _native;
+
+        public PlatformThreadingInterface(IAvnPlatformThreadingInterface native)
+        {
+            _native = native;
+            using (var cb = new SignaledCallback(this))
+                _native.SignaledCallback = cb;
+        }
+
+        public bool CurrentThreadIsLoopThread => _native.CurrentThreadIsLoopThread;
+
+        public event Action<DispatcherPriority?> Signaled;
+
+        public void RunLoop(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.CanBeCanceled == false)
+                _native.RunLoop(null);
+            else
+            {
+                var l = new object();
+                var cancellation = _native.CreateLoopCancellation();
+                cancellationToken.Register(() =>
+                {
+                    lock (l)
+                    {
+                        cancellation?.Cancel();
+                        cancellation?.Dispose();
+                        cancellation = null;
+                    }
+                });
+                try
+                {
+                    _native.RunLoop(cancellation);
+                }
+                finally
+                {
+                    lock(l)
+                    {
+                        cancellation?.Dispose();
+                        cancellation = null;
+                    }
+                }
+            }
+        }
+
+        public void Signal(DispatcherPriority priority)
+        {
+            _native.Signal((int)priority);
+        }
+
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
+        {
+            using (var cb = new TimerCallback(tick))
+                return _native.StartTimer((int)priority, (int)interval.TotalMilliseconds, cb);
+        }
+    }
+}

+ 48 - 0
src/Avalonia.Native/Stubs.cs

@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Input.Platform;
+using Avalonia.Platform;
+
+namespace Avalonia.Native
+{
+    class SystemDialogImpl : ISystemDialogImpl
+    {
+        public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
+        {
+            return Task.FromResult((string[])null);
+        }
+
+        public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
+        {
+            return Task.FromResult<string>(null);
+        }
+    }
+
+    class ClipboardImpl : IClipboard
+    {
+        public Task ClearAsync()
+        {
+            return Task.CompletedTask;
+        }
+
+        public Task<string> GetTextAsync()
+        {
+            return Task.FromResult<string>(null);
+        }
+
+        public Task SetTextAsync(string text)
+        {
+            return Task.CompletedTask;
+        }
+    }
+
+    class ScreenImpl : IScreenImpl
+    {
+        public int ScreenCount => 1;
+
+        public Screen[] AllScreens => new[] { new Screen(new Rect(0, 0, 1600, 900), new Rect(0, 0, 1600, 900), true) };
+    }
+}

+ 55 - 0
src/Avalonia.Native/WindowImpl.cs

@@ -0,0 +1,55 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Native.Interop;
+using Avalonia.Platform;
+
+namespace Avalonia.Native
+{
+    class WindowImpl : WindowBaseImpl, IWindowImpl
+    {
+        public WindowImpl(IAvaloniaNativeFactory factory)
+        {
+            using (var e = new WindowEvents(this))
+                Init(factory.CreateWindow(e));
+        }
+
+        class WindowEvents : WindowBaseEvents, IAvnWindowEvents
+        {
+            readonly WindowImpl _parent;
+
+            public WindowEvents(WindowImpl parent) : base(parent)
+            {
+                _parent = parent;
+            }
+        }
+
+        public IDisposable ShowDialog()
+        {
+            return null;
+        }
+
+
+        public void CanResize(bool value)
+        {
+
+        }
+        public void SetSystemDecorations(bool enabled)
+        {
+        }
+
+        public void SetTitle(string title)
+        {
+        }
+
+        public WindowState WindowState { get; set; } = WindowState.Normal;
+        public Action<WindowState> WindowStateChanged { get; set; }
+
+        public void ShowTaskbarIcon(bool value)
+        {
+        }
+        public void SetIcon(IWindowIconImpl icon)
+        {
+        }
+        public Func<bool> Closing { get; set; }
+    }
+}

+ 192 - 0
src/Avalonia.Native/WindowImplBase.cs

@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Native.Interop;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+
+namespace Avalonia.Native
+{
+    public class WindowBaseImpl : IWindowBaseImpl, IFramebufferPlatformSurface
+    {
+        IInputRoot _inputRoot;
+        IAvnWindowBase _native;
+
+        protected void Init(IAvnWindowBase window)
+        {
+            _native = window;
+        }
+
+        public Size ClientSize 
+        {
+            get
+            {
+                var s = _native.GetClientSize();
+                return new Size(s.Width, s.Height);
+            }
+        }
+        SavedFramebuffer _framebuffer;
+
+        public IEnumerable<object> Surfaces => new[] { this };
+        public ILockedFramebuffer Lock()
+        {
+            return _framebuffer;
+        }
+
+        public Action<Rect> Paint { get; set; }
+        public Action<Size> Resized { get; set; }
+        public Action Closed { get; set; }
+        public IMouseDevice MouseDevice => AvaloniaNativePlatform.MouseDevice;
+
+
+        class SavedFramebuffer : ILockedFramebuffer
+        {
+            public IntPtr Address { get; set; }
+            public int Width { get; set; }
+            public int Height { get; set; }
+            public int RowBytes {get;set;}
+            public Vector Dpi { get; set; }
+            public PixelFormat Format => PixelFormat.Rgba8888;
+            public void Dispose()
+            {
+                // Do nothing
+            }
+        }
+
+        protected class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
+        {
+            private readonly WindowBaseImpl _parent;
+
+            public WindowBaseEvents(WindowBaseImpl parent)
+            {
+                _parent = parent;
+            }
+
+            void IAvnWindowBaseEvents.Closed() => _parent.Closed?.Invoke();
+
+            void IAvnWindowBaseEvents.Activated() => _parent.Activated?.Invoke();
+
+
+            void IAvnWindowBaseEvents.Deactivated() => _parent.Deactivated?.Invoke();
+
+            void IAvnWindowBaseEvents.SoftwareDraw(IntPtr ptr, int stride, int pixelWidth, int pixelHeight, AvnSize logicalSize)
+            {
+                _parent._framebuffer = new SavedFramebuffer
+                {
+                    Address = ptr,
+                    RowBytes = stride,
+                    Width = pixelWidth,
+                    Height = pixelHeight,
+                    Dpi = new Vector(pixelWidth / logicalSize.Width * 96, pixelHeight / logicalSize.Height * 96)
+                };
+                _parent.Paint?.Invoke(new Rect(0, 0, logicalSize.Width, logicalSize.Height));
+            }
+
+            void IAvnWindowBaseEvents.Resized(AvnSize size) => _parent.Resized?.Invoke(new Size(size.Width, size.Height));
+
+        }
+
+
+        public void Activate()
+        {
+        
+        }
+
+
+        public void Resize(Size clientSize)
+        {
+            _native.Resize(clientSize.Width, clientSize.Height);
+        }
+
+        public IRenderer CreateRenderer(IRenderRoot root)
+        {
+            return new ImmediateRenderer(root);
+        }
+
+        public void Dispose()
+        {
+            _native.Close();
+            _native.Dispose();
+            _native = null;
+        }
+
+
+        public void Invalidate(Rect rect)
+        {
+            //TODO;
+        }
+
+        public void SetInputRoot(IInputRoot inputRoot)
+        {
+            _inputRoot = inputRoot;
+        }
+
+
+        public void Show()
+        {
+            _native.Show();
+        }
+
+
+        #region Stubs
+        public double Scaling => 1;
+
+        public Point Position { get; set; }
+        public Action<Point> PositionChanged { get; set; }
+        public Action Deactivated { get; set; }
+        public Action Activated { get; set; }
+        public Action<RawInputEventArgs> Input { get; set; }
+
+        Action<double> ScalingChanged { get; set; }
+        public IPlatformHandle Handle => new PlatformHandle(IntPtr.Zero, "NOT SUPPORTED");
+
+        public Size MaxClientSize => new Size(1600, 900);
+
+        public IScreenImpl Screen => new ScreenImpl();
+
+        Action<double> ITopLevelImpl.ScalingChanged { get; set; }
+
+
+
+        public void SetTopmost(bool value)
+        {
+        }
+
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
+
+        public void SetCursor(IPlatformHandle cursor)
+        {
+        }
+
+
+
+        public void Hide()
+        {
+        }
+        public void BeginMoveDrag()
+        {
+        }
+
+        public void BeginResizeDrag(WindowEdge edge)
+        {
+        }
+
+        public Point PointToClient(Point point)
+        {
+            return point;
+        }
+
+        public Point PointToScreen(Point point)
+        {
+            return point;
+        }
+
+        #endregion
+    }
+}

+ 2 - 0
src/Avalonia.Native/regen.sh

@@ -0,0 +1,2 @@
+#!/bin/sh
+dotnet msbuild /t:Clean,GenerateSharpGenBindings

+ 2 - 0
src/headers/avalonia-native-guids.h

@@ -0,0 +1,2 @@
+#define COM_GUIDS_MATERIALIZE
+#include "avalonia-native.h"

+ 90 - 0
src/headers/avalonia-native.h

@@ -0,0 +1,90 @@
+#include "com.h"
+
+#define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
+
+struct IAvnWindowEvents;
+struct IAvnWindow;
+struct IAvnMacOptions;
+struct IAvnPlatformThreadingInterface;
+
+
+struct AvnSize
+{
+    double Width, Height;
+};
+
+struct AvnRect
+{
+    double X, Y, Width, Height;
+};
+
+AVNCOM(IAvaloniaNativeFactory, 01) : virtual IUnknown
+{
+public:
+    virtual HRESULT Initialize() = 0;
+    virtual IAvnMacOptions* GetMacOptions() = 0;
+    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) = 0;
+    virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0;
+};
+
+AVNCOM(IAvnWindowBase, 02) : virtual IUnknown
+{
+    virtual HRESULT Show() = 0;
+    virtual HRESULT Close() = 0;
+    virtual HRESULT GetClientSize(AvnSize*ret) = 0;
+    virtual HRESULT Resize(double width, double height) = 0;
+};
+
+AVNCOM(IAvnWindow, 03) : virtual IAvnWindowBase
+{
+    
+};
+
+AVNCOM(IAvnWindowBaseEvents, 04) : IUnknown
+{
+    virtual HRESULT SoftwareDraw(void* ptr, int stride, int pixelWidth, int pixelHeight, const AvnSize& logicalSize) = 0;
+    virtual void Closed() = 0;
+    virtual void Activated() = 0;
+    virtual void Deactivated() = 0;
+    virtual void Resized(const AvnSize& size) = 0;
+};
+
+
+AVNCOM(IAvnWindowEvents, 05) : IAvnWindowBaseEvents
+{
+
+};
+
+AVNCOM(IAvnMacOptions, 06) : virtual IUnknown
+{
+    virtual HRESULT SetShowInDock(int show) = 0;
+};
+
+AVNCOM(IAvnActionCallback, 07) : IUnknown
+{
+    virtual void Run() = 0;
+};
+
+AVNCOM(IAvnSignaledCallback, 08) : IUnknown
+{
+    virtual void Signaled(int priority, bool priorityContainsMeaningfulValue) = 0;
+};
+
+
+AVNCOM(IAvnLoopCancellation, 09) : virtual IUnknown
+{
+    virtual void Cancel() = 0;
+};
+
+AVNCOM(IAvnPlatformThreadingInterface, 0a) : virtual IUnknown
+{
+    virtual bool GetCurrentThreadIsLoopThread() = 0;
+    virtual void SetSignaledCallback(IAvnSignaledCallback* cb) = 0;
+    virtual IAvnLoopCancellation* CreateLoopCancellation() = 0;
+    virtual void RunLoop(IAvnLoopCancellation* cancel) = 0;
+    // Can't pass int* to sharpgentools for some reason
+    virtual void Signal(int priority) = 0;
+    virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback) = 0;
+};
+
+extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();

+ 200 - 0
src/headers/com.h

@@ -0,0 +1,200 @@
+#pragma clang diagnostic push
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#ifndef COM_H_INCLUDED
+#define COM_H_INCLUDED
+
+#include <cstring>
+
+typedef struct _GUID {
+    unsigned int  Data1;
+    unsigned short Data2;
+    unsigned short Data3;
+    unsigned char  Data4[ 8 ];
+} GUID;
+typedef GUID IID;
+typedef const IID* REFIID;
+typedef unsigned int HRESULT;
+typedef unsigned int DWORD;
+typedef DWORD ULONG;
+
+#define STDMETHODCALLTYPE
+
+#define S_OK                             0x0L
+
+#define E_NOTIMPL                        0x80004001L
+#define E_NOINTERFACE                    0x80004002L
+#define E_POINTER                        0x80004003L
+#define E_ABORT                          0x80004004L
+#define E_FAIL                           0x80004005L
+#define E_UNEXPECTED                     0x8000FFFFL
+#define E_HANDLE                         0x80070006L
+#define E_INVALIDARG                     0x80070057L
+
+struct IUnknown
+{
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+            REFIID riid,
+            void **ppvObject) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
+
+};
+
+#ifdef COM_GUIDS_MATERIALIZE
+#define __IID_DEF(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) extern "C" const GUID IID_ ## name = {0x ## d1, 0x ## d2, 0x ## d3, \
+{0x ## d41, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42 } };
+#else
+#define __IID_DEF(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) extern "C" const GUID IID_ ## name;
+#endif
+#define COMINTERFACE(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) __IID_DEF(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) \
+struct __attribute__((annotate("uuid(" #d1 "-" #d2 "-" #d3 "-" #d41 #d42 "-" #d43 #d44 #d45 #d46 #d47 #d48 ")" ))) name
+__IID_DEF(IUnknown, 0, 0, 0, C0, 00, 00, 00, 00, 00, 00, 46);
+
+class ComObject : public virtual IUnknown
+{
+private:
+    unsigned int _refCount;
+public:
+    
+    virtual ULONG AddRef()
+    {
+        _refCount++;
+        return _refCount;
+    }
+    
+    
+    virtual ULONG Release()
+    {
+        _refCount--;
+        ULONG rv = _refCount;
+        if(_refCount == 0)
+            delete(this);
+        return rv;
+    }
+    
+    ComObject()
+    {
+        _refCount = 1;
+        
+    }
+    virtual ~ComObject()
+    {
+    }
+    
+    
+    virtual ::HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) = 0;
+    
+    virtual ::HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
+                                                     void **ppvObject)
+    {
+        if(0 == memcmp(riid, &IID_IUnknown, sizeof(GUID)))
+            *ppvObject = (IUnknown*)this;
+        else
+        {
+            auto rv = QueryInterfaceImpl(riid, ppvObject);
+            if(rv != S_OK)
+                return rv;
+        }
+        _refCount++;
+        return S_OK;
+    }
+
+};
+
+
+#define BEGIN_INTERFACE_MAP() public: virtual HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject){
+#define INTERFACE_MAP_ENTRY(TInterface, IID) if(0 == memcmp(riid, &IID, sizeof(GUID))) { TInterface* casted = this; *ppvObject = casted; return S_OK; }
+#define END_INTERFACE_MAP() return E_NOINTERFACE; }
+#define INHERIT_INTERFACE_MAP(TBase) if(TBase::QueryInterfaceImpl(riid, ppvObject) == S_OK) return S_OK;
+
+class ComUnknownObject : public ComObject
+{
+    virtual ::HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) override
+    {
+        return E_NOINTERFACE;
+    };
+};
+
+template<class TInterface, GUID const* TIID> class ComSingleObject : public ComObject, public virtual TInterface
+{
+    BEGIN_INTERFACE_MAP()
+    INTERFACE_MAP_ENTRY(TInterface, *TIID)
+    END_INTERFACE_MAP()
+};
+
+template<class TInterface>
+class ComPtr
+{
+private:
+    TInterface* _obj;
+public:
+    ComPtr()
+    {
+        _obj = 0;
+    }
+    
+    ComPtr(TInterface* pObj)
+    {
+        _obj = 0;
+
+        if (pObj)
+        {
+            _obj = pObj;
+            _obj->AddRef();
+        }
+    }
+    
+    ComPtr(const ComPtr& ptr)
+    {
+        _obj = 0;
+        
+        if (ptr._obj)
+        {
+            _obj = ptr._obj;
+            _obj->AddRef();
+        }
+
+    }
+    
+    ComPtr& operator=(ComPtr other)
+    {
+        if(_obj != NULL)
+            _obj->Release();
+        _obj = other._obj;
+        if(_obj != NULL)
+            _obj->AddRef();
+        return *this;
+    }
+
+    ~ComPtr()
+    {
+        if (_obj)
+        {
+            _obj->Release();
+            _obj = 0;
+        }
+    }
+
+public:
+    operator TInterface*() const
+    {
+        return _obj;
+    }
+    TInterface& operator*() const
+    {
+        return *_obj;
+    }
+    TInterface** operator&()
+    {
+        return &_obj;
+    }
+    TInterface* operator->() const
+    {
+        return _obj;
+    }
+};
+
+#endif // COM_H_INCLUDED
+#pragma clang diagnostic pop