ソースを参照

Merge branch 'master' into fix-keybindings-foreach-crash

Steven Kirk 4 年 前
コミット
4b9f08227d
100 ファイル変更1703 行追加1517 行削除
  1. 32 0
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 8 0
      .github/ISSUE_TEMPLATE/config.yml
  3. 19 0
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 3 1
      .github/PULL_REQUEST_TEMPLATE.md
  5. 1 3
      .ncrunch/Avalonia.MicroCom.v3.ncrunchproject
  6. 3 0
      .ncrunch/Avalonia.Win32.v3.ncrunchproject
  7. 1 0
      .ncrunch/Direct3DInteropSample.v3.ncrunchproject
  8. 27 2
      Avalonia.sln
  9. 2 1
      Avalonia.sln.DotSettings
  10. 21 12
      Documentation/build.md
  11. 3 3
      azure-pipelines.yml
  12. 1 1
      build/AndroidWorkarounds.props
  13. 1 1
      build/ApiDiff.props
  14. 2 1
      build/EmbedXaml.props
  15. 2 2
      build/HarfBuzzSharp.props
  16. 1 1
      build/ReactiveUI.props
  17. 1 1
      build/Rx.props
  18. 3 3
      build/SharedVersion.props
  19. 22 1
      build/SourceLink.props
  20. 0 1020
      native/Avalonia.Native/inc/key.h
  21. 8 4
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  22. 1 0
      native/Avalonia.Native/src/OSX/AvnString.h
  23. 15 0
      native/Avalonia.Native/src/OSX/AvnString.mm
  24. 6 1
      native/Avalonia.Native/src/OSX/KeyTransform.h
  25. 151 0
      native/Avalonia.Native/src/OSX/KeyTransform.mm
  26. 2 8
      native/Avalonia.Native/src/OSX/Screens.mm
  27. 25 3
      native/Avalonia.Native/src/OSX/app.mm
  28. 1 1
      native/Avalonia.Native/src/OSX/clipboard.mm
  29. 5 2
      native/Avalonia.Native/src/OSX/common.h
  30. 22 0
      native/Avalonia.Native/src/OSX/cursor.mm
  31. 28 7
      native/Avalonia.Native/src/OSX/main.mm
  32. 6 5
      native/Avalonia.Native/src/OSX/menu.h
  33. 124 58
      native/Avalonia.Native/src/OSX/menu.mm
  34. 1 1
      native/Avalonia.Native/src/OSX/platformthreading.mm
  35. 20 2
      native/Avalonia.Native/src/OSX/rendertarget.mm
  36. 48 21
      native/Avalonia.Native/src/OSX/window.mm
  37. 19 55
      nukebuild/Build.cs
  38. 2 5
      nukebuild/BuildParameters.cs
  39. 1 2
      nukebuild/_build.csproj
  40. 8 4
      packages/Avalonia/Avalonia.csproj
  41. 11 6
      readme.md
  42. 0 2
      samples/BindingDemo/App.xaml.cs
  43. 1 2
      samples/BindingDemo/BindingDemo.csproj
  44. 2 2
      samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
  45. 2 2
      samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
  46. 6 6
      samples/BindingDemo/ViewModels/MainWindowViewModel.cs
  47. 4 4
      samples/BindingDemo/ViewModels/NestedCommandViewModel.cs
  48. 2 2
      samples/BindingDemo/ViewModels/TestItem.cs
  49. 8 6
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  50. 4 17
      samples/ControlCatalog.Android/MainActivity.cs
  51. 1 1
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  52. 23 36
      samples/ControlCatalog.Android/Resources/Resource.Designer.cs
  53. BIN
      samples/ControlCatalog.Android/Resources/drawable/Icon.png
  54. 13 0
      samples/ControlCatalog.Android/Resources/drawable/splash_screen.xml
  55. 0 13
      samples/ControlCatalog.Android/Resources/layout/Main.axml
  56. 0 5
      samples/ControlCatalog.Android/Resources/values/Strings.xml
  57. 4 0
      samples/ControlCatalog.Android/Resources/values/colors.xml
  58. 17 0
      samples/ControlCatalog.Android/Resources/values/styles.xml
  59. 32 0
      samples/ControlCatalog.Android/SplashActivity.cs
  60. 1 3
      samples/ControlCatalog.Desktop/Program.cs
  61. 5 1
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  62. 3 5
      samples/ControlCatalog.NetCore/Program.cs
  63. 10 2
      samples/ControlCatalog/App.xaml.cs
  64. BIN
      samples/ControlCatalog/Assets/Fonts/WenQuanYiMicroHei-01.ttf
  65. BIN
      samples/ControlCatalog/Assets/avalonia-32.png
  66. 2 2
      samples/ControlCatalog/ControlCatalog.csproj
  67. 13 17
      samples/ControlCatalog/DecoratedWindow.xaml
  68. 10 0
      samples/ControlCatalog/MainView.xaml
  69. 29 37
      samples/ControlCatalog/MainWindow.xaml
  70. 1 1
      samples/ControlCatalog/MainWindow.xaml.cs
  71. 4 4
      samples/ControlCatalog/Pages/AcrylicPage.xaml
  72. 102 0
      samples/ControlCatalog/Pages/ContextFlyoutPage.axaml
  73. 45 0
      samples/ControlCatalog/Pages/ContextFlyoutPage.axaml.cs
  74. 1 0
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  75. 29 0
      samples/ControlCatalog/Pages/CursorPage.xaml
  76. 20 0
      samples/ControlCatalog/Pages/CursorPage.xaml.cs
  77. 5 4
      samples/ControlCatalog/Pages/DataGridPage.xaml
  78. 4 2
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  79. 24 5
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  80. 264 0
      samples/ControlCatalog/Pages/FlyoutsPage.axaml
  81. 81 0
      samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs
  82. 0 1
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  83. 1 1
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  84. 0 1
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  85. 2 2
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs
  86. 7 0
      samples/ControlCatalog/Pages/ProgressBarPage.xaml
  87. 7 9
      samples/ControlCatalog/Pages/ScreenPage.cs
  88. 2 2
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs
  89. 29 0
      samples/ControlCatalog/Pages/SliderPage.xaml
  90. 2 2
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  91. 4 1
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  92. 6 0
      samples/ControlCatalog/Pages/TextBoxPage.xaml.cs
  93. 26 1
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  94. 23 53
      samples/ControlCatalog/Pages/ViewboxPage.xaml
  95. 20 1
      samples/ControlCatalog/Pages/ViewboxPage.xaml.cs
  96. 78 0
      samples/ControlCatalog/ViewModels/ContextFlyoutPageViewModel.cs
  97. 7 7
      samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs
  98. 44 0
      samples/ControlCatalog/ViewModels/CursorPageViewModel.cs
  99. 3 3
      samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
  100. 13 14
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

+ 32 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a report to help us improve Avalonia
+title: ''
+labels: bug
+assignees: ''
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+
+- OS: [e.g. Windows, Mac, Linux (State distribution)]
+- Version [e.g. 0.10.0-rc1 or 0.9.12]
+
+**Additional context**
+Add any other context about the problem here.

+ 8 - 0
.github/ISSUE_TEMPLATE/config.yml

@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+  - name: Questions, Discussions, Ideas
+    url: https://github.com/AvaloniaUI/Avalonia/discussions/new
+    about: Please ask and answer questions here.
+  - name: Avalonia Community Support on Gitter
+    url: https://gitter.im/AvaloniaUI/Avalonia
+    about: Please ask and answer questions here.

+ 19 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,19 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.

+ 3 - 1
.github/PULL_REQUEST_TEMPLATE.md

@@ -18,11 +18,13 @@
 
 - [ ] Added unit tests (if possible)?
 - [ ] Added XML documentation to any related classes?
-- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Avaloniaui.net with user documentation
+- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Documentation with user documentation
 
 ## Breaking changes
 <!--- List any breaking changes here. When the PR is merged please add an entry to https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes -->
 
+## Obsoletions / Deprecations
+<!--- Obsolete and Deprecated attributes on APIs MUST only be included when discussed with Core team. @grokys, @kekekeks & @danwalmsley -->
 
 ## Fixed issues
 <!--- If the pull request fixes issue(s) list them like this: 

+ 1 - 3
.ncrunch/Avalonia.MicroCom.v3.ncrunchproject

@@ -1,5 +1,3 @@
 <ProjectConfiguration>
-  <Settings>
-    <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
-  </Settings>
+  <Settings />
 </ProjectConfiguration>

+ 3 - 0
.ncrunch/Avalonia.Win32.v3.ncrunchproject

@@ -1,5 +1,8 @@
 <ProjectConfiguration>
   <Settings>
+    <AdditionalFilesToIncludeForProject>
+      <Value>..\..\tools\MicroComGenerator\bin\Debug\netcoreapp3.1\**.*</Value>
+    </AdditionalFilesToIncludeForProject>
     <HiddenComponentWarnings>
       <Value>MissingOrIgnoredProjectReference</Value>
     </HiddenComponentWarnings>

+ 1 - 0
.ncrunch/Direct3DInteropSample.v3.ncrunchproject

@@ -3,6 +3,7 @@
     <HiddenComponentWarnings>
       <Value>MissingOrIgnoredProjectReference</Value>
     </HiddenComponentWarnings>
+    <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
     <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
   </Settings>
 </ProjectConfiguration>

+ 27 - 2
Avalonia.sln

@@ -222,14 +222,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.Vnc", "sr
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.Loader", "src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj", "{909A8CBD-7D0E-42FD-B841-022AD8925820}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.Events", "src\Avalonia.ReactiveUI.Events\Avalonia.ReactiveUI.Events.csproj", "{28F18757-C3E6-4BBE-A37D-11BA2AB9177C}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox", "samples\Sandbox\Sandbox.csproj", "{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroComGenerator", "src\tools\MicroComGenerator\MicroComGenerator.csproj", "{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}"
+EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@@ -2116,6 +2116,30 @@ Global
 		{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.Build.0 = Release|Any CPU
 		{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.Build.0 = Release|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2176,6 +2200,7 @@ Global
 		{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
 		{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
+		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

+ 2 - 1
Avalonia.sln.DotSettings

@@ -38,4 +38,5 @@
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EDaemon_002ESettings_002EMigration_002ESwaWarningsModeSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
-	<s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+	<s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/UserDictionary/Words/=Fcitx/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

+ 21 - 12
Documentation/build.md

@@ -9,10 +9,24 @@ git clone https://github.com/AvaloniaUI/Avalonia.git
 git submodule update --init
 ```
 
+### Install the required version of the .NET Core SDK
+
+Go to https://dotnet.microsoft.com/download/visual-studio-sdks and install the latest version of the .NET Core SDK compatible with Avalonia UI. Make sure to download the SDK (not just the "runtime") package. The version compatible is indicated within the [global.json](https://github.com/AvaloniaUI/Avalonia/blob/master/global.json) file. Note that Avalonia UI does not always use the latest version and is hardcoded to use the last version known to be compatible (SDK releases may break the builds from time-to-time).
+
 ###  Open in Visual Studio
 
-Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community
-edition works fine. Run the `Samples\ControlCatalog.Desktop` project to see the sample application.
+Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community edition works fine. Build and run the `Samples\ControlCatalog.Desktop` or `ControlCatalog.NetCore` project to see the sample application.
+
+### Troubleshooting
+
+ * **Error CS0006: Avalonia.DesktopRuntime.dll could not be found**
+
+    It is common for the first build to fail with the errors below (also discussed in [#4257](https://github.com/AvaloniaUI/Avalonia/issues/4257)).
+    ```
+    >CSC : error CS0006: Metadata file 'C:\...\Avalonia\src\Avalonia.DesktopRuntime\bin\Debug\netcoreapp2.0\Avalonia.DesktopRuntime.dll' could not be found
+    >CSC : error CS0006: Metadata file 'C:\...\Avalonia\packages\Avalonia\bin\Debug\netcoreapp2.0\Avalonia.dll' could not be found
+    ```
+    To correct this, right click on the `Avalonia.DesktopRuntime` project then press `Build` to build the project manually. Afterwards the solution should build normally and the ControlCatalog can be run.
 
 # Linux/macOS
 
@@ -20,9 +34,9 @@ It's *not* possible to build the *whole* project on Linux/macOS. You can only bu
 
 MonoDevelop, Xamarin Studio and Visual Studio for Mac aren't capable of properly opening our solution. You can use Rider (at least 2017.2 EAP) or VSCode instead. They will fail to load most of platform specific projects, but you don't need them to run on .NET Core.
 
-###  Install the latest version of .NET Core
+###  Install the latest version of the .NET Core SDK
 
-Go to https://www.microsoft.com/net/core and follow instructions for your OS. You need SDK (not just "runtime") package.
+Go to https://www.microsoft.com/net/core and follow the instructions for your OS. Make sure to download the SDK (not just the "runtime") package.
 
 ###  Additional requirements for macOS
 
@@ -60,15 +74,10 @@ git submodule update --init --recursive
 
 ### Build native libraries (macOS only)
 
-On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/).  The steps to get this working correctly are:
-- (for revisions after 2 Nov 2020) Run `./build.sh GenerateCppHeaders` to generate `avalonia-native.h` from `avn.idl`
-- Navigate to the Avalonia/native/Avalonia.Native/src/OSX folder and open the `Avalonia.Native.OSX.xcodeproj` project
-- Build the library via the Product->Build menu.  This will generate binaries in your local path under ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-*guid* where "guid" is uniquely generated every time you build.
-- Manually install the native library by copying it from the build artifacts folder into the shared dynamic library path:
+On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). Execute the build script in the root project with the `CompileNative` task. It will build the headers, build the libraries, and place them in the appropriate place to allow .NET to find them at compilation and run time.
 
-```
-cd ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-[guid]/Build/Products/Debug
-cp libAvalonia.Native.OSX.dylib /usr/local/lib/libAvaloniaNative.dylib
+```bash
+./build.sh CompileNative
 ```
 
 ###  Build and Run Avalonia

+ 3 - 3
azure-pipelines.yml

@@ -27,7 +27,7 @@ jobs:
   variables:
     SolutionDir: '$(Build.SourcesDirectory)'
   pool:
-    vmImage: 'macOS-10.14'
+    vmImage: 'macOS-10.15'
   steps:
   - task: UseDotNet@2
     displayName: 'Use .NET Core SDK 3.1.401'
@@ -51,10 +51,10 @@ jobs:
     inputs:
       actions: 'build'
       scheme: ''
-      sdk: 'macosx10.14'
+      sdk: 'macosx11.1'
       configuration: 'Release'
       xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
-      xcodeVersion: '10' # Options: 8, 9, default, specifyPath
+      xcodeVersion: '12' # Options: 8, 9, default, specifyPath
       args: '-derivedDataPath ./'
 
   - task: CmdLine@2

+ 1 - 1
build/AndroidWorkarounds.props

@@ -2,7 +2,7 @@
   <ItemGroup Condition="'$(AndroidApplication)' == 'true'">
     <!-- WORKAROUND: The packages below are transitively referenced by System.Memory,
       but Xamarin.Android applications need the newest versions directly referenced for the linker. -->
-    <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
+    <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.6.0" />
     <PackageReference Include="System.Buffers" Version="4.5.0" />
   </ItemGroup>
   <Target Name="_RemoveNonExistingResgenFile" BeforeTargets="CoreCompile" Condition="'$(_SdkSetAndroidResgenFile)' == 'true' And '$(AndroidResgenFile)' != '' And !Exists('$(AndroidResgenFile)')">

+ 1 - 1
build/ApiDiff.props

@@ -1,6 +1,6 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
-    <ApiContractPackageVersion>0.10.0-preview3</ApiContractPackageVersion>
+    <ApiContractPackageVersion>0.10.0</ApiContractPackageVersion>
     <NugetPackageName Condition="'$(PackageId)' != ''">$(PackageId)</NugetPackageName>
     <NugetPackageName Condition="'$(PackageId)' == ''">Avalonia</NugetPackageName>
   </PropertyGroup>

+ 2 - 1
build/EmbedXaml.props

@@ -4,8 +4,9 @@
      <Compile Update="**\*.xaml.cs">
       <DependentUpon>%(Filename)</DependentUpon>
     </Compile>
+    <None Remove="**\*.xaml"/>
     <AvaloniaResource Include="**\*.xaml">
       <SubType>Designer</SubType>
     </AvaloniaResource>
   </ItemGroup>
-</Project>
+</Project>

+ 2 - 2
build/HarfBuzzSharp.props

@@ -1,6 +1,6 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="HarfBuzzSharp" Version="2.6.1.6" />
-    <PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.6.1.6" />
+    <PackageReference Include="HarfBuzzSharp" Version="2.6.1.7" />
+    <PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.6.1.7" />
   </ItemGroup>
 </Project>

+ 1 - 1
build/ReactiveUI.props

@@ -1,5 +1,5 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="ReactiveUI" Version="12.1.1" />
+    <PackageReference Include="ReactiveUI" Version="13.2.10" />
   </ItemGroup>
 </Project>

+ 1 - 1
build/Rx.props

@@ -1,5 +1,5 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="System.Reactive" Version="4.4.1" />
+    <PackageReference Include="System.Reactive" Version="5.0" />
   </ItemGroup>
 </Project>

+ 3 - 3
build/SharedVersion.props

@@ -3,7 +3,7 @@
   <PropertyGroup>
     <Product>Avalonia</Product>
     <Version>0.10.999</Version>
-    <Copyright>Copyright 2020 &#169; The AvaloniaUI Project</Copyright>
+    <Copyright>Copyright 2021 &#169; The AvaloniaUI Project</Copyright>
     <PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
     <RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -16,11 +16,11 @@
     <PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes>
     <RepositoryType>git</RepositoryType>
     <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
-    <SignAssembly>false</SignAssembly>
+    <SignAssembly>true</SignAssembly>
     <DefineConstants Condition="$(SignAssembly) == true">$(DefineConstants);SIGNED_BUILD</DefineConstants>
   </PropertyGroup>
 
   <ItemGroup Label="PackageIcon">
-    <None Include="$(MSBuildThisFileDirectory)/Assets/Icon.png" Pack="true" PackagePath=""/>
+    <None Include="$(MSBuildThisFileDirectory)/Assets/Icon.png" Pack="true" Visible="false" PackagePath=""/>
   </ItemGroup>
 </Project>

+ 22 - 1
build/SourceLink.props

@@ -1,5 +1,26 @@
 <Project>
+  <PropertyGroup>
+    <PublishRepositoryUrl>true</PublishRepositoryUrl>
+    <IncludeSymbols>false</IncludeSymbols>
+    <EmbedUntrackedSources>true</EmbedUntrackedSources>
+    <DebugType>embedded</DebugType>
+    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
+    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
+    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
+  </PropertyGroup>
+  
   <ItemGroup>
-    <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="All" />
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
+  </ItemGroup>
+
+  <!-- Workaround for https://github.com/dotnet/sdk/issues/11105 -->
+  <ItemGroup>
+    <SourceRoot Include="$(NuGetPackageRoot)" Condition="'$(NuGetPackageRoot)' != ''" />
   </ItemGroup>
 </Project>

+ 0 - 1020
native/Avalonia.Native/inc/key.h

@@ -1,1020 +0,0 @@
-#ifndef _KEY_H_
-#define _KEY_H_
-
-/// <summary>
-/// Defines the keys available on a keyboard.
-/// </summary>
-enum AvnKey
-{
-    /// <summary>
-    /// No key pressed.
-    /// </summary>
-    AvnKeyNone = 0,
-    
-    /// <summary>
-    /// The Cancel key.
-    /// </summary>
-    AvnKeyCancel = 1,
-    
-    /// <summary>
-    /// The Back key.
-    /// </summary>
-    AvnKeyBack = 2,
-    
-    /// <summary>
-    /// The Tab key.
-    /// </summary>
-    AvnKeyTab = 3,
-    
-    /// <summary>
-    /// The Linefeed key.
-    /// </summary>
-    AvnKeyLineFeed = 4,
-    
-    /// <summary>
-    /// The Clear key.
-    /// </summary>
-    AvnKeyClear = 5,
-    
-    /// <summary>
-    /// The Return key.
-    /// </summary>
-    AvnKeyReturn = 6,
-    
-    /// <summary>
-    /// The Enter key.
-    /// </summary>
-    AvnKeyEnter = 6,
-    
-    /// <summary>
-    /// The Pause key.
-    /// </summary>
-    AvnKeyPause = 7,
-    
-    /// <summary>
-    /// The Caps Lock key.
-    /// </summary>
-    AvnKeyCapsLock = 8,
-    
-    /// <summary>
-    /// The Caps Lock key.
-    /// </summary>
-    AvnKeyCapital = 8,
-    
-    /// <summary>
-    /// The IME Hangul mode key.
-    /// </summary>
-    AvnKeyHangulMode = 9,
-    
-    /// <summary>
-    /// The IME Kana mode key.
-    /// </summary>
-    AvnKeyKanaMode = 9,
-    
-    /// <summary>
-    /// The IME Junja mode key.
-    /// </summary>
-    AvnKeyJunjaMode = 10,
-    
-    /// <summary>
-    /// The IME Final mode key.
-    /// </summary>
-    AvnKeyFinalMode = 11,
-    
-    /// <summary>
-    /// The IME Kanji mode key.
-    /// </summary>
-    AvnKeyKanjiMode = 12,
-    
-    /// <summary>
-    /// The IME Hanja mode key.
-    /// </summary>
-    HanjaMode = 12,
-    
-    /// <summary>
-    /// The Escape key.
-    /// </summary>
-    Escape = 13,
-    
-    /// <summary>
-    /// The IME Convert key.
-    /// </summary>
-    ImeConvert = 14,
-    
-    /// <summary>
-    /// The IME NonConvert key.
-    /// </summary>
-    ImeNonConvert = 15,
-    
-    /// <summary>
-    /// The IME Accept key.
-    /// </summary>
-    ImeAccept = 16,
-    
-    /// <summary>
-    /// The IME Mode change key.
-    /// </summary>
-    ImeModeChange = 17,
-    
-    /// <summary>
-    /// The space bar.
-    /// </summary>
-    Space = 18,
-    
-    /// <summary>
-    /// The Page Up key.
-    /// </summary>
-    PageUp = 19,
-    
-    /// <summary>
-    /// The Page Up key.
-    /// </summary>
-    Prior = 19,
-    
-    /// <summary>
-    /// The Page Down key.
-    /// </summary>
-    PageDown = 20,
-    
-    /// <summary>
-    /// The Page Down key.
-    /// </summary>
-    Next = 20,
-    
-    /// <summary>
-    /// The End key.
-    /// </summary>
-    End = 21,
-    
-    /// <summary>
-    /// The Home key.
-    /// </summary>
-    Home = 22,
-    
-    /// <summary>
-    /// The Left arrow key.
-    /// </summary>
-    Left = 23,
-    
-    /// <summary>
-    /// The Up arrow key.
-    /// </summary>
-    Up = 24,
-    
-    /// <summary>
-    /// The Right arrow key.
-    /// </summary>
-    Right = 25,
-    
-    /// <summary>
-    /// The Down arrow key.
-    /// </summary>
-    Down = 26,
-    
-    /// <summary>
-    /// The Select key.
-    /// </summary>
-    Select = 27,
-    
-    /// <summary>
-    /// The Print key.
-    /// </summary>
-    Print = 28,
-    
-    /// <summary>
-    /// The Execute key.
-    /// </summary>
-    Execute = 29,
-    
-    /// <summary>
-    /// The Print Screen key.
-    /// </summary>
-    Snapshot = 30,
-    
-    /// <summary>
-    /// The Print Screen key.
-    /// </summary>
-    PrintScreen = 30,
-    
-    /// <summary>
-    /// The Insert key.
-    /// </summary>
-    Insert = 31,
-    
-    /// <summary>
-    /// The Delete key.
-    /// </summary>
-    Delete = 32,
-    
-    /// <summary>
-    /// The Help key.
-    /// </summary>
-    Help = 33,
-    
-    /// <summary>
-    /// The 0 key.
-    /// </summary>
-    D0 = 34,
-    
-    /// <summary>
-    /// The 1 key.
-    /// </summary>
-    D1 = 35,
-    
-    /// <summary>
-    /// The 2 key.
-    /// </summary>
-    D2 = 36,
-    
-    /// <summary>
-    /// The 3 key.
-    /// </summary>
-    D3 = 37,
-    
-    /// <summary>
-    /// The 4 key.
-    /// </summary>
-    D4 = 38,
-    
-    /// <summary>
-    /// The 5 key.
-    /// </summary>
-    D5 = 39,
-    
-    /// <summary>
-    /// The 6 key.
-    /// </summary>
-    D6 = 40,
-    
-    /// <summary>
-    /// The 7 key.
-    /// </summary>
-    D7 = 41,
-    
-    /// <summary>
-    /// The 8 key.
-    /// </summary>
-    D8 = 42,
-    
-    /// <summary>
-    /// The 9 key.
-    /// </summary>
-    D9 = 43,
-    
-    /// <summary>
-    /// The A key.
-    /// </summary>
-    A = 44,
-    
-    /// <summary>
-    /// The B key.
-    /// </summary>
-    B = 45,
-    
-    /// <summary>
-    /// The C key.
-    /// </summary>
-    C = 46,
-    
-    /// <summary>
-    /// The D key.
-    /// </summary>
-    D = 47,
-    
-    /// <summary>
-    /// The E key.
-    /// </summary>
-    E = 48,
-    
-    /// <summary>
-    /// The F key.
-    /// </summary>
-    F = 49,
-    
-    /// <summary>
-    /// The G key.
-    /// </summary>
-    G = 50,
-    
-    /// <summary>
-    /// The H key.
-    /// </summary>
-    H = 51,
-    
-    /// <summary>
-    /// The I key.
-    /// </summary>
-    I = 52,
-    
-    /// <summary>
-    /// The J key.
-    /// </summary>
-    J = 53,
-    
-    /// <summary>
-    /// The K key.
-    /// </summary>
-    AvnKeyK = 54,
-    
-    /// <summary>
-    /// The L key.
-    /// </summary>
-    L = 55,
-    
-    /// <summary>
-    /// The M key.
-    /// </summary>
-    M = 56,
-    
-    /// <summary>
-    /// The N key.
-    /// </summary>
-    N = 57,
-    
-    /// <summary>
-    /// The O key.
-    /// </summary>
-    O = 58,
-    
-    /// <summary>
-    /// The P key.
-    /// </summary>
-    P = 59,
-    
-    /// <summary>
-    /// The Q key.
-    /// </summary>
-    Q = 60,
-    
-    /// <summary>
-    /// The R key.
-    /// </summary>
-    R = 61,
-    
-    /// <summary>
-    /// The S key.
-    /// </summary>
-    S = 62,
-    
-    /// <summary>
-    /// The T key.
-    /// </summary>
-    T = 63,
-    
-    /// <summary>
-    /// The U key.
-    /// </summary>
-    U = 64,
-    
-    /// <summary>
-    /// The V key.
-    /// </summary>
-    V = 65,
-    
-    /// <summary>
-    /// The W key.
-    /// </summary>
-    W = 66,
-    
-    /// <summary>
-    /// The X key.
-    /// </summary>
-    X = 67,
-    
-    /// <summary>
-    /// The Y key.
-    /// </summary>
-    Y = 68,
-    
-    /// <summary>
-    /// The Z key.
-    /// </summary>
-    Z = 69,
-    
-    /// <summary>
-    /// The left Windows key.
-    /// </summary>
-    LWin = 70,
-    
-    /// <summary>
-    /// The right Windows key.
-    /// </summary>
-    RWin = 71,
-    
-    /// <summary>
-    /// The Application key.
-    /// </summary>
-    Apps = 72,
-    
-    /// <summary>
-    /// The Sleep key.
-    /// </summary>
-    Sleep = 73,
-    
-    /// <summary>
-    /// The 0 key on the numeric keypad.
-    /// </summary>
-    NumPad0 = 74,
-    
-    /// <summary>
-    /// The 1 key on the numeric keypad.
-    /// </summary>
-    NumPad1 = 75,
-    
-    /// <summary>
-    /// The 2 key on the numeric keypad.
-    /// </summary>
-    NumPad2 = 76,
-    
-    /// <summary>
-    /// The 3 key on the numeric keypad.
-    /// </summary>
-    NumPad3 = 77,
-    
-    /// <summary>
-    /// The 4 key on the numeric keypad.
-    /// </summary>
-    NumPad4 = 78,
-    
-    /// <summary>
-    /// The 5 key on the numeric keypad.
-    /// </summary>
-    NumPad5 = 79,
-    
-    /// <summary>
-    /// The 6 key on the numeric keypad.
-    /// </summary>
-    NumPad6 = 80,
-    
-    /// <summary>
-    /// The 7 key on the numeric keypad.
-    /// </summary>
-    NumPad7 = 81,
-    
-    /// <summary>
-    /// The 8 key on the numeric keypad.
-    /// </summary>
-    NumPad8 = 82,
-    
-    /// <summary>
-    /// The 9 key on the numeric keypad.
-    /// </summary>
-    NumPad9 = 83,
-    
-    /// <summary>
-    /// The Multiply key.
-    /// </summary>
-    Multiply = 84,
-    
-    /// <summary>
-    /// The Add key.
-    /// </summary>
-    Add = 85,
-    
-    /// <summary>
-    /// The Separator key.
-    /// </summary>
-    Separator = 86,
-    
-    /// <summary>
-    /// The Subtract key.
-    /// </summary>
-    Subtract = 87,
-    
-    /// <summary>
-    /// The Decimal key.
-    /// </summary>
-    Decimal = 88,
-    
-    /// <summary>
-    /// The Divide key.
-    /// </summary>
-    Divide = 89,
-    
-    /// <summary>
-    /// The F1 key.
-    /// </summary>
-    F1 = 90,
-    
-    /// <summary>
-    /// The F2 key.
-    /// </summary>
-    F2 = 91,
-    
-    /// <summary>
-    /// The F3 key.
-    /// </summary>
-    F3 = 92,
-    
-    /// <summary>
-    /// The F4 key.
-    /// </summary>
-    F4 = 93,
-    
-    /// <summary>
-    /// The F5 key.
-    /// </summary>
-    F5 = 94,
-    
-    /// <summary>
-    /// The F6 key.
-    /// </summary>
-    F6 = 95,
-    
-    /// <summary>
-    /// The F7 key.
-    /// </summary>
-    F7 = 96,
-    
-    /// <summary>
-    /// The F8 key.
-    /// </summary>
-    F8 = 97,
-    
-    /// <summary>
-    /// The F9 key.
-    /// </summary>
-    F9 = 98,
-    
-    /// <summary>
-    /// The F10 key.
-    /// </summary>
-    F10 = 99,
-    
-    /// <summary>
-    /// The F11 key.
-    /// </summary>
-    F11 = 100,
-    
-    /// <summary>
-    /// The F12 key.
-    /// </summary>
-    F12 = 101,
-    
-    /// <summary>
-    /// The F13 key.
-    /// </summary>
-    F13 = 102,
-    
-    /// <summary>
-    /// The F14 key.
-    /// </summary>
-    F14 = 103,
-    
-    /// <summary>
-    /// The F15 key.
-    /// </summary>
-    F15 = 104,
-    
-    /// <summary>
-    /// The F16 key.
-    /// </summary>
-    F16 = 105,
-    
-    /// <summary>
-    /// The F17 key.
-    /// </summary>
-    F17 = 106,
-    
-    /// <summary>
-    /// The F18 key.
-    /// </summary>
-    F18 = 107,
-    
-    /// <summary>
-    /// The F19 key.
-    /// </summary>
-    F19 = 108,
-    
-    /// <summary>
-    /// The F20 key.
-    /// </summary>
-    F20 = 109,
-    
-    /// <summary>
-    /// The F21 key.
-    /// </summary>
-    F21 = 110,
-    
-    /// <summary>
-    /// The F22 key.
-    /// </summary>
-    F22 = 111,
-    
-    /// <summary>
-    /// The F23 key.
-    /// </summary>
-    F23 = 112,
-    
-    /// <summary>
-    /// The F24 key.
-    /// </summary>
-    F24 = 113,
-    
-    /// <summary>
-    /// The Numlock key.
-    /// </summary>
-    NumLock = 114,
-    
-    /// <summary>
-    /// The Scroll key.
-    /// </summary>
-    Scroll = 115,
-    
-    /// <summary>
-    /// The left Shift key.
-    /// </summary>
-    LeftShift = 116,
-    
-    /// <summary>
-    /// The right Shift key.
-    /// </summary>
-    RightShift = 117,
-    
-    /// <summary>
-    /// The left Ctrl key.
-    /// </summary>
-    LeftCtrl = 118,
-    
-    /// <summary>
-    /// The right Ctrl key.
-    /// </summary>
-    RightCtrl = 119,
-    
-    /// <summary>
-    /// The left Alt key.
-    /// </summary>
-    LeftAlt = 120,
-    
-    /// <summary>
-    /// The right Alt key.
-    /// </summary>
-    RightAlt = 121,
-    
-    /// <summary>
-    /// The browser Back key.
-    /// </summary>
-    BrowserBack = 122,
-    
-    /// <summary>
-    /// The browser Forward key.
-    /// </summary>
-    BrowserForward = 123,
-    
-    /// <summary>
-    /// The browser Refresh key.
-    /// </summary>
-    BrowserRefresh = 124,
-    
-    /// <summary>
-    /// The browser Stop key.
-    /// </summary>
-    BrowserStop = 125,
-    
-    /// <summary>
-    /// The browser Search key.
-    /// </summary>
-    BrowserSearch = 126,
-    
-    /// <summary>
-    /// The browser Favorites key.
-    /// </summary>
-    BrowserFavorites = 127,
-    
-    /// <summary>
-    /// The browser Home key.
-    /// </summary>
-    BrowserHome = 128,
-    
-    /// <summary>
-    /// The Volume Mute key.
-    /// </summary>
-    VolumeMute = 129,
-    
-    /// <summary>
-    /// The Volume Down key.
-    /// </summary>
-    VolumeDown = 130,
-    
-    /// <summary>
-    /// The Volume Up key.
-    /// </summary>
-    VolumeUp = 131,
-    
-    /// <summary>
-    /// The media Next Track key.
-    /// </summary>
-    MediaNextTrack = 132,
-    
-    /// <summary>
-    /// The media Previous Track key.
-    /// </summary>
-    MediaPreviousTrack = 133,
-    
-    /// <summary>
-    /// The media Stop key.
-    /// </summary>
-    MediaStop = 134,
-    
-    /// <summary>
-    /// The media Play/Pause key.
-    /// </summary>
-    MediaPlayPause = 135,
-    
-    /// <summary>
-    /// The Launch Mail key.
-    /// </summary>
-    LaunchMail = 136,
-    
-    /// <summary>
-    /// The Select Media key.
-    /// </summary>
-    SelectMedia = 137,
-    
-    /// <summary>
-    /// The Launch Application 1 key.
-    /// </summary>
-    LaunchApplication1 = 138,
-    
-    /// <summary>
-    /// The Launch Application 2 key.
-    /// </summary>
-    LaunchApplication2 = 139,
-    
-    /// <summary>
-    /// The OEM Semicolon key.
-    /// </summary>
-    OemSemicolon = 140,
-    
-    /// <summary>
-    /// The OEM 1 key.
-    /// </summary>
-    Oem1 = 140,
-    
-    /// <summary>
-    /// The OEM Plus key.
-    /// </summary>
-    OemPlus = 141,
-    
-    /// <summary>
-    /// The OEM Comma key.
-    /// </summary>
-    OemComma = 142,
-    
-    /// <summary>
-    /// The OEM Minus key.
-    /// </summary>
-    OemMinus = 143,
-    
-    /// <summary>
-    /// The OEM Period key.
-    /// </summary>
-    OemPeriod = 144,
-    
-    /// <summary>
-    /// The OEM Question Mark key.
-    /// </summary>
-    OemQuestion = 145,
-    
-    /// <summary>
-    /// The OEM 2 key.
-    /// </summary>
-    Oem2 = 145,
-    
-    /// <summary>
-    /// The OEM Tilde key.
-    /// </summary>
-    OemTilde = 146,
-    
-    /// <summary>
-    /// The OEM 3 key.
-    /// </summary>
-    Oem3 = 146,
-    
-    /// <summary>
-    /// The ABNT_C1 (Brazilian) key.
-    /// </summary>
-    AbntC1 = 147,
-    
-    /// <summary>
-    /// The ABNT_C2 (Brazilian) key.
-    /// </summary>
-    AbntC2 = 148,
-    
-    /// <summary>
-    /// The OEM Open Brackets key.
-    /// </summary>
-    OemOpenBrackets = 149,
-    
-    /// <summary>
-    /// The OEM 4 key.
-    /// </summary>
-    Oem4 = 149,
-    
-    /// <summary>
-    /// The OEM Pipe key.
-    /// </summary>
-    OemPipe = 150,
-    
-    /// <summary>
-    /// The OEM 5 key.
-    /// </summary>
-    Oem5 = 150,
-    
-    /// <summary>
-    /// The OEM Close Brackets key.
-    /// </summary>
-    OemCloseBrackets = 151,
-    
-    /// <summary>
-    /// The OEM 6 key.
-    /// </summary>
-    Oem6 = 151,
-    
-    /// <summary>
-    /// The OEM Quotes key.
-    /// </summary>
-    OemQuotes = 152,
-    
-    /// <summary>
-    /// The OEM 7 key.
-    /// </summary>
-    Oem7 = 152,
-    
-    /// <summary>
-    /// The OEM 8 key.
-    /// </summary>
-    Oem8 = 153,
-    
-    /// <summary>
-    /// The OEM Backslash key.
-    /// </summary>
-    OemBackslash = 154,
-    
-    /// <summary>
-    /// The OEM 3 key.
-    /// </summary>
-    Oem102 = 154,
-    
-    /// <summary>
-    /// A special key masking the real key being processed by an IME.
-    /// </summary>
-    ImeProcessed = 155,
-    
-    /// <summary>
-    /// A special key masking the real key being processed as a system key.
-    /// </summary>
-    System = 156,
-    
-    /// <summary>
-    /// The OEM ATTN key.
-    /// </summary>
-    OemAttn = 157,
-    
-    /// <summary>
-    /// The DBE_ALPHANUMERIC key.
-    /// </summary>
-    DbeAlphanumeric = 157,
-    
-    /// <summary>
-    /// The OEM Finish key.
-    /// </summary>
-    OemFinish = 158,
-    
-    /// <summary>
-    /// The DBE_KATAKANA key.
-    /// </summary>
-    DbeKatakana = 158,
-    
-    /// <summary>
-    /// The DBE_HIRAGANA key.
-    /// </summary>
-    DbeHiragana = 159,
-    
-    /// <summary>
-    /// The OEM Copy key.
-    /// </summary>
-    OemCopy = 159,
-    
-    /// <summary>
-    /// The DBE_SBCSCHAR key.
-    /// </summary>
-    DbeSbcsChar = 160,
-    
-    /// <summary>
-    /// The OEM Auto key.
-    /// </summary>
-    OemAuto = 160,
-    
-    /// <summary>
-    /// The DBE_DBCSCHAR key.
-    /// </summary>
-    DbeDbcsChar = 161,
-    
-    /// <summary>
-    /// The OEM ENLW key.
-    /// </summary>
-    OemEnlw = 161,
-    
-    /// <summary>
-    /// The OEM BackTab key.
-    /// </summary>
-    OemBackTab = 162,
-    
-    /// <summary>
-    /// The DBE_ROMAN key.
-    /// </summary>
-    DbeRoman = 162,
-    
-    /// <summary>
-    /// The DBE_NOROMAN key.
-    /// </summary>
-    DbeNoRoman = 163,
-    
-    /// <summary>
-    /// The ATTN key.
-    /// </summary>
-    Attn = 163,
-    
-    /// <summary>
-    /// The CRSEL key.
-    /// </summary>
-    CrSel = 164,
-    
-    /// <summary>
-    /// The DBE_ENTERWORDREGISTERMODE key.
-    /// </summary>
-    DbeEnterWordRegisterMode = 164,
-    
-    /// <summary>
-    /// The EXSEL key.
-    /// </summary>
-    ExSel = 165,
-    
-    /// <summary>
-    /// The DBE_ENTERIMECONFIGMODE key.
-    /// </summary>
-    DbeEnterImeConfigureMode = 165,
-    
-    /// <summary>
-    /// The ERASE EOF Key.
-    /// </summary>
-    EraseEof = 166,
-    
-    /// <summary>
-    /// The DBE_FLUSHSTRING key.
-    /// </summary>
-    DbeFlushString = 166,
-    
-    /// <summary>
-    /// The Play key.
-    /// </summary>
-    Play = 167,
-    
-    /// <summary>
-    /// The DBE_CODEINPUT key.
-    /// </summary>
-    DbeCodeInput = 167,
-    
-    /// <summary>
-    /// The DBE_NOCODEINPUT key.
-    /// </summary>
-    DbeNoCodeInput = 168,
-    
-    /// <summary>
-    /// The Zoom key.
-    /// </summary>
-    Zoom = 168,
-    
-    /// <summary>
-    /// Reserved for future use.
-    /// </summary>
-    NoName = 169,
-    
-    /// <summary>
-    /// The DBE_DETERMINESTRING key.
-    /// </summary>
-    DbeDetermineString = 169,
-    
-    /// <summary>
-    /// The DBE_ENTERDLGCONVERSIONMODE key.
-    /// </summary>
-    DbeEnterDialogConversionMode = 170,
-    
-    /// <summary>
-    /// The PA1 key.
-    /// </summary>
-    Pa1 = 170,
-    
-    /// <summary>
-    /// The OEM Clear key.
-    /// </summary>
-    OemClear = 171,
-    
-    /// <summary>
-    /// The key is used with another key to create a single combined character.
-    /// </summary>
-    DeadCharProcessed = 172,
-};
-
-#endif

+ 8 - 4
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@@ -8,19 +8,20 @@
 
 /* Begin PBXBuildFile section */
 		1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; };
+		1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
 		1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */; };
 		1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */; };
-		1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
-		1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; };
 		1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */; };
 		1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */; };
 		1A465D10246AB61600C5858B /* dnd.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A465D0F246AB61600C5858B /* dnd.mm */; };
+		1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; };
 		37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; };
 		37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
 		37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
 		37DDA9B0219330F8002E132B /* AvnString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DDA9AF219330F8002E132B /* AvnString.mm */; };
 		37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; };
 		520624B322973F4100C4DCEF /* menu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 520624B222973F4100C4DCEF /* menu.mm */; };
+		522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 522D5958258159C1006F7F7A /* Carbon.framework */; };
 		5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
 		5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
 		AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
@@ -32,13 +33,13 @@
 
 /* Begin PBXFileReference section */
 		1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = "<group>"; };
+		1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = "<group>"; };
 		1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = rendertarget.mm; sourceTree = "<group>"; };
 		1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
-		1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = "<group>"; };
-		1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = "<group>"; };
 		1A3E5EAD23E9FB1300EDE661 /* cgl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cgl.mm; sourceTree = "<group>"; };
 		1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 		1A465D0F246AB61600C5858B /* dnd.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = dnd.mm; sourceTree = "<group>"; };
+		1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = "<group>"; };
 		37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = "<group>"; };
 		379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; };
 		37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = "<group>"; };
@@ -49,6 +50,7 @@
 		37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.h; sourceTree = "<group>"; };
 		37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = "<group>"; };
 		520624B222973F4100C4DCEF /* menu.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = menu.mm; sourceTree = "<group>"; };
+		522D5958258159C1006F7F7A /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
 		5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = "<group>"; };
 		5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; };
 		5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; };
@@ -69,6 +71,7 @@
 				1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */,
 				1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */,
 				AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
+				522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */,
 				AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -79,6 +82,7 @@
 		AB661C1C2148230E00291242 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				522D5958258159C1006F7F7A /* Carbon.framework */,
 				1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */,
 				1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */,
 				AB1E522B217613570091CD71 /* OpenGL.framework */,

+ 1 - 0
native/Avalonia.Native/src/OSX/AvnString.h

@@ -11,6 +11,7 @@
 
 extern IAvnString* CreateAvnString(NSString* string);
 extern IAvnStringArray* CreateAvnStringArray(NSArray<NSString*>* array);
+extern IAvnStringArray* CreateAvnStringArray(NSArray<NSURL*>* array);
 extern IAvnStringArray* CreateAvnStringArray(NSString* string);
 extern IAvnString* CreateByteArray(void* data, int len);
 #endif /* AvnString_h */

+ 15 - 0
native/Avalonia.Native/src/OSX/AvnString.mm

@@ -85,6 +85,16 @@ public:
         }
     }
     
+    AvnStringArrayImpl(NSArray<NSURL*>* array)
+    {
+        for(int c = 0; c < [array count]; c++)
+        {
+            ComPtr<IAvnString> s;
+            *s.getPPV() = new AvnStringImpl([array objectAtIndex:c].absoluteString);
+            _list.push_back(s);
+        }
+    }
+    
     AvnStringArrayImpl(NSString* string)
     {
         ComPtr<IAvnString> s;
@@ -117,6 +127,11 @@ IAvnStringArray* CreateAvnStringArray(NSArray<NSString*> * array)
     return new AvnStringArrayImpl(array);
 }
 
+IAvnStringArray* CreateAvnStringArray(NSArray<NSURL*> * array)
+{
+    return new AvnStringArrayImpl(array);
+}
+
 IAvnStringArray* CreateAvnStringArray(NSString* string)
 {
     return new AvnStringArrayImpl(string);

+ 6 - 1
native/Avalonia.Native/src/OSX/KeyTransform.h

@@ -1,9 +1,14 @@
 #ifndef keytransform_h
 #define keytransform_h
 #include "common.h"
-#include "key.h"
 #include <map>
 
 extern std::map<int, AvnKey> s_KeyMap;
 
+extern std::map<AvnKey, int> s_AvnKeyMap;
+
+extern std::map<int, const char*> s_QwertyKeyMap;
+
+extern std::map<AvnKey, int> s_UnicodeKeyMap;
+
 #endif

+ 151 - 0
native/Avalonia.Native/src/OSX/KeyTransform.mm

@@ -120,6 +120,138 @@ const int kVK_UpArrow = 0x7E;
 //const int kVK_JIS_Eisu = 0x66;
 const int kVK_JIS_Kana = 0x68;
 
+// converts from AvaloniaKeys to UnicodeSpecial keys.
+std::map<AvnKey, int> s_UnicodeKeyMap =
+{
+    { Up, NSUpArrowFunctionKey },
+    { Down, NSDownArrowFunctionKey },
+    { Left, NSLeftArrowFunctionKey },
+    { Right, NSRightArrowFunctionKey },
+    { F1, NSF1FunctionKey },
+    { F2, NSF2FunctionKey },
+    { F3, NSF3FunctionKey },
+    { F4, NSF4FunctionKey },
+    { F5, NSF5FunctionKey },
+    { F6, NSF6FunctionKey },
+    { F7, NSF7FunctionKey },
+    { F8, NSF8FunctionKey },
+    { F9, NSF9FunctionKey },
+    { F10, NSF10FunctionKey },
+    { F11, NSF11FunctionKey },
+    { F12, NSF12FunctionKey },
+    { F13, NSF13FunctionKey },
+    { F14, NSF14FunctionKey },
+    { F15, NSF15FunctionKey },
+    { F16, NSF16FunctionKey },
+    { F17, NSF17FunctionKey },
+    { F18, NSF18FunctionKey },
+    { F19, NSF19FunctionKey },
+    { F20, NSF20FunctionKey },
+    { F21, NSF21FunctionKey },
+    { F22, NSF22FunctionKey },
+    { F23, NSF23FunctionKey },
+    { F24, NSF24FunctionKey },
+    { Insert, NSInsertFunctionKey },
+    { Delete, NSDeleteFunctionKey },
+    { Home, NSHomeFunctionKey },
+    //{ Begin, NSBeginFunctionKey },
+    { End, NSEndFunctionKey },
+    { PageUp, NSPageUpFunctionKey },
+    { PageDown, NSPageDownFunctionKey },
+    { PrintScreen, NSPrintScreenFunctionKey },
+    { Scroll, NSScrollLockFunctionKey },
+    //{ SysReq, NSSysReqFunctionKey },
+    //{ Break, NSBreakFunctionKey },
+    //{ Reset, NSResetFunctionKey },
+    //{ Stop, NSStopFunctionKey },
+    //{ Menu, NSMenuFunctionKey },
+    //{ UserFunction, NSUserFunctionKey },
+    //{ SystemFunction, NSSystemFunctionKey },
+    { Print, NSPrintFunctionKey },
+    //{ ClearLine, NSClearLineFunctionKey },
+    //{ ClearDisplay, NSClearDisplayFunctionKey },
+};
+
+// Converts from Ansi virtual keys to Qwerty Keyboard map.
+std::map<int, const char*> s_QwertyKeyMap =
+{
+    { 0, "a" },
+    { 1, "s" },
+    { 2, "d" },
+    { 3, "f" },
+    { 4, "h" },
+    { 5, "g" },
+    { 6, "z" },
+    { 7, "x" },
+    { 8, "c" },
+    { 9, "v" },
+    { 10, "§" },
+    { 11, "b" },
+    { 12, "q" },
+    { 13, "w" },
+    { 14, "e" },
+    { 15, "r" },
+    { 16, "y" },
+    { 17, "t" },
+    { 18, "1" },
+    { 19, "2" },
+    { 20, "3" },
+    { 21, "4" },
+    { 22, "6" },
+    { 23, "5" },
+    { 24, "=" },
+    { 25, "9" },
+    { 26, "7" },
+    { 27, "-" },
+    { 28, "8" },
+    { 29, "0" },
+    { 30, "]" },
+    { 31, "o" },
+    { 32, "u" },
+    { 33, "[" },
+    { 34, "i" },
+    { 35, "p" },
+    { 37, "l" },
+    { 38, "j" },
+    { 39, "'" },
+    { 40, "k" },
+    { 41, ";" },
+    { 42, "\\" },
+    { 43, "," },
+    { 44, "/" },
+    { 45, "n" },
+    { 46, "m" },
+    { 47, "." },
+    { 49, " " },
+    { 50, "`" },
+    { 51, "" },
+    { 52, "" },
+    { 53, "" },
+    { 65, "." },
+    { 66, "" },
+    { 67, "*" },
+    { 69, "+" },
+    { 70, "" },
+    { 71, "" },
+    { 72, "" },
+    { 75, "/" },
+    { 76, "" },
+    { 77, "" },
+    { 78, "-" },
+    { 81, "=" },
+    { 82, "0" },
+    { 83, "1" },
+    { 84, "2" },
+    { 85, "3" },
+    { 86, "4" },
+    { 87, "5" },
+    { 88, "6" },
+    { 89, "7" },
+    { 91, "8" },
+    { 92, "9" }
+};
+
+// converts from ansi virtualkeys to AvnKeys.
  std::map<int, AvnKey> s_KeyMap =
  {
     {kVK_ANSI_A, A},
@@ -237,3 +369,22 @@ const int kVK_JIS_Kana = 0x68;
     {kVK_UpArrow, Up},
     {kVK_JIS_Kana, AvnKeyKanaMode},
 };
+
+static std::map<AvnKey, int> BuildAvnKeyMap ()
+{
+    std::map<AvnKey, int> result;
+    
+    for( auto it = s_KeyMap.begin(); it != s_KeyMap.end(); ++it )
+    {
+        int key = it->first;
+        AvnKey value = it->second;
+        
+        result[value] = key;
+    }
+    
+    return result;
+}
+
+// Converts AvnKeys to Ansi VirtualKeys
+std::map<AvnKey, int> s_AvnKeyMap = BuildAvnKeyMap();
+

+ 2 - 8
native/Avalonia.Native/src/OSX/Screens.mm

@@ -5,12 +5,6 @@ class Screens : public ComSingleObject<IAvnScreens, &IID_IAvnScreens>
     public:
     FORWARD_IUNKNOWN()
     
-    private:
-    CGFloat PrimaryDisplayHeight()
-    {
-      return NSMaxY([[[NSScreen screens] firstObject] frame]);
-    }
-    
 public:
     virtual HRESULT GetScreenCount (int* ret) override
     {
@@ -36,12 +30,12 @@ public:
             ret->Bounds.Height = [screen frame].size.height;
             ret->Bounds.Width = [screen frame].size.width;
             ret->Bounds.X = [screen frame].origin.x;
-            ret->Bounds.Y = PrimaryDisplayHeight() - [screen frame].origin.y - ret->Bounds.Height;
+            ret->Bounds.Y = ConvertPointY(ToAvnPoint([screen frame].origin)).Y - ret->Bounds.Height;
             
             ret->WorkingArea.Height = [screen visibleFrame].size.height;
             ret->WorkingArea.Width = [screen visibleFrame].size.width;
             ret->WorkingArea.X = [screen visibleFrame].origin.x;
-            ret->WorkingArea.Y = ret->Bounds.Height - [screen visibleFrame].origin.y - ret->WorkingArea.Height;
+            ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height;
             
             ret->PixelDensity = [screen backingScaleFactor];
             

+ 25 - 3
native/Avalonia.Native/src/OSX/app.mm

@@ -1,10 +1,20 @@
 #include "common.h"
+#include "AvnString.h"
 @interface AvnAppDelegate : NSObject<NSApplicationDelegate>
+-(AvnAppDelegate* _Nonnull) initWithEvents: (IAvnApplicationEvents* _Nonnull) events;
 @end
 
 NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
 
 @implementation AvnAppDelegate
+ComPtr<IAvnApplicationEvents> _events;
+
+- (AvnAppDelegate *)initWithEvents:(IAvnApplicationEvents *)events
+{
+    _events = events;
+    return self;
+}
+
 - (void)applicationWillFinishLaunching:(NSNotification *)notification
 {
     if([[NSApplication sharedApplication] activationPolicy] != AvnDesiredActivationPolicy)
@@ -27,11 +37,23 @@ NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivati
     [[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
 }
 
+- (void)application:(NSApplication *)sender openFiles:(NSArray<NSString *> *)filenames
+{
+    auto array = CreateAvnStringArray(filenames);
+    
+    _events->FilesOpened(array);
+}
+
+- (void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls
+{
+    auto array = CreateAvnStringArray(urls);
+    
+    _events->FilesOpened(array);
+}
 @end
 
 @interface AvnApplication : NSApplication
 
-
 @end
 
 @implementation AvnApplication
@@ -63,9 +85,9 @@ NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivati
 
 @end
 
-extern void InitializeAvnApp()
+extern void InitializeAvnApp(IAvnApplicationEvents* events)
 {
     NSApplication* app = [AvnApplication sharedApplication];
-    id delegate = [AvnAppDelegate new];
+    id delegate = [[AvnAppDelegate alloc] initWithEvents:events];
     [app setDelegate:delegate];
 }

+ 1 - 1
native/Avalonia.Native/src/OSX/clipboard.mm

@@ -56,7 +56,7 @@ public:
                 return S_OK;
             }
             
-            NSArray* arr = (NSArray*)data;
+            NSArray<NSString*>* arr = (NSArray*)data;
             
             for(int c = 0; c < [arr count]; c++)
                 if(![[arr objectAtIndex:c] isKindOfClass:[NSString class]])

+ 5 - 2
native/Avalonia.Native/src/OSX/common.h

@@ -23,17 +23,20 @@ extern IAvnCursorFactory* CreateCursorFactory();
 extern IAvnGlDisplay* GetGlDisplay();
 extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events);
 extern IAvnMenuItem* CreateAppMenuItem();
-extern IAvnMenuItem* CreateAppMenuItemSeperator();
+extern IAvnMenuItem* CreateAppMenuItemSeparator();
 extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent);
 extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
 extern IAvnMenu* GetAppMenu ();
 extern NSMenuItem* GetAppMenuItem ();
+extern void SetAutoGenerateDefaultAppMenuItems (bool enabled);
+extern bool GetAutoGenerateDefaultAppMenuItems ();
 
-extern void InitializeAvnApp();
+extern void InitializeAvnApp(IAvnApplicationEvents* events);
 extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;
 extern NSPoint ToNSPoint (AvnPoint p);
 extern AvnPoint ToAvnPoint (NSPoint p);
 extern AvnPoint ConvertPointY (AvnPoint p);
+extern CGFloat PrimaryDisplayHeight();
 extern NSSize ToNSSize (AvnSize s);
 #ifdef DEBUG
 #define NSDebugLog(...) NSLog(__VA_ARGS__)

+ 22 - 0
native/Avalonia.Native/src/OSX/cursor.mm

@@ -62,6 +62,28 @@ public:
             
         return S_OK;
     }
+    
+    virtual HRESULT CreateCustomCursor (void* bitmapData, size_t length, AvnPixelSize hotPixel, IAvnCursor** retOut) override
+    {
+        if(bitmapData == nullptr || retOut == nullptr)
+        {
+            return E_POINTER;
+        }
+        
+        NSData *imageData = [NSData dataWithBytes:bitmapData length:length];
+        NSImage *image = [[NSImage alloc] initWithData:imageData];
+        
+        
+        NSPoint hotSpot;
+        hotSpot.x = hotPixel.Width;
+        hotSpot.y = hotPixel.Height;
+        
+        *retOut = new Cursor([[NSCursor new] initWithImage: image hotSpot: hotSpot]);
+        
+        (*retOut)->AddRef();
+        
+        return S_OK;
+    }
 };
 
 extern IAvnCursorFactory* CreateCursorFactory()

+ 28 - 7
native/Avalonia.Native/src/OSX/main.mm

@@ -2,6 +2,7 @@
 #define COM_GUIDS_MATERIALIZE
 #include "common.h"
 
+static bool s_generateDefaultAppMenuItems = true;
 static NSString* s_appTitle = @"Avalonia";
 
 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
@@ -122,6 +123,12 @@ public:
             ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory;
         return S_OK;
     }
+    
+    virtual HRESULT SetDisableDefaultApplicationMenuItems (bool enabled) override
+    {
+        SetAutoGenerateDefaultAppMenuItems(!enabled);
+        return S_OK;
+    }
 };
 
 /// See "Using POSIX Threads in a Cocoa Application" section here:
@@ -156,13 +163,13 @@ class AvaloniaNative : public ComSingleObject<IAvaloniaNativeFactory, &IID_IAval
     
 public:
     FORWARD_IUNKNOWN()
-    virtual HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator) override
+    virtual HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator, IAvnApplicationEvents* events) override
     {
         _deallocator = deallocator;
         @autoreleasepool{
             [[ThreadingInitializer new] do];
         }
-        InitializeAvnApp();
+        InitializeAvnApp(events);
         return S_OK;
     };
     
@@ -246,9 +253,9 @@ public:
         return S_OK;
     }
     
-    virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) override
+    virtual HRESULT CreateMenuItemSeparator (IAvnMenuItem** ppv) override
     {
-        *ppv = ::CreateAppMenuItemSeperator();
+        *ppv = ::CreateAppMenuItemSeparator();
         return S_OK;
     }
     
@@ -299,10 +306,24 @@ AvnPoint ToAvnPoint (NSPoint p)
 
 AvnPoint ConvertPointY (AvnPoint p)
 {
-    auto sw = [NSScreen.screens objectAtIndex:0].frame;
+    auto primaryDisplayHeight = NSMaxY([[[NSScreen screens] firstObject] frame]);
     
-    auto t = MAX(sw.origin.y, sw.origin.y + sw.size.height);
-    p.Y = t - p.Y;
+    p.Y = primaryDisplayHeight - p.Y;
     
     return p;
 }
+
+CGFloat PrimaryDisplayHeight()
+{
+  return NSMaxY([[[NSScreen screens] firstObject] frame]);
+}
+
+void SetAutoGenerateDefaultAppMenuItems (bool enabled)
+{
+    s_generateDefaultAppMenuItems = enabled;
+}
+
+bool GetAutoGenerateDefaultAppMenuItems ()
+{
+    return s_generateDefaultAppMenuItems;
+}

+ 6 - 5
native/Avalonia.Native/src/OSX/menu.h

@@ -31,13 +31,13 @@ private:
     NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem
     IAvnActionCallback* _callback;
     IAvnPredicateCallback* _predicate;
-    bool _isSeperator;
+    bool _isSeparator;
     bool _isCheckable;
     
 public:
     FORWARD_IUNKNOWN()
     
-    AvnAppMenuItem(bool isSeperator);
+    AvnAppMenuItem(bool isSeparator);
     
     NSMenuItem* GetNative();
     
@@ -45,7 +45,7 @@ public:
     
     virtual HRESULT SetTitle (char* utf8String) override;
     
-    virtual HRESULT SetGesture (char* key, AvnInputModifiers modifiers) override;
+    virtual HRESULT SetGesture (AvnKey key, AvnInputModifiers modifiers) override;
     
     virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;
     
@@ -60,7 +60,6 @@ public:
     void RaiseOnClicked();
 };
 
-
 class AvnAppMenu : public ComSingleObject<IAvnMenu, &IID_IAvnMenu>
 {
 private:
@@ -71,10 +70,12 @@ public:
     FORWARD_IUNKNOWN()
     
     AvnAppMenu(IAvnMenuEvents* events);
-        
+
     AvnMenu* GetNative();
     
     void RaiseNeedsUpdate ();
+    void RaiseOpening();
+    void RaiseClosed();
     
     virtual HRESULT InsertItem (int index, IAvnMenuItem* item) override;
     

+ 124 - 58
native/Avalonia.Native/src/OSX/menu.mm

@@ -2,6 +2,9 @@
 #include "common.h"
 #include "menu.h"
 #include "window.h"
+#include "KeyTransform.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
 
 @implementation AvnMenu
 {
@@ -68,12 +71,12 @@
 }
 @end
 
-AvnAppMenuItem::AvnAppMenuItem(bool isSeperator)
+AvnAppMenuItem::AvnAppMenuItem(bool isSeparator)
 {
     _isCheckable = false;
-    _isSeperator = isSeperator;
+    _isSeparator = isSeparator;
     
-    if(isSeperator)
+    if(isSeparator)
     {
         _native = [NSMenuItem separatorItem];
     }
@@ -122,23 +125,57 @@ HRESULT AvnAppMenuItem::SetTitle (char* utf8String)
     }
 }
 
-HRESULT AvnAppMenuItem::SetGesture (char* key, AvnInputModifiers modifiers)
+
+HRESULT AvnAppMenuItem::SetGesture (AvnKey key, AvnInputModifiers modifiers)
 {
     @autoreleasepool
     {
-        NSEventModifierFlags flags = 0;
-        
-        if (modifiers & Control)
-            flags |= NSEventModifierFlagControl;
-        if (modifiers & Shift)
-            flags |= NSEventModifierFlagShift;
-        if (modifiers & Alt)
-            flags |= NSEventModifierFlagOption;
-        if (modifiers & Windows)
-            flags |= NSEventModifierFlagCommand;
+        if(key != AvnKeyNone)
+        {
+            NSEventModifierFlags flags = 0;
+            
+            if (modifiers & Control)
+                flags |= NSEventModifierFlagControl;
+            if (modifiers & Shift)
+                flags |= NSEventModifierFlagShift;
+            if (modifiers & Alt)
+                flags |= NSEventModifierFlagOption;
+            if (modifiers & Windows)
+                flags |= NSEventModifierFlagCommand;
+            
+            auto it = s_UnicodeKeyMap.find(key);
+            
+            if(it != s_UnicodeKeyMap.end())
+            {
+                auto keyString= [NSString stringWithFormat:@"%C", (unsigned short)it->second];
+                
+                [_native setKeyEquivalent: keyString];
+                [_native setKeyEquivalentModifierMask:flags];
+                
+                return S_OK;
+            }
+            else
+            {
+                auto it = s_AvnKeyMap.find(key); // check if a virtual key is mapped.
+                
+                if(it != s_AvnKeyMap.end())
+                {
+                    auto it1 = s_QwertyKeyMap.find(it->second); // convert virtual key to qwerty string.
+                    
+                    if(it1 != s_QwertyKeyMap.end())
+                    {
+                        [_native setKeyEquivalent: [NSString  stringWithUTF8String: it1->second]];
+                        [_native setKeyEquivalentModifierMask:flags];
+                        
+                        return S_OK;
+                    }
+                }
+            }
+        }
         
-        [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
-        [_native setKeyEquivalentModifierMask:flags];
+        // Nothing matched... clear.
+        [_native setKeyEquivalent: @""];
+        [_native setKeyEquivalentModifierMask: 0];
         
         return S_OK;
     }
@@ -261,6 +298,23 @@ void AvnAppMenu::RaiseNeedsUpdate()
     }
 }
 
+void AvnAppMenu::RaiseOpening()
+{
+    if(_baseEvents != nullptr)
+    {
+        _baseEvents->Opening();
+    }
+}
+
+void AvnAppMenu::RaiseClosed()
+{
+    if(_baseEvents != nullptr)
+    {
+        _baseEvents->Closed();
+    }
+}
+
+
 HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item)
 {
     @autoreleasepool
@@ -345,6 +399,15 @@ HRESULT AvnAppMenu::Clear()
     _parent->RaiseNeedsUpdate();
 }
 
+- (void)menuWillOpen:(NSMenu *)menu
+{
+    _parent->RaiseOpening();
+}
+
+- (void)menuDidClose:(NSMenu *)menu
+{
+    _parent->RaiseClosed();
+}
 
 @end
 
@@ -364,7 +427,7 @@ extern IAvnMenuItem* CreateAppMenuItem()
     }
 }
 
-extern IAvnMenuItem* CreateAppMenuItemSeperator()
+extern IAvnMenuItem* CreateAppMenuItemSeparator()
 {
     @autoreleasepool
     {
@@ -408,47 +471,50 @@ extern void SetAppMenu (NSString* appName, IAvnMenu* menu)
         
         auto appMenu  = [s_appMenuItem submenu];
         
-        [appMenu addItem:[NSMenuItem separatorItem]];
-        
-        // Services item and menu
-        auto servicesItem = [[NSMenuItem alloc] init];
-        servicesItem.title = @"Services";
-        NSMenu *servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
-        servicesItem.submenu = servicesMenu;
-        [NSApplication sharedApplication].servicesMenu = servicesMenu;
-        [appMenu addItem:servicesItem];
-        
-        [appMenu addItem:[NSMenuItem separatorItem]];
-        
-        // Hide Application
-        auto hideItem = [[NSMenuItem alloc] initWithTitle:[@"Hide " stringByAppendingString:appName] action:@selector(hide:) keyEquivalent:@"h"];
-        
-        [appMenu addItem:hideItem];
-        
-        // Hide Others
-        auto hideAllOthersItem = [[NSMenuItem alloc] initWithTitle:@"Hide Others"
-                                                       action:@selector(hideOtherApplications:)
-                                                keyEquivalent:@"h"];
-        
-        hideAllOthersItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagOption;
-        [appMenu addItem:hideAllOthersItem];
-        
-        // Show All
-        auto showAllItem = [[NSMenuItem alloc] initWithTitle:@"Show All"
-                                                 action:@selector(unhideAllApplications:)
-                                          keyEquivalent:@""];
-        
-        [appMenu addItem:showAllItem];
-        
-        [appMenu addItem:[NSMenuItem separatorItem]];
-        
-        // Quit Application
-        auto quitItem = [[NSMenuItem alloc] init];
-        quitItem.title = [@"Quit " stringByAppendingString:appName];
-        quitItem.keyEquivalent = @"q";
-        quitItem.target = [AvnWindow class];
-        quitItem.action = @selector(closeAll);
-        [appMenu addItem:quitItem];
+        if(GetAutoGenerateDefaultAppMenuItems())
+        {
+            [appMenu addItem:[NSMenuItem separatorItem]];
+            
+            // Services item and menu
+            auto servicesItem = [[NSMenuItem alloc] init];
+            servicesItem.title = @"Services";
+            NSMenu *servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
+            servicesItem.submenu = servicesMenu;
+            [NSApplication sharedApplication].servicesMenu = servicesMenu;
+            [appMenu addItem:servicesItem];
+            
+            [appMenu addItem:[NSMenuItem separatorItem]];
+            
+            // Hide Application
+            auto hideItem = [[NSMenuItem alloc] initWithTitle:[@"Hide " stringByAppendingString:appName] action:@selector(hide:) keyEquivalent:@"h"];
+            
+            [appMenu addItem:hideItem];
+            
+            // Hide Others
+            auto hideAllOthersItem = [[NSMenuItem alloc] initWithTitle:@"Hide Others"
+                                                           action:@selector(hideOtherApplications:)
+                                                    keyEquivalent:@"h"];
+            
+            hideAllOthersItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagOption;
+            [appMenu addItem:hideAllOthersItem];
+            
+            // Show All
+            auto showAllItem = [[NSMenuItem alloc] initWithTitle:@"Show All"
+                                                     action:@selector(unhideAllApplications:)
+                                              keyEquivalent:@""];
+            
+            [appMenu addItem:showAllItem];
+            
+            [appMenu addItem:[NSMenuItem separatorItem]];
+            
+            // Quit Application
+            auto quitItem = [[NSMenuItem alloc] init];
+            quitItem.title = [@"Quit " stringByAppendingString:appName];
+            quitItem.keyEquivalent = @"q";
+            quitItem.target = [AvnWindow class];
+            quitItem.action = @selector(closeAll);
+            [appMenu addItem:quitItem];
+        }
     }
     else
     {

+ 1 - 1
native/Avalonia.Native/src/OSX/platformthreading.mm

@@ -101,7 +101,7 @@ public:
     
     virtual bool GetCurrentThreadIsLoopThread() override
     {
-        return [[NSThread currentThread] isMainThread];
+        return [NSThread isMainThread];
     }
     virtual void SetSignaledCallback(IAvnSignaledCallback* cb) override
     {

+ 20 - 2
native/Avalonia.Native/src/OSX/rendertarget.mm

@@ -2,6 +2,7 @@
 #include "rendertarget.h"
 #import <IOSurface/IOSurface.h>
 #import <IOSurface/IOSurfaceObjC.h>
+#import <QuartzCore/QuartzCore.h>
 
 #include <OpenGL/CGLIOSurface.h>
 #include <OpenGL/OpenGL.h>
@@ -110,7 +111,11 @@
         if(_renderbuffer != 0)
             glDeleteRenderbuffers(1, &_renderbuffer);
     }
-    CFRelease(surface);
+
+    if(surface != nullptr)
+    {
+        CFRelease(surface);
+    }
 }
 @end
 
@@ -143,13 +148,23 @@ static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* ta
     return _layer;
 }
 
-- (void)resize:(AvnPixelSize)size withScale: (float) scale;{
+- (void)resize:(AvnPixelSize)size withScale: (float) scale{
+
+    if(size.Height <= 0)
+        size.Height = 1;
+    if(size.Width <= 0)
+        size.Width = 1;
+
     @synchronized (lock) {
         if(surface == nil
            || surface->size.Width != size.Width
            || surface->size.Height != size.Height
            || surface->scale != scale)
+        {
             surface = [[IOSurfaceHolder alloc] initWithSize:size withScale:scale withOpenGlContext:_glContext.getRaw()];
+            
+            [self updateLayer];
+        }
     }
 }
 
@@ -159,12 +174,15 @@ static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* ta
         @synchronized (lock) {
             if(_layer == nil)
                 return;
+            [CATransaction begin];
             [_layer setContents: nil];
             if(surface != nil)
             {
                 [_layer setContentsScale: surface->scale];
                 [_layer setContents: (__bridge IOSurface*) surface->surface];
             }
+            [CATransaction commit];
+            [CATransaction flush];
         }
     }
     else

+ 48 - 21
native/Avalonia.Native/src/OSX/window.mm

@@ -50,7 +50,6 @@ public:
         [Window setBackingType:NSBackingStoreBuffered];
         
         [Window setOpaque:false];
-        [Window setContentView: StandardContainer];
     }
     
     virtual HRESULT ObtainNSWindowHandle(void** ret) override
@@ -106,13 +105,16 @@ public:
         return Window;
     }
     
-    virtual HRESULT Show() override
+    virtual HRESULT Show(bool activate) override
     {
         @autoreleasepool
         {
             SetPosition(lastPositionSet);
             UpdateStyle();
-            if(ShouldTakeFocusOnShow())
+            
+            [Window setContentView: StandardContainer];
+            
+            if(ShouldTakeFocusOnShow() && activate)
             {
                 [Window makeKeyAndOrderFront:Window];
                 [NSApp activateIgnoringOtherApps:YES];
@@ -124,7 +126,7 @@ public:
             [Window setTitle:_lastTitle];
             
             _shown = true;
-        
+            
             return S_OK;
         }
     }
@@ -191,9 +193,11 @@ public:
         {
             if(ret == nullptr)
                 return E_POINTER;
+            
             auto frame = [View frame];
             ret->Width = frame.size.width;
             ret->Height = frame.size.height;
+            
             return S_OK;
         }
     }
@@ -254,6 +258,12 @@ public:
                 y = maxSize.height;
             }
             
+            if(!_shown)
+            {
+                BaseEvents->Resized(AvnSize{x,y});
+            }
+            
+            [StandardContainer setFrameSize:NSSize{x,y}];
             [Window setContentSize:NSSize{x, y}];
             
             return S_OK;
@@ -561,11 +571,11 @@ private:
         }
     }
     
-    virtual HRESULT Show () override
+    virtual HRESULT Show (bool activate) override
     {
         @autoreleasepool
         {            
-            WindowBaseImpl::Show();
+            WindowBaseImpl::Show(activate);
             
             HideOrShowTrafficLights();
             
@@ -1391,17 +1401,20 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     [super viewDidChangeBackingProperties];
 }
 
-- (bool) ignoreUserInput
+- (bool) ignoreUserInput:(bool)trigerInputWhenDisabled
 {
     auto parentWindow = objc_cast<AvnWindow>([self window]);
     
     if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents])
     {
-        auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
-        
-        if(window != nullptr)
+        if(trigerInputWhenDisabled)
         {
-            window->WindowEvents->GotInputWhenDisabled();
+            auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
+            
+            if(window != nullptr)
+            {
+                window->WindowEvents->GotInputWhenDisabled();
+            }
         }
         
         return TRUE;
@@ -1412,7 +1425,9 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
 
 - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
 {
-    if([self ignoreUserInput])
+    bool triggerInputWhenDisabled = type != Move;
+    
+    if([self ignoreUserInput: triggerInputWhenDisabled])
     {
         return;
     }
@@ -1578,7 +1593,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
 
 - (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
 {
-    if([self ignoreUserInput])
+    if([self ignoreUserInput: false])
     {
         return;
     }
@@ -1872,7 +1887,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     
     for(int i = 0; i < numWindows; i++)
     {
-        [[windows objectAtIndex:i] performClose:nil];
+        auto window = (AvnWindow*)[windows objectAtIndex:i];
+        
+        if([window parentWindow] == nullptr) // Avalonia will handle the child windows.
+        {
+            [window performClose:nil];
+        }
     }
 }
 
@@ -1926,6 +1946,10 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
         
         [NSApp setMenu:_menu];
     }
+    else
+    {
+        [self showAppMenuOnly];
+    }
 }
 
 -(void) showAppMenuOnly
@@ -1982,7 +2006,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     _lastScaling = [self backingScaleFactor];
     [self setOpaque:NO];
     [self setBackgroundColor: [NSColor clearColor]];
-    [self invalidateShadow];
     _isExtended = false;
     return self;
 }
@@ -2063,17 +2086,17 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
 
 -(void)becomeKeyWindow
 {
+    [self showWindowMenuWithAppMenu];
+    
     if([self activateAppropriateChild: true])
     {
-        [self showWindowMenuWithAppMenu];
-        
         if(_parent != nullptr)
         {
             _parent->BaseEvents->Activated();
         }
-        
-        [super becomeKeyWindow];
     }
+    
+    [super becomeKeyWindow];
 }
 
 -(void) restoreParentWindow;
@@ -2221,9 +2244,13 @@ protected:
     {
         @autoreleasepool
         {
-            [Window setContentSize:NSSize{x, y}];
+            if (Window != nullptr)
+            {
+                [StandardContainer setFrameSize:NSSize{x,y}];
+                [Window setContentSize:NSSize{x, y}];
             
-            [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))];
+                [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))];
+            }
             
             return S_OK;
         }

+ 19 - 55
nukebuild/Build.cs

@@ -16,7 +16,6 @@ using Nuke.Common.Tools.MSBuild;
 using Nuke.Common.Tools.Npm;
 using Nuke.Common.Utilities;
 using Nuke.Common.Utilities.Collections;
-using Pharmacist.Core;
 using static Nuke.Common.EnvironmentInfo;
 using static Nuke.Common.IO.FileSystemTasks;
 using static Nuke.Common.IO.PathConstruction;
@@ -89,10 +88,6 @@ partial class Build : NukeBuild
             Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit();
         }
         ExecWait("dotnet version:", "dotnet", "--version");
-        if (Parameters.IsRunningOnUnix)
-            ExecWait("Mono version:", "mono", "--version");
-
-
     }
 
     IReadOnlyCollection<Output> MsBuildCommon(
@@ -107,7 +102,7 @@ partial class Build : NukeBuild
                 .AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64")))
             .AddProperty("PackageVersion", Parameters.Version)
             .AddProperty("iOSRoslynPathHackRequired", true)
-            .SetToolPath(MsBuildExe.Value)
+            .SetProcessToolPath(MsBuildExe.Value)
             .SetConfiguration(Parameters.Configuration)
             .SetVerbosity(MSBuildVerbosity.Minimal)
             .Apply(configurator));
@@ -132,10 +127,10 @@ partial class Build : NukeBuild
             var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
 
             NpmTasks.NpmInstall(c => c
-                .SetWorkingDirectory(webappDir)
-                .SetArgumentConfigurator(a => a.Add("--silent")));
+                .SetProcessWorkingDirectory(webappDir)
+                .SetProcessArgumentConfigurator(a => a.Add("--silent")));
             NpmTasks.NpmRun(c => c
-                .SetWorkingDirectory(webappDir)
+                .SetProcessWorkingDirectory(webappDir)
                 .SetCommand("dist"));
         });
 
@@ -157,7 +152,7 @@ partial class Build : NukeBuild
         {
             if (Parameters.IsRunningOnWindows)
                 MsBuildCommon(Parameters.MSBuildSolution, c => c
-                    .SetArgumentConfigurator(a => a.Add("/r"))
+                    .SetProcessArgumentConfigurator(a => a.Add("/r"))
                     .AddTargets("Build")
                 );
 
@@ -167,44 +162,8 @@ partial class Build : NukeBuild
                     .AddProperty("PackageVersion", Parameters.Version)
                     .SetConfiguration(Parameters.Configuration)
                 );
-
-            await CompileReactiveEvents();
         });
 
-    async Task CompileReactiveEvents()
-    {
-        var avaloniaBuildOutput = Path.Combine(RootDirectory, "packages", "Avalonia", "bin", Parameters.Configuration);
-        var avaloniaAssemblies = GlobFiles(avaloniaBuildOutput, "**/Avalonia*.dll")
-            .Where(file => !file.Contains("Avalonia.Build.Tasks") &&
-                            !file.Contains("Avalonia.Remote.Protocol"));
-
-        var eventsDirectory = GlobDirectories($"{RootDirectory}/src/**/Avalonia.ReactiveUI.Events").First();
-        var eventsBuildFile = Path.Combine(eventsDirectory, "Events_Avalonia.cs");
-        if (File.Exists(eventsBuildFile))
-            File.Delete(eventsBuildFile);
-
-        using (var stream = File.Create(eventsBuildFile))
-        using (var writer = new StreamWriter(stream))
-        {
-            await ObservablesForEventGenerator.ExtractEventsFromAssemblies(
-                writer, avaloniaAssemblies, new string[0], "netstandard2.0"
-            );
-        }
-
-        var eventsProject = Path.Combine(eventsDirectory, "Avalonia.ReactiveUI.Events.csproj");
-        if (Parameters.IsRunningOnWindows)
-            MsBuildCommon(eventsProject, c => c
-                .SetArgumentConfigurator(a => a.Add("/r"))
-                .AddTargets("Build")
-            );
-        else
-            DotNetBuild(c => c
-                .SetProjectFile(eventsProject)
-                .AddProperty("PackageVersion", Parameters.Version)
-                .SetConfiguration(Parameters.Configuration)
-            );
-    }
-
     void RunCoreTest(string projectName)
     {
         Information($"Running tests from {projectName}");
@@ -242,10 +201,10 @@ partial class Build : NukeBuild
             var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp";
 
             NpmTasks.NpmInstall(c => c
-                .SetWorkingDirectory(webappTestDir)
-                .SetArgumentConfigurator(a => a.Add("--silent")));
+                .SetProcessWorkingDirectory(webappTestDir)
+                .SetProcessArgumentConfigurator(a => a.Add("--silent")));
             NpmTasks.NpmRun(c => c
-                .SetWorkingDirectory(webappTestDir)
+                .SetProcessWorkingDirectory(webappTestDir)
                 .SetCommand("test"));
         });
 
@@ -305,14 +264,19 @@ partial class Build : NukeBuild
         .Executes(() =>
         {
             var data = Parameters;
+            var pathToProjectSource = RootDirectory / "samples" / "ControlCatalog.NetCore";
+            var pathToPublish = pathToProjectSource / "bin" / data.Configuration / "publish";
+
+            DotNetPublish(c => c
+                .SetProject(pathToProjectSource / "ControlCatalog.NetCore.csproj")
+                .EnableNoBuild()
+                .SetConfiguration(data.Configuration)
+                .AddProperty("PackageVersion", data.Version)
+                .AddProperty("PublishDir", pathToPublish));
+
             Zip(data.ZipCoreArtifacts, data.BinRoot);
             Zip(data.ZipNuGetArtifacts, data.NugetRoot);
-            Zip(data.ZipTargetControlCatalogDesktopDir,
-                GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dll").Concat(
-                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.config")).Concat(
-                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.so")).Concat(
-                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dylib")).Concat(
-                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.exe")));
+            Zip(data.ZipTargetControlCatalogNetCoreDir, pathToPublish);
         });
 
     Target CreateIntermediateNugetPackages => _ => _

+ 2 - 5
nukebuild/BuildParameters.cs

@@ -58,8 +58,7 @@ public partial class Build
         public string FileZipSuffix { get; }
         public AbsolutePath ZipCoreArtifacts { get; }
         public AbsolutePath ZipNuGetArtifacts { get; }
-        public AbsolutePath ZipSourceControlCatalogDesktopDir { get; }
-        public AbsolutePath ZipTargetControlCatalogDesktopDir { get; }
+        public AbsolutePath ZipTargetControlCatalogNetCoreDir { get; }
 
 
         public BuildParameters(Build b)
@@ -129,9 +128,7 @@ public partial class Build
             FileZipSuffix = Version + ".zip";
             ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix);
             ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix);
-            ZipSourceControlCatalogDesktopDir =
-                RootDirectory / ("samples/ControlCatalog.Desktop/bin/" + DirSuffix + "/net461");
-            ZipTargetControlCatalogDesktopDir = ZipRoot / ("ControlCatalog.Desktop-" + FileZipSuffix);
+            ZipTargetControlCatalogNetCoreDir = ZipRoot / ("ControlCatalog.NetCore-" + FileZipSuffix);
         }
 
         string GetVersion()

+ 1 - 2
nukebuild/_build.csproj

@@ -10,14 +10,13 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Nuke.Common" Version="0.24.0" />
+    <PackageReference Include="Nuke.Common" Version="5.0.0" />
     <PackageReference Include="xunit.runner.console" Version="2.3.1" />
     <PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
     <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
     <PackageReference Include="ILRepack.NETStandard" Version="2.0.4" />
     <!-- Keep in sync with Avalonia.Build.Tasks -->
     <PackageReference Include="Mono.Cecil" Version="0.11.2" />
-    <PackageReference Include="Pharmacist.Core" Version="1.8.1" />
   </ItemGroup>
 
   <ItemGroup>

+ 8 - 4
packages/Avalonia/Avalonia.csproj

@@ -6,7 +6,9 @@
 
   <ItemGroup>
       <ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
-      <ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" />
+      <ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" >
+        <PrivateAssets>all</PrivateAssets>
+      </ProjectReference>  
   </ItemGroup>
 
   <PropertyGroup>
@@ -29,21 +31,23 @@
       </_PackageFiles>
     </ItemGroup>
   </Target>
+  
   <ItemGroup>
     <Content Include="*.props">
        <Pack>true</Pack>
-       <PackagePath>build\</PackagePath>
+       <PackagePath>build\;buildTransitive\</PackagePath>
     </Content>
     <Content Include="*.targets">
       <Pack>true</Pack>
-      <PackagePath>build\</PackagePath>
+      <PackagePath>build\;buildTransitive\</PackagePath>
     </Content>
     <Content Include="AvaloniaItemSchema.xaml">
       <Pack>true</Pack>
-      <PackagePath>build\</PackagePath>
+      <PackagePath>build\;buildTransitive\</PackagePath>
     </Content>
   </ItemGroup>
   <Import Project="..\..\build\SharedVersion.props" />
   <Import Project="..\..\build\NetFX.props" />
   <Import Project="..\..\build\CoreLibraries.props" />
+  <Import Project="..\..\build\SourceLink.props" Condition="'$(DisableSourceLink)' == ''" />
 </Project>

+ 11 - 6
readme.md

@@ -2,21 +2,19 @@
 <br />
 [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg) 
 
-<img alt="Avalonia" src="https://user-images.githubusercontent.com/6759207/84897744-cab6d800-b0ae-11ea-8214-e5174d71f5c8.png" width="400"/>
-
 ## 📖 About AvaloniaUI 
 
 Avalonia is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows via .NET Framework and .NET Core, Linux via Xorg, macOS. Avalonia is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development. 
 
 <img src="https://user-images.githubusercontent.com/6759207/84751662-7c79da00-afc5-11ea-8780-dda28db70b76.png" width="700" />
 
-> **Note:** The UI theme you see in the picture above is still work-in-progress and will be available in the upcoming Avalonia 0.10.0 release. However, you can connect to our nightly build feed and install latest pre-release versions of Avalonia NuGet packages, if you are willing to help out with the development and testing. See [Using nightly build feed](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) for more info.
+([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
 
 To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
 
 ## 🚀 Getting Started
 
-The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://avaloniaui.net/docs/quickstart/create-new-project).
+The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started).
 
 Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
 
@@ -31,15 +29,22 @@ Install-Package Avalonia.Desktop
 Examples of UIs built with Avalonia
 ![image](https://user-images.githubusercontent.com/4672627/84707589-5b69a880-af35-11ea-87a6-7ad57a31d314.png)
 
+([Synfonia](https://github.com/jmacato/Synfonia))
+
 ![image](https://user-images.githubusercontent.com/4672627/85069644-d8419000-b18a-11ea-8732-be9055bb61fd.PNG)
+([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
 
 ![image](https://user-images.githubusercontent.com/4672627/85069659-dc6dad80-b18a-11ea-8375-39ef95315b5c.PNG)
+([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
 
 ![image](https://user-images.githubusercontent.com/4672627/84708947-c3b98980-af37-11ea-8c9d-503334615bbf.png)
+([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
 
 ## JetBrains Rider
 
-If you need to develop Avalonia app with JetBrains Rider you can use latest Rider [preview builds](https://www.jetbrains.com/rider/nextversion/).
+[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
+
+Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
 
 ## Bleeding Edge Builds
 
@@ -47,7 +52,7 @@ We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using
 
 ## Documentation
 
-Documentation can be found on our website at https://avaloniaui.net/docs/. We also have a [tutorial](https://avaloniaui.net/docs/tutorial/) over there for newcomers.
+Documentation can be found at https://docs.avaloniaui.net. We also have a [tutorial](https://docs.avaloniaui.net/docs/getting-started/programming-with-avalonia) over there for newcomers.
 
 ## Building and Using
 

+ 0 - 2
samples/BindingDemo/App.xaml.cs

@@ -1,7 +1,6 @@
 using Avalonia;
 using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
 
 namespace BindingDemo
 {
@@ -25,7 +24,6 @@ namespace BindingDemo
         public static AppBuilder BuildAvaloniaApp()
           => AppBuilder.Configure<App>()
                 .UsePlatformDetect()
-                .UseReactiveUI()
                 .LogToTrace();
     }
 }

+ 1 - 2
samples/BindingDemo/BindingDemo.csproj

@@ -6,12 +6,11 @@
   <ItemGroup>
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
+    <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\EmbedXaml.props" />
   <Import Project="..\..\build\Rx.props" />
-  <Import Project="..\..\build\ReactiveUI.props" />
   <Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
   <Import Project="..\..\build\ReferenceCoreLibraries.props" />
   <Import Project="..\..\build\BuildTargets.targets" />

+ 2 - 2
samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs

@@ -1,9 +1,9 @@
-using ReactiveUI;
+using MiniMvvm;
 using System;
 
 namespace BindingDemo.ViewModels
 {
-    public class ExceptionErrorViewModel : ReactiveObject
+    public class ExceptionErrorViewModel : ViewModelBase
     {
         private int _lessThan10;
 

+ 2 - 2
samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs

@@ -1,11 +1,11 @@
-using ReactiveUI;
+using MiniMvvm;
 using System;
 using System.ComponentModel;
 using System.Collections;
 
 namespace BindingDemo.ViewModels
 {
-    public class IndeiErrorViewModel : ReactiveObject, INotifyDataErrorInfo
+    public class IndeiErrorViewModel : ViewModelBase, INotifyDataErrorInfo
     {
         private int _maximum = 10;
         private int _value;

+ 6 - 6
samples/BindingDemo/ViewModels/MainWindowViewModel.cs

@@ -5,14 +5,14 @@ using System.Reactive;
 using System.Reactive.Linq;
 using System.Threading.Tasks;
 using System.Threading;
-using ReactiveUI;
+using MiniMvvm;
 using Avalonia.Controls;
 using Avalonia.Metadata;
 using Avalonia.Controls.Selection;
 
 namespace BindingDemo.ViewModels
 {
-    public class MainWindowViewModel : ReactiveObject
+    public class MainWindowViewModel : ViewModelBase
     {
         private string _booleanString = "True";
         private double _doubleValue = 5.0;
@@ -32,13 +32,13 @@ namespace BindingDemo.ViewModels
 
             Selection = new SelectionModel<TestItem> { SingleSelect = false };
 
-            ShuffleItems = ReactiveCommand.Create(() =>
+            ShuffleItems = MiniCommand.Create(() =>
             {
                 var r = new Random();
                 Items.Move(r.Next(Items.Count), 1);
             });
 
-            StringValueCommand = ReactiveCommand.Create<object>(param =>
+            StringValueCommand = MiniCommand.Create<object>(param =>
             {
                 BooleanFlag = !BooleanFlag;
                 StringValue = param.ToString();
@@ -60,7 +60,7 @@ namespace BindingDemo.ViewModels
 
         public ObservableCollection<TestItem> Items { get; }
         public SelectionModel<TestItem> Selection { get; }
-        public ReactiveCommand<Unit, Unit> ShuffleItems { get; }
+        public MiniCommand ShuffleItems { get; }
 
         public string BooleanString
         {
@@ -93,7 +93,7 @@ namespace BindingDemo.ViewModels
         }
 
         public IObservable<DateTimeOffset> CurrentTimeObservable { get; }
-        public ReactiveCommand<object, Unit> StringValueCommand { get; }
+        public MiniCommand StringValueCommand { get; }
 
         public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel();
         public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel();

+ 4 - 4
samples/BindingDemo/ViewModels/NestedCommandViewModel.cs

@@ -1,18 +1,18 @@
-using ReactiveUI;
-using System;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Input;
+using MiniMvvm;
 
 namespace BindingDemo.ViewModels
 {
-    public class NestedCommandViewModel : ReactiveObject
+    public class NestedCommandViewModel : ViewModelBase
     {
         public NestedCommandViewModel()
         {
-            Command = ReactiveCommand.Create(() => { });
+            Command = MiniCommand.Create(() => { });
         }
 
         public ICommand Command { get; }

+ 2 - 2
samples/BindingDemo/ViewModels/TestItem.cs

@@ -1,8 +1,8 @@
-using ReactiveUI;
+using MiniMvvm;
 
 namespace BindingDemo.ViewModels
 {
-    public class TestItem : ReactiveObject
+    public class TestItem : ViewModelBase
     {
         private string _stringValue = "String Value";
         private string _detail;

+ 8 - 6
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@@ -16,7 +16,7 @@
     <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
     <AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
-    <TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
     <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@@ -71,21 +71,23 @@
     <Compile Include="MainActivity.cs" />
     <Compile Include="Resources\Resource.Designer.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SplashActivity.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="Resources\AboutResources.txt" />
     <None Include="Assets\AboutAssets.txt" />
   </ItemGroup>
   <ItemGroup>
-    <AndroidResource Include="Resources\layout\Main.axml">
-      <SubType>Designer</SubType>
-    </AndroidResource>
+    <AndroidResource Include="Resources\drawable\splash_screen.xml" />
   </ItemGroup>
   <ItemGroup>
-    <AndroidResource Include="Resources\values\Strings.xml" />
+    <AndroidResource Include="Resources\values\colors.xml" />
+    <AndroidResource Include="Resources\values\styles.xml" />
   </ItemGroup>
   <ItemGroup>
-    <AndroidResource Include="Resources\drawable\Icon.png" />
+    <AndroidResource Include="..\..\build\Assets\Icon.png">
+      <Link>Resources\drawable\Icon.png</Link>
+    </AndroidResource>
   </ItemGroup>
   <ItemGroup>
     <None Include="Properties\AndroidManifest.xml" />

+ 4 - 17
samples/ControlCatalog.Android/MainActivity.cs

@@ -1,31 +1,18 @@
-using System;
-using Android.App;
+using Android.App;
 using Android.OS;
 using Android.Content.PM;
 using Avalonia.Android;
-using Avalonia.Controls;
-using Avalonia.Controls.Templates;
-using Avalonia.Markup.Xaml;
-using Avalonia.Media;
-using Avalonia.Styling;
-using Avalonia.Themes.Default;
-using Avalonia;
 
 namespace ControlCatalog.Android
 {
-    [Activity(Label = "ControlCatalog.Android", MainLauncher = true, Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)]
+    [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)]
     public class MainActivity : AvaloniaActivity
     {
         protected override void OnCreate(Bundle savedInstanceState)
         {
-            if (Avalonia.Application.Current == null)           
-            {
-                AppBuilder.Configure<App>()
-                    .UseAndroid()
-                    .SetupWithoutStarting();
-                Content = new MainView();
-            }
             base.OnCreate(savedInstanceState);
+
+            Content = new MainView();
         }
     }
 }

+ 1 - 1
samples/ControlCatalog.Android/Properties/AndroidManifest.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ControlCatalog.Android" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
-	<uses-sdk />
+	<uses-sdk android:targetSdkVersion="30" />
 	<application android:label="ControlCatalog.Android"></application>
 </manifest>

+ 23 - 36
samples/ControlCatalog.Android/Resources/Resource.Designer.cs

@@ -2,7 +2,6 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:4.0.30319.42000
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
 //     the code is regenerated.
@@ -15,7 +14,7 @@ namespace ControlCatalog.Android
 {
 	
 	
-	[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+	[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
 	public partial class Resource
 	{
 		
@@ -26,8 +25,6 @@ namespace ControlCatalog.Android
 		
 		public static void UpdateIdValues()
 		{
-			global::Avalonia.Android.Resource.String.ApplicationName = global::ControlCatalog.Android.Resource.String.ApplicationName;
-			global::Avalonia.Android.Resource.String.Hello = global::ControlCatalog.Android.Resource.String.Hello;
 		}
 		
 		public partial class Attribute
@@ -43,69 +40,59 @@ namespace ControlCatalog.Android
 			}
 		}
 		
-		public partial class Drawable
+		public partial class Color
 		{
 			
-			// aapt resource value: 0x7f020000
-			public const int Icon = 2130837504;
+			// aapt resource value: 0x7F010000
+			public const int splash_background = 2130771968;
 			
-			static Drawable()
+			static Color()
 			{
 				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
 			}
 			
-			private Drawable()
+			private Color()
 			{
 			}
 		}
 		
-		public partial class Id
+		public partial class Drawable
 		{
 			
-			// aapt resource value: 0x7f050000
-			public const int MyButton = 2131034112;
-			
-			static Id()
-			{
-				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
-			}
-			
-			private Id()
-			{
-			}
-		}
-		
-		public partial class Layout
-		{
+			// aapt resource value: 0x7F020000
+			public const int Icon = 2130837504;
 			
-			// aapt resource value: 0x7f030000
-			public const int Main = 2130903040;
+			// aapt resource value: 0x7F020001
+			public const int splash_screen = 2130837505;
 			
-			static Layout()
+			static Drawable()
 			{
 				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
 			}
 			
-			private Layout()
+			private Drawable()
 			{
 			}
 		}
 		
-		public partial class String
+		public partial class Style
 		{
 			
-			// aapt resource value: 0x7f040001
-			public const int ApplicationName = 2130968577;
+			// aapt resource value: 0x7F030000
+			public const int MyTheme = 2130903040;
+			
+			// aapt resource value: 0x7F030001
+			public const int MyTheme_NoActionBar = 2130903041;
 			
-			// aapt resource value: 0x7f040000
-			public const int Hello = 2130968576;
+			// aapt resource value: 0x7F030002
+			public const int MyTheme_Splash = 2130903042;
 			
-			static String()
+			static Style()
 			{
 				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
 			}
 			
-			private String()
+			private Style()
 			{
 			}
 		}

BIN
samples/ControlCatalog.Android/Resources/drawable/Icon.png


+ 13 - 0
samples/ControlCatalog.Android/Resources/drawable/splash_screen.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+  <item>
+    <color android:color="@color/splash_background"/>
+  </item>
+
+  <item android:drawable="@drawable/icon"
+        android:width="120dp"
+        android:height="120dp"
+        android:gravity="center" />
+
+</layer-list>

+ 0 - 13
samples/ControlCatalog.Android/Resources/layout/Main.axml

@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-<Button  
-    android:id="@+id/MyButton"
-    android:layout_width="match_parent" 
-    android:layout_height="wrap_content" 
-    android:text="@string/Hello"
-    />
-</LinearLayout>

+ 0 - 5
samples/ControlCatalog.Android/Resources/values/Strings.xml

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="Hello">Hello World, Click Me!</string>
-    <string name="ApplicationName">ControlCatalog.Android</string>
-</resources>

+ 4 - 0
samples/ControlCatalog.Android/Resources/values/colors.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <color name="splash_background">#FFFFFF</color>
+</resources>

+ 17 - 0
samples/ControlCatalog.Android/Resources/values/styles.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<resources>
+
+  <style name="MyTheme">
+  </style>
+
+  <style name="MyTheme.NoActionBar">
+    <item name="android:windowActionBar">false</item>
+    <item name="android:windowNoTitle">true</item>
+  </style>
+
+  <style name="MyTheme.Splash" parent ="MyTheme.NoActionBar">
+    <item name="android:windowBackground">@drawable/splash_screen</item>
+    <item name="android:windowContentOverlay">@null</item>
+  </style>
+
+</resources>

+ 32 - 0
samples/ControlCatalog.Android/SplashActivity.cs

@@ -0,0 +1,32 @@
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Application = Android.App.Application;
+
+using Avalonia;
+
+namespace ControlCatalog.Android
+{
+    [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
+    public class SplashActivity : Activity
+    {
+        protected override void OnCreate(Bundle savedInstanceState)
+        {
+            base.OnCreate(savedInstanceState);
+        }
+
+        protected override void OnResume()
+        {
+            base.OnResume();
+
+            if (Avalonia.Application.Current == null)
+            {
+                AppBuilder.Configure<App>()
+                    .UseAndroid()
+                    .SetupWithoutStarting();
+            }
+
+            StartActivity(new Intent(Application.Context, typeof(MainActivity)));
+        }
+    }
+}

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

@@ -3,7 +3,6 @@ using System.Linq;
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Platform;
-using Avalonia.ReactiveUI;
 
 namespace ControlCatalog
 {
@@ -19,8 +18,7 @@ namespace ControlCatalog
         public static AppBuilder BuildAvaloniaApp()
             => AppBuilder.Configure<App>()
                 .LogToTrace()
-                .UsePlatformDetect()
-                .UseReactiveUI();
+                .UsePlatformDetect();
 
         private static void ConfigureAssetAssembly(AppBuilder builder)
         {

+ 5 - 1
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <OutputType>Exe</OutputType>
+    <OutputType>WinExe</OutputType>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
   </PropertyGroup>
@@ -15,6 +15,10 @@
     <PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
   </ItemGroup>
 
+  <PropertyGroup>
+    <!-- For Microsoft.CodeAnalysis -->
+    <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
+  </PropertyGroup>
 
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\ReferenceCoreLibraries.props" />

+ 3 - 5
samples/ControlCatalog.NetCore/Program.cs

@@ -10,7 +10,6 @@ using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Dialogs;
 using Avalonia.Headless;
 using Avalonia.LogicalTree;
-using Avalonia.ReactiveUI;
 using Avalonia.Threading;
 
 namespace ControlCatalog.NetCore
@@ -110,15 +109,14 @@ namespace ControlCatalog.NetCore
                 .With(new X11PlatformOptions
                 {
                     EnableMultiTouch = true,
-                    UseDBusMenu = true
+                    UseDBusMenu = true,
+                    EnableIme = true,
                 })
                 .With(new Win32PlatformOptions
                 {
-                    EnableMultitouch = true,
-                    AllowEglInitialization = true
+                    EnableMultitouch = true
                 })
                 .UseSkia()
-                .UseReactiveUI()
                 .UseManagedSystemDialogs()
                 .LogToTrace();
 

+ 10 - 2
samples/ControlCatalog/App.xaml.cs

@@ -23,7 +23,7 @@ namespace ControlCatalog
         {
             new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
             {
-                Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/FluentDark.xaml")
+                Source = new Uri("avares://Avalonia.Themes.Fluent/FluentDark.xaml")
             },
             DataGridFluent
         };
@@ -32,13 +32,17 @@ namespace ControlCatalog
         {
             new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
             {
-                Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/FluentLight.xaml")
+                Source = new Uri("avares://Avalonia.Themes.Fluent/FluentLight.xaml")
             },
             DataGridFluent
         };
 
         public static Styles DefaultLight = new Styles
         {
+            new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+            {
+                Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
+            },
             new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
             {
                 Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")
@@ -60,6 +64,10 @@ namespace ControlCatalog
 
         public static Styles DefaultDark = new Styles
         {
+            new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+            {
+                Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
+            },
             new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
             {
                 Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")

BIN
samples/ControlCatalog/Assets/Fonts/WenQuanYiMicroHei-01.ttf


BIN
samples/ControlCatalog/Assets/avalonia-32.png


+ 2 - 2
samples/ControlCatalog/ControlCatalog.csproj

@@ -24,9 +24,9 @@
   <ItemGroup>
     <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
+    <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
   </ItemGroup>
-  
+
   <Import Project="..\..\build\BuildTargets.targets" />
 </Project>

+ 13 - 17
samples/ControlCatalog/DecoratedWindow.xaml

@@ -6,25 +6,21 @@
         <NativeMenu.Menu>
     <NativeMenu>
       <NativeMenuItem Header="Decorated">
-        <NativeMenuItem.Menu>
-          <NativeMenu>
-            <NativeMenuItem Header="Open"/>
-            <NativeMenuItem Header="Recent">
-              <NativeMenuItem.Menu>
-                <NativeMenu/>
-              </NativeMenuItem.Menu>
-            </NativeMenuItem>
-            <NativeMenuItem Header="Quit Avalonia" Gesture="CMD+Q"/>
-          </NativeMenu>
-        </NativeMenuItem.Menu>
+        <NativeMenu>
+          <NativeMenuItem Header="Open"/>
+          <NativeMenuItem Header="Recent">
+            <NativeMenuItem.Menu>
+              <NativeMenu/>
+            </NativeMenuItem.Menu>
+          </NativeMenuItem>
+          <NativeMenuItem Header="Quit Avalonia" Gesture="CMD+Q"/>
+        </NativeMenu>
       </NativeMenuItem>
       <NativeMenuItem Header="Edit">
-        <NativeMenuItem.Menu>
-          <NativeMenu>
-            <NativeMenuItem Header="Copy"/>
-            <NativeMenuItem Header="Paste"/>
-          </NativeMenu>
-        </NativeMenuItem.Menu>
+        <NativeMenu>
+          <NativeMenuItem Header="Copy"/>
+          <NativeMenuItem Header="Paste"/>
+        </NativeMenu>
       </NativeMenuItem>
     </NativeMenu>
   </NativeMenu.Menu>

+ 10 - 0
samples/ControlCatalog/MainView.xaml

@@ -21,7 +21,14 @@
       <TabItem Header="Carousel"><pages:CarouselPage/></TabItem>
       <TabItem Header="CheckBox"><pages:CheckBoxPage/></TabItem>
       <TabItem Header="ComboBox"><pages:ComboBoxPage/></TabItem>
+      <TabItem Header="ContextFlyout">
+        <pages:ContextFlyoutPage/>
+      </TabItem>
       <TabItem Header="ContextMenu"><pages:ContextMenuPage/></TabItem>
+      <TabItem Header="Cursor"
+               ScrollViewer.VerticalScrollBarVisibility="Disabled">
+        <pages:CursorPage/>
+      </TabItem>
       <TabItem Header="DataGrid" 
                ScrollViewer.VerticalScrollBarVisibility="Disabled"
                ScrollViewer.HorizontalScrollBarVisibility="Disabled">
@@ -34,6 +41,9 @@
         <pages:CalendarDatePickerPage/></TabItem>
       <TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem>
       <TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
+      <TabItem Header="Flyouts">
+        <pages:FlyoutsPage />
+      </TabItem>
       <TabItem Header="Image"
                ScrollViewer.VerticalScrollBarVisibility="Disabled"
                ScrollViewer.HorizontalScrollBarVisibility="Disabled">

+ 29 - 37
samples/ControlCatalog/MainWindow.xaml

@@ -16,47 +16,39 @@
   <NativeMenu.Menu>
     <NativeMenu>
       <NativeMenuItem Header="File">
-        <NativeMenuItem.Menu>
-          <NativeMenu>
-            <NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Clicked="OnOpenClicked" Gesture="Ctrl+O"/>
-            <NativeMenuItemSeperator/>
-            <NativeMenuItem Icon="/Assets/github_icon.png" Header="Recent">
-              <NativeMenuItem.Menu>
-                <NativeMenu/>
-              </NativeMenuItem.Menu>
-            </NativeMenuItem>
-            <NativeMenuItemSeperator/>
-            <NativeMenuItem Header="{x:Static local:MainWindow.MenuQuitHeader}"
-                            Gesture="{x:Static local:MainWindow.MenuQuitGesture}"
-                            Clicked="OnCloseClicked" />
-          </NativeMenu>
-        </NativeMenuItem.Menu>
+        <NativeMenu>
+          <NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Clicked="OnOpenClicked" Gesture="Ctrl+O"/>
+          <NativeMenuItemSeperator/><!-- Uses incorrect spelling to demonstrate backwards compatibility -->
+          <NativeMenuItem Icon="/Assets/github_icon.png" Header="Recent">
+            <NativeMenu/>
+          </NativeMenuItem>
+          <NativeMenuItemSeparator/>
+          <NativeMenuItem Header="{x:Static local:MainWindow.MenuQuitHeader}"
+                          Gesture="{x:Static local:MainWindow.MenuQuitGesture}"
+                          Clicked="OnCloseClicked" />
+        </NativeMenu>
       </NativeMenuItem>
       <NativeMenuItem Header="Edit">
-        <NativeMenuItem.Menu>
-          <NativeMenu>
-            <NativeMenuItem Header="Copy"/>
-            <NativeMenuItem Header="Paste"/>
-          </NativeMenu>
-        </NativeMenuItem.Menu>
+        <NativeMenu>
+          <NativeMenuItem Header="Copy"/>
+          <NativeMenuItem Header="Paste"/>
+        </NativeMenu>
       </NativeMenuItem>
       <NativeMenuItem Header="Options">
-        <NativeMenuItem.Menu>
-          <NativeMenu>
-           <NativeMenuItem Header="Check Me (None)" 
-                            Command="{Binding ToggleMenuItemCheckedCommand}"
-                            ToggleType="None"
-                            IsChecked="{Binding IsMenuItemChecked}"  />
-            <NativeMenuItem Header="Check Me (CheckBox)" 
-                            Command="{Binding ToggleMenuItemCheckedCommand}"
-                            ToggleType="CheckBox"
-                            IsChecked="{Binding IsMenuItemChecked}"  />
-            <NativeMenuItem Header="Check Me (Radio)" 
-                            Command="{Binding ToggleMenuItemCheckedCommand}"
-                            ToggleType="Radio"
-                            IsChecked="{Binding IsMenuItemChecked}"  />
-          </NativeMenu>
-        </NativeMenuItem.Menu>
+        <NativeMenu>
+          <NativeMenuItem Header="Check Me (None)" 
+                          Command="{Binding ToggleMenuItemCheckedCommand}"
+                          ToggleType="None"
+                          IsChecked="{Binding IsMenuItemChecked}"  />
+          <NativeMenuItem Header="Check Me (CheckBox)" 
+                          Command="{Binding ToggleMenuItemCheckedCommand}"
+                          ToggleType="CheckBox"
+                          IsChecked="{Binding IsMenuItemChecked}"  />
+          <NativeMenuItem Header="Check Me (Radio)" 
+                          Command="{Binding ToggleMenuItemCheckedCommand}"
+                          ToggleType="Radio"
+                          IsChecked="{Binding IsMenuItemChecked}"  />
+        </NativeMenu>
       </NativeMenuItem>
     </NativeMenu>
   </NativeMenu.Menu>

+ 1 - 1
samples/ControlCatalog/MainWindow.xaml.cs

@@ -67,7 +67,7 @@ namespace ControlCatalog
             if (Application.Current.Styles.Contains(App.FluentDark)
                 || Application.Current.Styles.Contains(App.FluentLight))
             {
-                var theme = new Avalonia.Themes.Fluent.FluentTheme();
+                var theme = new Avalonia.Themes.Fluent.Controls.FluentControls();
                 theme.TryGetResource("Button", out _);
             }
             else

+ 4 - 4
samples/ControlCatalog/Pages/AcrylicPage.xaml

@@ -16,13 +16,13 @@
         <StackPanel Spacing="5" Margin="40 10">
           <StackPanel Orientation="Horizontal">
             <TextBlock Text="TintOpacity" Foreground="Black" />
-            <Slider Name="TintOpacitySlider" Minimum="0" Maximum="1" Value="0.9" Width="400" />
-            <TextBlock Text="{Binding #TintOpacitySlider.Value}" Foreground="Black" />
+            <Slider Name="TintOpacitySlider" Minimum="0" Maximum="1" Value="0.9" SmallChange="0.1" LargeChange="0.2" Width="400" />
+            <TextBlock Text="{Binding #TintOpacitySlider.Value, StringFormat=\{0:0.#\}}" Foreground="Black" />
           </StackPanel>
           <StackPanel Orientation="Horizontal">
             <TextBlock Text="MaterialOpacity" Foreground="Black" />
-            <Slider Name="MaterialOpacitySlider" Minimum="0" Maximum="1" Value="0.8" Width="400" />
-            <TextBlock Text="{Binding #MaterialOpacitySlider.Value}" Foreground="Black" />
+            <Slider Name="MaterialOpacitySlider" Minimum="0" Maximum="1" Value="0.8" SmallChange="0.1" LargeChange="0.2" Width="400" />
+            <TextBlock Text="{Binding #MaterialOpacitySlider.Value, StringFormat=\{0:0.#\}}" Foreground="Black" />
           </StackPanel>
         </StackPanel>
       </ExperimentalAcrylicBorder>

+ 102 - 0
samples/ControlCatalog/Pages/ContextFlyoutPage.axaml

@@ -0,0 +1,102 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+             x:Class="ControlCatalog.Pages.ContextFlyoutPage">
+    <UserControl.Styles>
+        <Style Selector="FlyoutPresenter.NoPadding">
+            <Setter Property="Padding" Value="0" />
+        </Style>
+    </UserControl.Styles>
+    
+    <StackPanel Orientation="Vertical" Spacing="4">
+        <TextBlock Classes="h1">Context Flyout</TextBlock>
+        <TextBlock Classes="h2">A right click Flyout that can be applied to any control.</TextBlock>
+
+        <StackPanel Orientation="Horizontal"
+              Margin="0,16,0,0"
+              HorizontalAlignment="Center"
+              Spacing="16">
+            <Border Background="{DynamicResource SystemAccentColor}"
+                    Margin="16"
+                    Padding="48,48,48,48">
+                <Border.ContextFlyout>
+                    <MenuFlyout>
+                        <MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" />
+                        <MenuItem Header="_Disabled Menu Item" IsEnabled="False" InputGesture="Ctrl+D" />
+                        <Separator/>
+                        <MenuItem Header="Menu with _Submenu">
+                            <MenuItem Header="Submenu _1"/>
+                            <MenuItem Header="Submenu _2"/>
+                        </MenuItem>
+                        <MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B">
+                            <MenuItem.Icon>
+                                <Image Source="/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>
+                    </MenuFlyout>
+                </Border.ContextFlyout>
+                <TextBlock Text="Defined in XAML"/>
+            </Border>
+            <Border Background="{DynamicResource SystemAccentColor}"
+                    Margin="16"
+                    Padding="48,48,48,48">
+                <Border.ContextMenu>
+                    <ContextMenu Items="{Binding MenuItems}">
+                        <ContextMenu.Styles>
+                            <Style Selector="MenuItem">
+                                <Setter Property="Header" Value="{Binding Header}"/>
+                                <Setter Property="Items" Value="{Binding Items}"/>
+                                <Setter Property="Command" Value="{Binding Command}"/>
+                                <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
+                            </Style>
+                        </ContextMenu.Styles>
+                    </ContextMenu>
+                </Border.ContextMenu>
+                <TextBlock Text="Dynamically Generated"/>
+            </Border>
+        </StackPanel>
+
+        <TextBlock Text="Custom ContextFlyout for TextBox" />
+
+        <TextBox Name="TextBox" Width="150" HorizontalAlignment="Center" ContextMenu="{x:Null}">
+            <TextBox.ContextFlyout>
+                <Flyout FlyoutPresenterClasses="NoPadding">
+                    <StackPanel Orientation="Horizontal">
+                        <StackPanel.Styles>
+                            <Style Selector="Button">
+                                <Setter Property="Background" Value="Transparent" />
+                                <Setter Property="Height" Value="40" />
+                                <Setter Property="Width" Value="40" />
+                                <Setter Property="VerticalContentAlignment" Value="Center" />
+                            </Style>
+                            <Style Selector="Button:disabled /template/ ContentPresenter#PART_ContentPresenter">
+                                <Setter Property="Background" Value="Transparent" />
+                                <Setter Property="Opacity" Value="0.5" />
+                            </Style>
+                        </StackPanel.Styles>
+                        <Button Name="CutButton" Command="{Binding $parent[TextBox].Cut}" IsEnabled="{Binding $parent[TextBox].CanCut}">
+                            <PathIcon Width="14" Height="14" Data="M5.22774,2.08072 C5.43359778,1.94704 5.7011484,1.98419259 5.86368634,2.15675215 L5.91939,2.22774 L12.5191,12.3904 C12.956,12.1419 13.4614,12.0000019 14,12.0000019 C15.6569,12.0000019 17,13.3431 17,15.0000019 C17,16.6569 15.6569,18.0000019 14,18.0000019 C12.3431,18.0000019 11,16.6569 11,15.0000019 C11,14.3201402 11.226152,13.693011 11.6073785,13.1899092 L11.7401,13.0269 L10,10.3474 L8.25991,13.0269 C8.72078,13.5543 9,14.2446 9,15.0000019 C9,16.6569 7.65685,18.0000019 6,18.0000019 C4.34315,18.0000019 3,16.6569 3,15.0000019 C3,13.3431 4.34315,12.0000019 6,12.0000019 C6.46163143,12.0000019 6.89890041,12.1042536 7.28955831,12.2905296 L7.4809,12.3904 L9.40382,9.42936 L5.08072,2.77238 C4.93033,2.54079 4.99615,2.23112 5.22774,2.08072 Z M14,13 C12.8954,13 12,13.8954 12,15 C12,16.1046 12.8954,17 14,17 C15.1046,17 16,16.1046 16,15 C16,13.8954 15.1046,13 14,13 Z M6,13 C4.89543,13 4,13.8954 4,15 C4,16.1046 4.89543,17 6,17 C7.10457,17 8,16.1046 8,15 C8,13.8954 7.10457,13 6,13 Z M14.7723,2.08072 C15.0039,2.23112 15.0697,2.54079 14.9193,2.77238 L11.1924,8.51133 L10.5962,7.59329 L14.0806,2.22774 C14.231,1.99615 14.5407,1.93033 14.7723,2.08072 Z" />
+                        </Button>
+                        <Button Name="CopyButton" Command="{Binding $parent[TextBox].Copy}" IsEnabled="{Binding $parent[TextBox].CanCopy}">
+                            <PathIcon Width="14" Height="14" Data="M5.50280381,4.62704038 L5.5,6.75 L5.5,17.2542087 C5.5,19.0491342 6.95507456,20.5042087 8.75,20.5042087 L17.3662868,20.5044622 C17.057338,21.3782241 16.2239751,22.0042087 15.2444057,22.0042087 L8.75,22.0042087 C6.12664744,22.0042087 4,19.8775613 4,17.2542087 L4,6.75 C4,5.76928848 4.62744523,4.93512464 5.50280381,4.62704038 Z M17.75,2 C18.9926407,2 20,3.00735931 20,4.25 L20,17.25 C20,18.4926407 18.9926407,19.5 17.75,19.5 L8.75,19.5 C7.50735931,19.5 6.5,18.4926407 6.5,17.25 L6.5,4.25 C6.5,3.00735931 7.50735931,2 8.75,2 L17.75,2 Z M17.75,3.5 L8.75,3.5 C8.33578644,3.5 8,3.83578644 8,4.25 L8,17.25 C8,17.6642136 8.33578644,18 8.75,18 L17.75,18 C18.1642136,18 18.5,17.6642136 18.5,17.25 L18.5,4.25 C18.5,3.83578644 18.1642136,3.5 17.75,3.5 Z" />
+                        </Button>
+                        <Button Name="PasteButton" Command="{Binding $parent[TextBox].Paste}" IsEnabled="{Binding $parent[TextBox].CanPaste}">
+                            <PathIcon Width="14" Height="14" Data="M13.75,2 C14.940864,2 15.9156449,2.92516159 15.9948092,4.09595119 L16,4.25 L16,4.25 C16,4.16530567 15.9953205,4.0817043 15.9862059,3.99944035 L17.75,4 C18.9926407,4 20,5.00735931 20,6.25 L20,19.75 C20,20.9926407 18.9926407,22 17.75,22 L6.25,22 C5.00735931,22 4,20.9926407 4,19.75 L4,6.25 C4,5.00735931 5.00735931,4 6.25,4 L8.01379413,3.99944035 C8.00733496,4.05773764 8.00310309,4.11670658 8.00118552,4.17626017 L8,4.25 C8,3.00735931 9.00735931,2 10.25,2 L13.75,2 Z M13.75,6.5 L10.25,6.5 C9.45594921,6.5 8.75796956,6.08867052 8.357512,5.4674625 L8.37902077,5.50019943 L8.37902077,5.50019943 L6.25,5.5 C5.83578644,5.5 5.5,5.83578644 5.5,6.25 L5.5,19.75 C5.5,20.1642136 5.83578644,20.5 6.25,20.5 L17.75,20.5 C18.1642136,20.5 18.5,20.1642136 18.5,19.75 L18.5,6.25 C18.5,5.83578644 18.1642136,5.5 17.75,5.5 L15.6209792,5.50019943 L15.642488,5.4674625 C15.2420304,6.08867052 14.5440508,6.5 13.75,6.5 Z M13.75,3.5 L10.25,3.5 C9.83578644,3.5 9.5,3.83578644 9.5,4.25 C9.5,4.66421356 9.83578644,5 10.25,5 L13.75,5 C14.1642136,5 14.5,4.66421356 14.5,4.25 C14.5,3.83578644 14.1642136,3.5 13.75,3.5 Z" />
+                        </Button>
+                        <Button Name="ClearButton" Command="{Binding $parent[TextBox].Clear}">
+                            <PathIcon Width="14" Height="14" Data="M3.52499419,3.71761187 L3.61611652,3.61611652 C4.0717282,3.16050485 4.79154862,3.13013074 5.28238813,3.52499419 L5.38388348,3.61611652 L14,12.233 L22.6161165,3.61611652 C23.1042719,3.12796116 23.8957281,3.12796116 24.3838835,3.61611652 C24.8720388,4.10427189 24.8720388,4.89572811 24.3838835,5.38388348 L15.767,14 L24.3838835,22.6161165 C24.8394952,23.0717282 24.8698693,23.7915486 24.4750058,24.2823881 L24.3838835,24.3838835 C23.9282718,24.8394952 23.2084514,24.8698693 22.7176119,24.4750058 L22.6161165,24.3838835 L14,15.767 L5.38388348,24.3838835 C4.89572811,24.8720388 4.10427189,24.8720388 3.61611652,24.3838835 C3.12796116,23.8957281 3.12796116,23.1042719 3.61611652,22.6161165 L12.233,14 L3.61611652,5.38388348 C3.16050485,4.9282718 3.13013074,4.20845138 3.52499419,3.71761187 L3.61611652,3.61611652 L3.52499419,3.71761187 Z" />
+                        </Button>
+                    </StackPanel>
+                </Flyout>
+            </TextBox.ContextFlyout>
+        </TextBox>
+    
+    </StackPanel>
+</UserControl>

+ 45 - 0
samples/ControlCatalog/Pages/ContextFlyoutPage.axaml.cs

@@ -0,0 +1,45 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using ControlCatalog.ViewModels;
+using Avalonia.Interactivity;
+namespace ControlCatalog.Pages
+{
+    public class ContextFlyoutPage : UserControl
+    {
+        private TextBox _textBox;
+
+        public ContextFlyoutPage()
+        {
+            InitializeComponent();
+
+            var vm = new ContextFlyoutPageViewModel();
+            vm.View = this;
+            DataContext = vm;
+
+            _textBox = this.FindControl<TextBox>("TextBox");
+
+            var cutButton = this.FindControl<Button>("CutButton");
+            cutButton.Click += CloseFlyout;
+
+            var copyButton = this.FindControl<Button>("CopyButton");
+            copyButton.Click += CloseFlyout;
+
+            var pasteButton = this.FindControl<Button>("PasteButton");
+            pasteButton.Click += CloseFlyout;
+
+            var clearButton = this.FindControl<Button>("ClearButton");
+            clearButton.Click += CloseFlyout;
+        }
+
+        private void CloseFlyout(object sender, RoutedEventArgs e)
+        {
+            _textBox.ContextFlyout.Hide();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

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

@@ -31,6 +31,7 @@
                                 <CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
                             </MenuItem.Icon>
                         </MenuItem>
+                        <MenuItem Header="Menu Item that won't close on click" StaysOpenOnClick="True" />
                     </ContextMenu>
                 </Border.ContextMenu>
                 <TextBlock Text="Defined in XAML"/>

+ 29 - 0
samples/ControlCatalog/Pages/CursorPage.xaml

@@ -0,0 +1,29 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             x:Class="ControlCatalog.Pages.CursorPage">
+  <Grid ColumnDefinitions="*,*" RowDefinitions="Auto,*">
+    <StackPanel Grid.ColumnSpan="2" Orientation="Vertical" Spacing="4">
+      <TextBlock Classes="h1">Cursor</TextBlock>
+      <TextBlock Classes="h2">Defines a cursor (mouse pointer)</TextBlock>
+    </StackPanel>
+
+    <ListBox Grid.Row="1" Items="{Binding StandardCursors}" Margin="0 8 8 8">
+      <ListBox.Styles>
+        <Style Selector="ListBoxItem">
+          <Setter Property="Cursor" Value="{Binding Cursor}"/>
+        </Style>
+      </ListBox.Styles>
+      <ListBox.ItemTemplate>
+        <DataTemplate>
+          <TextBlock Text="{Binding Type}"/>
+        </DataTemplate>
+      </ListBox.ItemTemplate>
+    </ListBox>
+
+    <StackPanel Grid.Column="1" Grid.Row="1" Margin="8 8 0 8">
+      <Button Cursor="{Binding CustomCursor}" Margin="0 8" Padding="16">
+        <TextBlock>Custom Cursor</TextBlock>
+      </Button>
+    </StackPanel>
+ </Grid>
+</UserControl>

+ 20 - 0
samples/ControlCatalog/Pages/CursorPage.xaml.cs

@@ -0,0 +1,20 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using ControlCatalog.ViewModels;
+
+namespace ControlCatalog.Pages
+{
+    public class CursorPage : UserControl
+    {
+        public CursorPage()
+        {
+            this.InitializeComponent();
+            DataContext = new CursorPageViewModel();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 5 - 4
samples/ControlCatalog/Pages/DataGridPage.xaml

@@ -1,5 +1,5 @@
 <UserControl xmlns="https://github.com/avaloniaui"
-             xmlns:local="clr-namespace:ControlCatalog.Models;assembly=ControlCatalog"
+             xmlns:local="using:ControlCatalog.Models"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              x:Class="ControlCatalog.Pages.DataGridPage">
   <UserControl.Resources>
@@ -26,7 +26,8 @@
         <DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All">
           <DataGrid.Columns>
             <DataGridTextColumn Header="Country" Binding="{Binding Name}" Width="6*" />
-            <DataGridTextColumn Header="Region" Binding="{Binding Region}" Width="4*" />
+            <!-- CompiledBinding example of usage. -->
+            <DataGridTextColumn Header="Region" Binding="{CompiledBinding Region}" Width="4*" x:DataType="local:Country" />
             <DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" />
             <DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" />
             <DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" CellStyleClasses="gdp" />
@@ -38,8 +39,8 @@
           <DataGrid.Columns>
             <DataGridTextColumn Header="Country" Binding="{Binding Name}" Width="6*" />
             <DataGridTextColumn Header="Region" Binding="{Binding Region}" Width="4*" />
-            <DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" />
-            <DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" />
+            <DataGridTextColumn DisplayIndex="3" Header="Population" Binding="{Binding Population}" Width="3*" />
+            <DataGridTextColumn DisplayIndex="2" Header="Area" Binding="{Binding Area}" Width="3*" />
             <DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" />
           </DataGrid.Columns>
         </DataGrid>

+ 4 - 2
samples/ControlCatalog/Pages/DataGridPage.xaml.cs

@@ -24,8 +24,10 @@ namespace ControlCatalog.Pages
             dg1.LoadingRow += Dg1_LoadingRow;
             dg1.Sorting += (s, a) =>
             {
-                var property = ((a.Column as DataGridBoundColumn)?.Binding as Binding).Path;
-                if (property == dataGridSortDescription.PropertyPath
+                var binding = (a.Column as DataGridBoundColumn)?.Binding as Binding;
+
+                if (binding?.Path is string property
+                    && property == dataGridSortDescription.PropertyPath
                     && !collectionView1.SortDescriptions.Contains(dataGridSortDescription))
                 {
                     collectionView1.SortDescriptions.Add(dataGridSortDescription);

+ 24 - 5
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -4,6 +4,7 @@ using System.Linq;
 using System.Reflection;
 using Avalonia.Controls;
 using Avalonia.Dialogs;
+using Avalonia.Layout;
 using Avalonia.Markup.Xaml;
 #pragma warning disable 4014
 
@@ -112,11 +113,29 @@ namespace ControlCatalog.Pages
 
         private Window CreateSampleWindow()
         {
-            var window = new Window();
-            window.Height = 200;
-            window.Width = 200;
-            window.Content = new TextBlock { Text = "Hello world!" };
-            window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
+            Button button;
+            
+            var window = new Window
+            {
+                Height = 200,
+                Width = 200,
+                Content = new StackPanel
+                {
+                    Spacing = 4,
+                    Children =
+                    {
+                        new TextBlock { Text = "Hello world!" },
+                        (button = new Button
+                        {
+                            HorizontalAlignment = HorizontalAlignment.Center,
+                            Content = "Click to close"
+                        })
+                    }
+                },
+                WindowStartupLocation = WindowStartupLocation.CenterOwner
+            };
+
+            button.Click += (_, __) => window.Close();
 
             return window;
         }

+ 264 - 0
samples/ControlCatalog/Pages/FlyoutsPage.axaml

@@ -0,0 +1,264 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="700"
+             x:Class="ControlCatalog.Pages.FlyoutsPage">
+
+    <UserControl.Resources>
+        <MenuFlyout x:Key="SharedMenuFlyout">
+            <MenuItem Header="Item 1">
+                <MenuItem Header="Subitem 1" />
+                <MenuItem Header="Subitem 2" />
+                <MenuItem Header="Subitem 3" />
+            </MenuItem>
+            <MenuItem Header="Item 2" InputGesture="Ctrl+A" />
+            <MenuItem Header="Item 3" />
+        </MenuFlyout>
+        <Flyout Placement="Bottom" x:Key="BasicFlyout">
+            <Panel Width="100" Height="100">
+                <TextBlock Text="Flyout Content!" />
+            </Panel>
+        </Flyout>
+    </UserControl.Resources>
+
+    <ScrollViewer HorizontalScrollBarVisibility="Disabled">
+        <StackPanel Spacing="10">
+            <TextBlock FontSize="18" Text="Button with a Flyout" />
+            <StackPanel>
+                <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
+                        BorderThickness="1" Padding="15">
+                    <Button Content="Click Me!" Flyout="{StaticResource BasicFlyout}" />
+                </Border>
+                <Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
+                    <TextBlock Name="ButtonFlyoutXamlText" Padding="15" />
+                </Panel>
+            </StackPanel>
+
+            <TextBlock FontSize="18" Text="MenuFlyout" />
+            <StackPanel>
+                <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
+                        BorderThickness="1" Padding="15">
+                    <Button Content="Click Me!" Flyout="{StaticResource SharedMenuFlyout}" />
+                </Border>
+                <Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
+                    <TextBlock Name="MenuFlyoutXamlText" Padding="15" />
+                </Panel>
+            </StackPanel>
+
+            <TextBlock FontSize="18" Text="Attached Flyouts" />
+            <StackPanel>
+                <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
+                        BorderThickness="1" Padding="15">
+                    <Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}"
+                           HorizontalAlignment="Left"
+                           Height="100"
+                           Name="AttachedFlyoutPanel">
+                        <FlyoutBase.AttachedFlyout>
+                            <Flyout>
+                                <Panel Height="100">
+                                    <TextBlock Text="Attached Flyout!"
+                                               VerticalAlignment="Center"
+                                               Margin="10"/>
+                                </Panel>
+                            </Flyout>
+                        </FlyoutBase.AttachedFlyout>
+
+                        <TextBlock Text="Double click panel to launch AttachedFlyout"
+                                   VerticalAlignment="Center"
+                                   Margin="10"/>
+
+                    </Panel>
+                </Border>
+                <Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
+                    <TextBlock Name="AttachedFlyoutXamlText" Padding="15" />
+                </Panel>
+            </StackPanel>
+
+
+            <TextBlock FontSize="18" Text="Sharing Flyouts" />
+            <StackPanel>
+                <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
+                        BorderThickness="1" Padding="15">
+                    <StackPanel Orientation="Horizontal" Spacing="30">
+                        <Button Content="Launch Flyout on this button" Flyout="{StaticResource SharedMenuFlyout}"/>
+                        <Button Content="Launch Flyout on this button" Flyout="{StaticResource SharedMenuFlyout}"/>
+                    </StackPanel>
+                </Border>
+                <Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
+                    <TextBlock Name="SharedFlyoutXamlText" Padding="15" />
+                </Panel>
+            </StackPanel>
+
+            <TextBlock FontSize="18" Text="Flyout Placements" />
+            <StackPanel>
+                <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
+                        BorderThickness="1" Padding="15">
+                    <UniformGrid Columns="3">
+                        <UniformGrid.Styles>
+                            <Style Selector="Button">
+                                <Setter Property="Margin" Value="10" />
+                            </Style>
+                        </UniformGrid.Styles>
+                        <Button Content="Placement=Top">
+                            <Button.Flyout>
+                                <Flyout Placement="Top">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=Bottom">
+                            <Button.Flyout>
+                                <Flyout Placement="Bottom">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=Left">
+                            <Button.Flyout>
+                                <Flyout Placement="Left">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=Right">
+                            <Button.Flyout>
+                                <Flyout Placement="Right">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=TopEdgeAlignedLeft">
+                            <Button.Flyout>
+                                <Flyout Placement="TopEdgeAlignedLeft">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=TopEdgeAlignedRight">
+                            <Button.Flyout>
+                                <Flyout Placement="TopEdgeAlignedRight">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=BottomEdgeAlignedLeft">
+                            <Button.Flyout>
+                                <Flyout Placement="BottomEdgeAlignedLeft">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=BottomEdgeAlignedRight">
+                            <Button.Flyout>
+                                <Flyout Placement="BottomEdgeAlignedRight">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=LeftEdgeAlignedTop">
+                            <Button.Flyout>
+                                <Flyout Placement="LeftEdgeAlignedTop">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=LeftEdgeAlignedBottom">
+                            <Button.Flyout>
+                                <Flyout Placement="LeftEdgeAlignedBottom">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=RightEdgeAlignedBottom">
+                            <Button.Flyout>
+                                <Flyout Placement="RightEdgeAlignedTop">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="Placement=RightEdgeAlignedBottom">
+                            <Button.Flyout>
+                                <Flyout Placement="RightEdgeAlignedBottom">
+                                    <Panel Width="100" Height="100">
+                                        <TextBlock Text="Flyout Content!" />
+                                    </Panel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+
+                    </UniformGrid>
+                </Border>
+            </StackPanel>
+
+            <TextBlock FontSize="18" Text="Flyout ShowMode" />
+            <StackPanel>
+                <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
+                        BorderThickness="1" Padding="15">
+                    <WrapPanel Orientation="Horizontal">
+                        <WrapPanel.Styles>
+                            <Style Selector="Button">
+                                <Setter Property="Margin" Value="4" />
+                            </Style>
+                        </WrapPanel.Styles>
+                        <Button Content="ShowMode=Standard (default)">
+                            <Button.Flyout>
+                                <Flyout>
+                                    <StackPanel Width="200">
+                                        <TextBox />
+                                        <TextBlock Text="Standard ShowMode attempts to focus the Flyout when its opened" TextWrapping="Wrap"/>
+                                    </StackPanel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="ShowMode=Transient">
+                            <Button.Flyout>
+                                <Flyout ShowMode="Transient">
+                                    <StackPanel Width="200">
+                                        <TextBox />
+                                        <TextBlock Text="Transient ShowMode does not focus the Flyout when opened" TextWrapping="Wrap"/>
+                                    </StackPanel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        <Button Content="ShowMode=TransientWithDismissOnPointerMoveAway">
+                            <Button.Flyout>
+                                <Flyout ShowMode="TransientWithDismissOnPointerMoveAway">
+                                    <StackPanel Width="200">
+                                        <TextBox />
+                                        <TextBlock Text="Show in Transient mode (no focus), but closes the Flyout when the pointer moves away" TextWrapping="Wrap"/>
+                                    </StackPanel>
+                                </Flyout>
+                            </Button.Flyout>
+                        </Button>
+                        
+                    </WrapPanel>
+                </Border>
+            </StackPanel>
+            
+        </StackPanel>
+    </ScrollViewer>
+    
+</UserControl>

+ 81 - 0
samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs

@@ -0,0 +1,81 @@
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Markup.Xaml;
+using Avalonia.Interactivity;
+
+namespace ControlCatalog.Pages
+{
+    public class FlyoutsPage : UserControl
+    {
+        public FlyoutsPage()
+        {
+            InitializeComponent();
+
+            var afp = this.FindControl<Panel>("AttachedFlyoutPanel");
+            if (afp != null)
+            {
+                afp.DoubleTapped += Afp_DoubleTapped;
+            }
+
+            SetXamlTexts();
+        }
+
+        private void Afp_DoubleTapped(object sender, RoutedEventArgs e)
+        {
+            if (sender is Panel p)
+            {
+                FlyoutBase.ShowAttachedFlyout(p);
+            }
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        private void SetXamlTexts()
+        {
+            var bfxt = this.FindControl<TextBlock>("ButtonFlyoutXamlText");
+            bfxt.Text = "<Button Content=\"Click me!\">\n" +
+                        "    <Button.Flyout>\n" +
+                        "        <Flyout>\n" +
+                        "            <Panel Width=\"100\" Height=\"100\">\n" +
+                        "                <TextBlock Text=\"Flyout Content!\" />\n" +
+                        "            </Panel>\n" +
+                        "        </Flyout>\n" +
+                        "    </Button.Flyout>\n</Button>";
+
+            var mfxt = this.FindControl<TextBlock>("MenuFlyoutXamlText");
+            mfxt.Text = "<Button Content=\"Click me!\">\n" +
+                    "    <Button.Flyout>\n" +
+                    "        <MenuFlyout>\n" +
+                    "            <MenuItem Header=\"Item 1\">\n" +
+                    "            <MenuItem Header=\"Item 2\">\n" +
+                    "        </MenuFlyout>\n" +
+                    "    </Button.Flyout>\n</Button>";
+
+            var afxt = this.FindControl<TextBlock>("AttachedFlyoutXamlText");
+            afxt.Text = "<Panel Name=\"AttachedFlyoutPanel\">\n" +
+                "    <FlyoutBase.AttachedFlyout>\n" +
+                "        <Flyout>\n" +
+                "            <Panel Height=\"100\">\n" +
+                "                <TextBlock Text=\"Attached Flyout\" />\n" +
+                "            </Panel>\n" +
+                "        </Flyout>\n" +
+                "    </FlyoutBase.AttachedFlyout>\n</Panel>" + 
+                "\n\n In DoubleTapped handler:\n" +
+                "FlyoutBase.ShowAttachedFlyout(AttachedFlyoutPanel);";
+
+            var sfxt = this.FindControl<TextBlock>("SharedFlyoutXamlText");
+            sfxt.Text = "Declare a flyout in Resources:\n" +
+                "<Window.Resources>\n" +
+                "    <Flyout x:Key=\"SharedFlyout\">\n" +
+                "        <Panel Width=\"100\" Height=\"100\">\n" +
+                "            <TextBlock Text=\"Flyout Content!\" />\n" +
+                "        </Panel>\n" +
+                "    </Flyout>\n</Window.Resources>\n\n" +
+                "Then attach the flyout where you want it:\n" +
+                "<Button Content=\"Launch Flyout here\" Flyout=\"{StaticResource SharedFlyout}\" />";
+        }
+    }
+}

+ 0 - 1
samples/ControlCatalog/Pages/LabelsPage.axaml.cs

@@ -2,7 +2,6 @@
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 using ControlCatalog.Models;
-using ReactiveUI;
 
 namespace ControlCatalog.Pages
 {

+ 1 - 1
samples/ControlCatalog/Pages/ListBoxPage.xaml

@@ -20,6 +20,6 @@
     <ListBox Items="{Binding Items}"
              Selection="{Binding Selection}"
              AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}"
-             SelectionMode="{Binding SelectionMode}"/>
+             SelectionMode="{Binding SelectionMode^}"/>
   </DockPanel>
 </UserControl>

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

@@ -6,7 +6,6 @@ using System.Windows.Input;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 using ControlCatalog.ViewModels;
-using ReactiveUI;
 
 namespace ControlCatalog.Pages
 {

+ 2 - 2
samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs

@@ -6,7 +6,7 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls.Primitives;
 using Avalonia.Markup.Xaml;
-using ReactiveUI;
+using MiniMvvm;
 
 namespace ControlCatalog.Pages
 {
@@ -26,7 +26,7 @@ namespace ControlCatalog.Pages
 
     }
 
-    public class NumbersPageViewModel : ReactiveObject
+    public class NumbersPageViewModel : ViewModelBase
     {
         private IList<FormatObject> _formats;
         private FormatObject _selectedFormat;

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

@@ -15,6 +15,13 @@
         <Slider Name="hprogress" Maximum="100" Value="40" />
         <Slider Name="vprogress" Maximum="100" Value="60" />
       </StackPanel>
+
+      <StackPanel Spacing="10">
+        <ProgressBar VerticalAlignment="Center" IsIndeterminate="True" />
+        <ProgressBar VerticalAlignment="Center" Value="5" Maximum="10" />
+        <ProgressBar VerticalAlignment="Center" Value="50" />
+        <ProgressBar VerticalAlignment="Center" Value="50" Minimum="25" Maximum="75" />
+      </StackPanel>
     </StackPanel>
   </StackPanel>
 </UserControl>

+ 7 - 9
samples/ControlCatalog/Pages/ScreenPage.cs

@@ -29,7 +29,7 @@ namespace ControlCatalog.Pages
             var screens = w.Screens.All;
             var scaling = ((IRenderRoot)w).RenderScaling;
 
-            var drawBrush = Brushes.Green;
+            var drawBrush = Brushes.Black;
             Pen p = new Pen(drawBrush);
             if (screens != null)
                 foreach (Screen screen in screens)
@@ -45,18 +45,16 @@ namespace ControlCatalog.Pages
                                       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}";
+                    var text = new FormattedText() { Typeface = new Typeface("Arial"), FontSize = 18 };
+
+                    text.Text = $"Bounds: {screen.Bounds.TopLeft} {screen.Bounds.Width}:{screen.Bounds.Height}";
                     context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text);
                     
-                    text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
+                    text.Text = $"WorkArea: {screen.WorkingArea.TopLeft} {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
                     context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
 
                     text.Text = $"Scaling: {screen.PixelDensity * 100}%";
@@ -69,7 +67,7 @@ namespace ControlCatalog.Pages
                     context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), 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));
+            context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10));
         }
     }
 }

+ 2 - 2
samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs

@@ -2,11 +2,11 @@ using System.Collections.Generic;
 using Avalonia.Controls;
 using Avalonia.Controls.Primitives;
 using Avalonia.Markup.Xaml;
-using ReactiveUI;
+using MiniMvvm;
 
 namespace ControlCatalog.Pages
 {
-    public class ScrollViewerPageViewModel : ReactiveObject
+    public class ScrollViewerPageViewModel : ViewModelBase
     {
         private bool _allowAutoHide;
         private ScrollBarVisibility _horizontalScrollVisibility;

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

@@ -22,6 +22,20 @@
                 IsSnapToTickEnabled="True"
                 Ticks="0,20,25,40,75,100"
                 Width="300" />
+        <Slider Name="SliderWithTooltip"
+                Value="0"
+                Minimum="0"
+                Maximum="100"
+                Width="300">
+          <Slider.Styles>
+            <Style Selector="Slider /template/ Thumb">
+              <Setter Property="ToolTip.Tip" Value="{Binding $parent[Slider].Value, Mode=OneWay, StringFormat='Value \{0:f\}'}" />
+              <Setter Property="ToolTip.Placement" Value="Top" />
+              <Setter Property="ToolTip.VerticalOffset" Value="-10" />
+              <Setter Property="ToolTip.HorizontalOffset" Value="-30" />
+            </Style>
+          </Slider.Styles>
+        </Slider>
         <Slider Value="0"
                 Minimum="0"
                 Maximum="100"
@@ -31,6 +45,12 @@
             <sys:Exception /> 
           </DataValidationErrors.Error>
         </Slider>
+        <Slider Value="0"
+                IsDirectionReversed="True"
+                Minimum="0"
+                Maximum="100"
+                TickFrequency="10"
+                Width="300" />
       </StackPanel>
       <Slider Value="0"
               Minimum="0"
@@ -40,6 +60,15 @@
               TickPlacement="Outside"
               TickFrequency="10"
               Height="300"/>
+      <Slider Value="0"
+              IsDirectionReversed="True"
+              Minimum="0"
+              Maximum="100"
+              Orientation="Vertical"
+              IsSnapToTickEnabled="True"
+              TickPlacement="Outside"
+              TickFrequency="10"
+              Height="300"/>
     </StackPanel>
 
   </StackPanel>

+ 2 - 2
samples/ControlCatalog/Pages/TabControlPage.xaml.cs

@@ -6,7 +6,7 @@ using Avalonia.Markup.Xaml;
 using Avalonia.Media.Imaging;
 using Avalonia.Platform;
 
-using ReactiveUI;
+using MiniMvvm;
 
 namespace ControlCatalog.Pages
 {
@@ -56,7 +56,7 @@ namespace ControlCatalog.Pages
             return new Bitmap(assets.Open(new Uri(uri)));
         }
 
-        private class PageViewModel : ReactiveObject
+        private class PageViewModel : ViewModelBase
         {
             private Dock _tabPlacement;
 

+ 4 - 1
samples/ControlCatalog/Pages/TextBoxPage.xaml

@@ -13,7 +13,7 @@
       <StackPanel Orientation="Vertical" Spacing="8">
         <TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
         <TextBox Width="200" Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/>
-        <TextBox Width="200" Watermark="Watermark" />
+        <TextBox Width="200" Watermark="Numeric Watermark" x:Name="numericWatermark"/>
         <TextBox Width="200"
                  Watermark="Floating Watermark"
                  UseFloatingWatermark="True"
@@ -64,5 +64,8 @@
         <TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/>
       </StackPanel>
     </StackPanel>
+    <TextBox AcceptsReturn="True" TextWrapping="Wrap" Height="200" MaxWidth="400"
+             FontFamily="avares://ControlCatalog/Assets/Fonts#WenQuanYi Micro Hei"
+             Text="计算机科学(是系统性研究信息与计算的理论基础以及它们在计算机系统中如何实现与应用的实用技术的学科。它通常被形容为对那些创造、描述以及转换信息的算法处理的系统研究。计算机科学包含很多分支领域;有些强调特定结果的计算,比如计算机图形学;而有些是探討计算问题的性质,比如计算复杂性理论;还有一些领域專注于怎样实现计算,比如程式語言理論是研究描述计算的方法,而程式设计是应用特定的程式語言解决特定的计算问题,人机交互则是專注于怎样使计算机和计算变得有用、好用,以及随时随地为人所用。&#xD;&#xD;有时公众会误以为计算机科学就是解决计算机问题的事业(比如信息技术),或者只是与使用计算机的经验有关,如玩游戏、上网或者文字处理。其实计算机科学所关注的,不仅仅是去理解实现类似游戏、浏览器这些软件的程序的性质,更要通过现有的知识创造新的程序或者改进已有的程序。" />
   </StackPanel>
 </UserControl>

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

@@ -13,6 +13,12 @@ namespace ControlCatalog.Pages
         private void InitializeComponent()
         {
             AvaloniaXamlLoader.Load(this);
+
+            this.Get<TextBox>("numericWatermark")
+                .TextInputOptionsQuery += (s, a) =>
+                {
+                    a.ContentType = Avalonia.Input.TextInput.TextInputContentType.Number;
+                };
         }
     }
 }

+ 26 - 1
samples/ControlCatalog/Pages/ToolTipPage.xaml

@@ -6,7 +6,7 @@
         <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"
+        <Grid RowDefinitions="Auto,Auto,Auto"
               ColumnDefinitions="Auto,Auto"
               Margin="0,16,0,0"
               HorizontalAlignment="Center">
@@ -38,6 +38,31 @@
                 </ToolTip.Tip>
                 <TextBlock>ToolTip bottom placement</TextBlock>
             </Border>
+            <Border Grid.Row="2"
+                    Grid.ColumnSpan="2"
+                    Background="{DynamicResource SystemAccentColor}"
+                    Margin="5"
+                    Padding="50"
+                    ToolTip.Tip="Hello"
+                    ToolTip.Placement="Top">
+              <Border.Styles>
+                <Style Selector="Border">
+                  <Style.Animations>
+                    <Animation Duration="0:0:2" IterationCount="Infinite">
+                      <KeyFrame KeyTime="0:0:0">
+                        <Setter Property="ToolTip.HorizontalOffset" Value="0" />
+                        <Setter Property="ToolTip.VerticalOffset" Value="-50" />
+                      </KeyFrame>
+                      <KeyFrame KeyTime="0:0:2" >
+                        <Setter Property="ToolTip.HorizontalOffset" Value="100" />
+                        <Setter Property="ToolTip.VerticalOffset" Value="50" />
+                      </KeyFrame>
+                    </Animation>
+                  </Style.Animations>
+                </Style>
+              </Border.Styles>
+              <TextBlock>Moving offset</TextBlock>
+            </Border>
         </Grid>
     </StackPanel>
 </UserControl>

+ 23 - 53
samples/ControlCatalog/Pages/ViewboxPage.xaml

@@ -1,66 +1,36 @@
 <UserControl xmlns="https://github.com/avaloniaui"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              x:Class="ControlCatalog.Pages.ViewboxPage">
-    <UserControl.Resources>
-        <StreamGeometry x:Key="Acorn">
-            F1 M 16.6309,18.6563C 17.1309,
-            8.15625 29.8809,14.1563 29.8809,
-            14.1563C 30.8809,11.1563 34.1308,
-            11.4063 34.1308,11.4063C 33.5,12
-            34.6309,13.1563 34.6309,13.1563C
-            32.1309,13.1562 31.1309,14.9062
-            31.1309,14.9062C 41.1309,23.9062
-            32.6309,27.9063 32.6309,27.9062C
-            24.6309,24.9063 21.1309,22.1562
-            16.6309,18.6563 Z M 16.6309,19.9063C
-            21.6309,24.1563 25.1309,26.1562
-            31.6309,28.6562C 31.6309,28.6562
-            26.3809,39.1562 18.3809,36.1563C
-            18.3809,36.1563 18,38 16.3809,36.9063C
-            15,36 16.3809,34.9063 16.3809,34.9063C
-            16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z
-        </StreamGeometry>
-    </UserControl.Resources>
 
-    <Grid RowDefinitions="Auto,*">
+    <Grid RowDefinitions="Auto,*,*">
         <StackPanel Orientation="Vertical" Spacing="4">
             <TextBlock Classes="h1">Viewbox</TextBlock>
             <TextBlock Classes="h2">A control used to scale single child.</TextBlock>
         </StackPanel>
-        <Grid ColumnDefinitions="Auto,*,*"
-              RowDefinitions="*,*,*,*"
-              Grid.Row="1" Margin="48"
-              MaxWidth="400">
-            <TextBlock Grid.Row="0" VerticalAlignment="Center">None</TextBlock>
-            <TextBlock Grid.Row="1" VerticalAlignment="Center">Fill</TextBlock>
-            <TextBlock Grid.Row="2" VerticalAlignment="Center">Uniform</TextBlock>
-            <TextBlock Grid.Row="3" VerticalAlignment="Center">UniformToFill</TextBlock>
 
-            <Viewbox Grid.Row="0" Grid.Column="1" Stretch="None">
-                <TextBlock>Hello World!</TextBlock>
-            </Viewbox>
-            <Viewbox Grid.Row="1" Grid.Column="1" Stretch="Fill">
-                <TextBlock>Hello World!</TextBlock>
-            </Viewbox>
-            <Viewbox Grid.Row="2" Grid.Column="1" Stretch="Uniform">
-                <TextBlock>Hello World!</TextBlock>
-            </Viewbox>
-            <Viewbox Grid.Row="3" Grid.Column="1" Stretch="UniformToFill">
-                <TextBlock>Hello World!</TextBlock>
-            </Viewbox>
+        <Grid Grid.Row="1" ColumnDefinitions="*,Auto" HorizontalAlignment="Center" Margin="0,10,0,0">
 
-            <Viewbox Grid.Row="0" Grid.Column="2" Stretch="None">
-                <Path Fill="Blue" Data="{StaticResource Acorn}"/>
-            </Viewbox>
-            <Viewbox Grid.Row="1" Grid.Column="2" Stretch="Fill">
-                <Path Fill="Blue" Data="{StaticResource Acorn}"/>
-            </Viewbox>
-            <Viewbox Grid.Row="2" Grid.Column="2" Stretch="Uniform">
-                <Path Fill="Blue" Data="{StaticResource Acorn}"/>
-            </Viewbox>
-            <Viewbox Grid.Row="3" Grid.Column="2" Stretch="UniformToFill">
-                <Path Fill="Blue" Data="{StaticResource Acorn}"/>
-            </Viewbox>
+          <Border HorizontalAlignment="Center" Grid.Column="0" BorderThickness="1" BorderBrush="Orange" Width="200" Height="200">
+            <Border VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0" BorderThickness="1" BorderBrush="CornflowerBlue" Width="{Binding #WidthSlider.Value}" Height="{Binding #HeightSlider.Value}" >
+              <Viewbox
+                  Stretch="{Binding #StretchSelector.SelectedItem}"
+                  StretchDirection="{Binding #StretchDirectionSelector.SelectedItem}">
+                <Ellipse Width="50" Height="50" Fill="CornflowerBlue" />
+              </Viewbox>
+            </Border>
+          </Border>
+
+          <StackPanel HorizontalAlignment="Left" Orientation="Vertical" Grid.Column="1" Margin="8,0,0,0" Width="150">
+            <TextBlock Text="Width" />
+            <Slider Minimum="10" Maximum="200" Value="100" x:Name="WidthSlider" TickFrequency="25" TickPlacement="TopLeft" />
+            <TextBlock Text="Height" />
+            <Slider Minimum="10" Maximum="200" Value="100" x:Name="HeightSlider" TickFrequency="25" TickPlacement="TopLeft" />
+            <TextBlock Text="Stretch" />
+            <ComboBox x:Name="StretchSelector" HorizontalAlignment="Stretch" Margin="0,0,0,2" />
+            <TextBlock Text="Stretch Direction" />
+            <ComboBox x:Name="StretchDirectionSelector" HorizontalAlignment="Stretch" />
+          </StackPanel>
         </Grid>
+
     </Grid>
 </UserControl>

+ 20 - 1
samples/ControlCatalog/Pages/ViewboxPage.xaml.cs

@@ -1,5 +1,6 @@
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
+using Avalonia.Media;
 
 namespace ControlCatalog.Pages
 {
@@ -7,7 +8,25 @@ namespace ControlCatalog.Pages
     {
         public ViewboxPage()
         {
-            this.InitializeComponent();
+            InitializeComponent();
+
+            var stretchSelector = this.FindControl<ComboBox>("StretchSelector");
+
+            stretchSelector.Items = new[]
+            {
+                Stretch.Uniform, Stretch.UniformToFill, Stretch.Fill, Stretch.None
+            };
+
+            stretchSelector.SelectedIndex = 0;
+
+            var stretchDirectionSelector = this.FindControl<ComboBox>("StretchDirectionSelector");
+
+            stretchDirectionSelector.Items = new[]
+            {
+                StretchDirection.Both, StretchDirection.DownOnly, StretchDirection.UpOnly
+            };
+
+            stretchDirectionSelector.SelectedIndex = 0;
         }
 
         private void InitializeComponent()

+ 78 - 0
samples/ControlCatalog/ViewModels/ContextFlyoutPageViewModel.cs

@@ -0,0 +1,78 @@
+using System.Collections.Generic;
+using System.Reactive;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.VisualTree;
+using MiniMvvm;
+
+namespace ControlCatalog.ViewModels
+{
+    public class ContextFlyoutPageViewModel
+    {
+        public Control View { get; set; }
+        public ContextFlyoutPageViewModel()
+        {
+            OpenCommand = MiniCommand.CreateFromTask(Open);
+            SaveCommand = MiniCommand.Create(Save);
+            OpenRecentCommand = MiniCommand.Create<string>(OpenRecent);
+
+            MenuItems = new[]
+            {
+                new MenuItemViewModel { Header = "_Open...", Command = OpenCommand },
+                new MenuItemViewModel { Header = "Save", Command = SaveCommand },
+                new MenuItemViewModel { Header = "-" },
+                new MenuItemViewModel
+                {
+                    Header = "Recent",
+                    Items = new[]
+                    {
+                        new MenuItemViewModel
+                        {
+                            Header = "File1.txt",
+                            Command = OpenRecentCommand,
+                            CommandParameter = @"c:\foo\File1.txt"
+                        },
+                        new MenuItemViewModel
+                        {
+                            Header = "File2.txt",
+                            Command = OpenRecentCommand,
+                            CommandParameter = @"c:\foo\File2.txt"
+                        },
+                    }
+                },
+            };
+        }
+
+        public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
+        public MiniCommand OpenCommand { get; }
+        public MiniCommand SaveCommand { get; }
+        public MiniCommand OpenRecentCommand { get; }
+
+        public async Task Open()
+        {
+            var window = View?.GetVisualRoot() as Window;
+            if (window == null)
+                return;
+            var dialog = new OpenFileDialog();
+            var result = await dialog.ShowAsync(window);
+
+            if (result != null)
+            {
+                foreach (var path in result)
+                {
+                    System.Diagnostics.Debug.WriteLine($"Opened: {path}");
+                }
+            }
+        }
+
+        public void Save()
+        {
+            System.Diagnostics.Debug.WriteLine("Save");
+        }
+
+        public void OpenRecent(string path)
+        {
+            System.Diagnostics.Debug.WriteLine($"Open recent: {path}");
+        }
+    }
+}

+ 7 - 7
samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs

@@ -3,7 +3,7 @@ using System.Reactive;
 using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.VisualTree;
-using ReactiveUI;
+using MiniMvvm;
 
 namespace ControlCatalog.ViewModels
 {
@@ -12,9 +12,9 @@ namespace ControlCatalog.ViewModels
         public Control View { get; set; }
         public ContextMenuPageViewModel()
         {
-            OpenCommand = ReactiveCommand.CreateFromTask(Open);
-            SaveCommand = ReactiveCommand.Create(Save);
-            OpenRecentCommand = ReactiveCommand.Create<string>(OpenRecent);
+            OpenCommand = MiniCommand.CreateFromTask(Open);
+            SaveCommand = MiniCommand.Create(Save);
+            OpenRecentCommand = MiniCommand.Create<string>(OpenRecent);
 
             MenuItems = new[]
             {
@@ -44,9 +44,9 @@ namespace ControlCatalog.ViewModels
         }
 
         public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
-        public ReactiveCommand<Unit, Unit> OpenCommand { get; }
-        public ReactiveCommand<Unit, Unit> SaveCommand { get; }
-        public ReactiveCommand<string, Unit> OpenRecentCommand { get; }
+        public MiniCommand OpenCommand { get; }
+        public MiniCommand SaveCommand { get; }
+        public MiniCommand OpenRecentCommand { get; }
 
         public async Task Open()
         {

+ 44 - 0
samples/ControlCatalog/ViewModels/CursorPageViewModel.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Input;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using MiniMvvm;
+
+namespace ControlCatalog.ViewModels
+{
+    public class CursorPageViewModel : ViewModelBase
+    {
+        public CursorPageViewModel()
+        {
+            StandardCursors = Enum.GetValues(typeof(StandardCursorType))
+                .Cast<StandardCursorType>()
+                .Select(x => new StandardCursorModel(x))
+                .ToList();
+
+            var loader = AvaloniaLocator.Current.GetService<IAssetLoader>();
+            var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png"));
+            var bitmap = new Bitmap(s);
+            CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16));
+        }
+
+        public IEnumerable<StandardCursorModel> StandardCursors { get; }
+        
+        public Cursor CustomCursor { get; }
+
+        public class StandardCursorModel
+        {
+            public StandardCursorModel(StandardCursorType type)
+            {
+                Type = type;
+                Cursor = new Cursor(type);
+            }
+
+            public StandardCursorType Type { get; }
+            
+            public Cursor Cursor { get; }
+        }
+    }
+}

+ 3 - 3
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs

@@ -2,11 +2,11 @@
 using System.Collections.ObjectModel;
 using System.Linq;
 using Avalonia.Media;
-using ReactiveUI;
+using MiniMvvm;
 
 namespace ControlCatalog.ViewModels
 {
-    public class ItemsRepeaterPageViewModel : ReactiveObject
+    public class ItemsRepeaterPageViewModel : ViewModelBase
     {
         private int _newItemIndex = 1;
         private int _newGenerationIndex = 0;
@@ -59,7 +59,7 @@ namespace ControlCatalog.ViewModels
                 }));
         }
 
-        public class Item : ReactiveObject
+        public class Item : ViewModelBase
         {
             private double _height = double.NaN;
 

+ 13 - 14
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@@ -4,18 +4,18 @@ using System.Linq;
 using System.Reactive;
 using Avalonia.Controls;
 using Avalonia.Controls.Selection;
-using ReactiveUI;
+using MiniMvvm;
 
 namespace ControlCatalog.ViewModels
 {
-    public class ListBoxPageViewModel : ReactiveObject
+    public class ListBoxPageViewModel : ViewModelBase
     {
         private bool _multiple;
         private bool _toggle;
         private bool _alwaysSelected;
         private bool _autoScrollToSelectedItem = true;
         private int _counter;
-        private ObservableAsPropertyHelper<SelectionMode> _selectionMode;
+        private IObservable<SelectionMode> _selectionMode;
 
         public ListBoxPageViewModel()
         {
@@ -29,14 +29,13 @@ namespace ControlCatalog.ViewModels
                 x => x.Toggle,
                 x => x.AlwaysSelected,
                 (m, t, a) =>
-                    (m ? SelectionMode.Multiple : 0) |
-                    (t ? SelectionMode.Toggle : 0) |
-                    (a ? SelectionMode.AlwaysSelected : 0))
-                .ToProperty(this, x => x.SelectionMode);
+                    (m ? Avalonia.Controls.SelectionMode.Multiple : 0) |
+                    (t ? Avalonia.Controls.SelectionMode.Toggle : 0) |
+                    (a ? Avalonia.Controls.SelectionMode.AlwaysSelected : 0));
 
-            AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
+            AddItemCommand = MiniCommand.Create(() => Items.Add(GenerateItem()));
 
-            RemoveItemCommand = ReactiveCommand.Create(() =>
+            RemoveItemCommand = MiniCommand.Create(() =>
             {
                 var items = Selection.SelectedItems.ToList();
 
@@ -46,7 +45,7 @@ namespace ControlCatalog.ViewModels
                 }
             });
 
-            SelectRandomItemCommand = ReactiveCommand.Create(() =>
+            SelectRandomItemCommand = MiniCommand.Create(() =>
             {
                 var random = new Random();
 
@@ -60,7 +59,7 @@ namespace ControlCatalog.ViewModels
 
         public ObservableCollection<string> Items { get; }
         public SelectionModel<string> Selection { get; }
-        public SelectionMode SelectionMode => _selectionMode.Value;
+        public IObservable<SelectionMode> SelectionMode => _selectionMode;
 
         public bool Multiple
         {
@@ -86,9 +85,9 @@ namespace ControlCatalog.ViewModels
             set => this.RaiseAndSetIfChanged(ref _autoScrollToSelectedItem, value);
         }
 
-        public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
-        public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
-        public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
+        public MiniCommand AddItemCommand { get; }
+        public MiniCommand RemoveItemCommand { get; }
+        public MiniCommand SelectRandomItemCommand { get; }
 
         private string GenerateItem() => $"Item {_counter++.ToString()}";
     }

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません