Browse Source

Merge branch 'master' into issues/compiledbindingsetsource

pull/5052/head
Dan Walmsley 5 years ago
committed by GitHub
parent
commit
22344d8f6a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      Avalonia.sln
  2. 11
      Documentation/build.md
  3. 2
      build/ApiDiff.props
  4. 3
      build/EmbedXaml.props
  5. 2
      build/Rx.props
  6. 2
      build/SharedVersion.props
  7. 1020
      native/Avalonia.Native/inc/key.h
  8. 12
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  9. 7
      native/Avalonia.Native/src/OSX/KeyTransform.h
  10. 151
      native/Avalonia.Native/src/OSX/KeyTransform.mm
  11. 2
      native/Avalonia.Native/src/OSX/menu.h
  12. 65
      native/Avalonia.Native/src/OSX/menu.mm
  13. 2
      native/Avalonia.Native/src/OSX/platformthreading.mm
  14. 10
      native/Avalonia.Native/src/OSX/rendertarget.mm
  15. 8
      native/Avalonia.Native/src/OSX/window.mm
  16. 18
      nukebuild/Build.cs
  17. 2
      nukebuild/_build.csproj
  18. 2
      samples/BindingDemo/App.xaml.cs
  19. 3
      samples/BindingDemo/BindingDemo.csproj
  20. 4
      samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
  21. 4
      samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
  22. 12
      samples/BindingDemo/ViewModels/MainWindowViewModel.cs
  23. 8
      samples/BindingDemo/ViewModels/NestedCommandViewModel.cs
  24. 4
      samples/BindingDemo/ViewModels/TestItem.cs
  25. 4
      samples/ControlCatalog.Desktop/Program.cs
  26. 2
      samples/ControlCatalog.NetCore/Program.cs
  27. 4
      samples/ControlCatalog/App.xaml.cs
  28. 2
      samples/ControlCatalog/ControlCatalog.csproj
  29. 30
      samples/ControlCatalog/DecoratedWindow.xaml
  30. 66
      samples/ControlCatalog/MainWindow.xaml
  31. 2
      samples/ControlCatalog/MainWindow.xaml.cs
  32. 29
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  33. 1
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  34. 2
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  35. 1
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  36. 4
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs
  37. 4
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs
  38. 4
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  39. 14
      samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs
  40. 6
      samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
  41. 27
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  42. 28
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  43. 14
      samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
  44. 10
      samples/ControlCatalog/ViewModels/NotificationViewModel.cs
  45. 4
      samples/ControlCatalog/ViewModels/SplitViewPageViewModel.cs
  46. 16
      samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
  47. 66
      samples/MiniMvvm/MiniCommand.cs
  48. 6
      samples/MiniMvvm/MiniMvvm.csproj
  49. 108
      samples/MiniMvvm/PropertyChangedExtensions.cs
  50. 26
      samples/MiniMvvm/ViewModelBase.cs
  51. 1
      samples/Previewer/Previewer.csproj
  52. 2
      samples/RenderDemo/App.xaml
  53. 2
      samples/RenderDemo/App.xaml.cs
  54. 2
      samples/RenderDemo/MainWindow.xaml.cs
  55. 3
      samples/RenderDemo/RenderDemo.csproj
  56. 4
      samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs
  57. 17
      samples/RenderDemo/ViewModels/MainWindowViewModel.cs
  58. 2
      samples/Sandbox/App.axaml
  59. 2
      samples/Sandbox/Program.cs
  60. 1
      samples/Sandbox/Sandbox.csproj
  61. 2
      samples/VirtualizationDemo/Program.cs
  62. 4
      samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
  63. 24
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  64. 3
      samples/VirtualizationDemo/VirtualizationDemo.csproj
  65. 2
      samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
  66. 4
      samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
  67. 6
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  68. 4
      src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
  69. 4
      src/Avalonia.Base/ApiCompatBaseline.txt
  70. 18
      src/Avalonia.Base/Collections/AvaloniaList.cs
  71. 2
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  72. 25
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  73. 24
      src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
  74. 5
      src/Avalonia.Base/Utilities/MathUtilities.cs
  75. 14
      src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs
  76. 5
      src/Avalonia.Base/Utilities/StringTokenizer.cs
  77. 35
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  78. 4
      src/Avalonia.Build.Tasks/SpanCompat.cs
  79. 4
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  80. 6
      src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
  81. 29
      src/Avalonia.Controls.DataGrid/Themes/Default.xaml
  82. 29
      src/Avalonia.Controls/ApiCompatBaseline.txt
  83. 7
      src/Avalonia.Controls/AutoCompleteBox.cs
  84. 32
      src/Avalonia.Controls/ComboBox.cs
  85. 10
      src/Avalonia.Controls/ContextMenu.cs
  86. 60
      src/Avalonia.Controls/DefinitionList.cs
  87. 4
      src/Avalonia.Controls/Generators/ItemContainerInfo.cs
  88. 10
      src/Avalonia.Controls/GridLength.cs
  89. 3
      src/Avalonia.Controls/NativeMenuBar.cs
  90. 18
      src/Avalonia.Controls/NativeMenuItem.cs
  91. 2
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  92. 4
      src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
  93. 2
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  94. 9
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  95. 11
      src/Avalonia.Controls/Slider.cs
  96. 5
      src/Avalonia.Controls/TextBox.cs
  97. 20
      src/Avalonia.Controls/Window.cs
  98. 2
      src/Avalonia.Controls/WindowBase.cs
  99. 2
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  100. 2
      src/Avalonia.DesignerSupport/Remote/Stubs.cs

27
Avalonia.sln

@ -230,6 +230,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroComGenerator", "src\to
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -2116,6 +2118,30 @@ Global
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.Build.0 = Release|Any CPU {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.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -2176,6 +2202,7 @@ Global
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C} {909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098} {11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

11
Documentation/build.md

@ -60,15 +60,10 @@ git submodule update --init --recursive
### Build native libraries (macOS only) ### 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: 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.
- (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:
``` ```bash
cd ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-[guid]/Build/Products/Debug ./build.sh CompileNative
cp libAvalonia.Native.OSX.dylib /usr/local/lib/libAvaloniaNative.dylib
``` ```
### Build and Run Avalonia ### Build and Run Avalonia

2
build/ApiDiff.props

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

3
build/EmbedXaml.props

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

2
build/Rx.props

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

2
build/SharedVersion.props

@ -16,7 +16,7 @@
<PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>false</SignAssembly> <SignAssembly>true</SignAssembly>
<DefineConstants Condition="$(SignAssembly) == true">$(DefineConstants);SIGNED_BUILD</DefineConstants> <DefineConstants Condition="$(SignAssembly) == true">$(DefineConstants);SIGNED_BUILD</DefineConstants>
</PropertyGroup> </PropertyGroup>

1020
native/Avalonia.Native/inc/key.h

File diff suppressed because it is too large

12
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

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

7
native/Avalonia.Native/src/OSX/KeyTransform.h

@ -1,9 +1,14 @@
#ifndef keytransform_h #ifndef keytransform_h
#define keytransform_h #define keytransform_h
#include "common.h" #include "common.h"
#include "key.h"
#include <map> #include <map>
extern std::map<int, AvnKey> s_KeyMap; 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 #endif

151
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_Eisu = 0x66;
const int kVK_JIS_Kana = 0x68; 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 = std::map<int, AvnKey> s_KeyMap =
{ {
{kVK_ANSI_A, A}, {kVK_ANSI_A, A},
@ -237,3 +369,22 @@ const int kVK_JIS_Kana = 0x68;
{kVK_UpArrow, Up}, {kVK_UpArrow, Up},
{kVK_JIS_Kana, AvnKeyKanaMode}, {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
native/Avalonia.Native/src/OSX/menu.h

@ -45,7 +45,7 @@ public:
virtual HRESULT SetTitle (char* utf8String) override; 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; virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;

65
native/Avalonia.Native/src/OSX/menu.mm

@ -2,6 +2,9 @@
#include "common.h" #include "common.h"
#include "menu.h" #include "menu.h"
#include "window.h" #include "window.h"
#include "KeyTransform.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
@implementation AvnMenu @implementation AvnMenu
{ {
@ -122,23 +125,57 @@ HRESULT AvnAppMenuItem::SetTitle (char* utf8String)
} }
} }
HRESULT AvnAppMenuItem::SetGesture (char* key, AvnInputModifiers modifiers)
HRESULT AvnAppMenuItem::SetGesture (AvnKey key, AvnInputModifiers modifiers)
{ {
@autoreleasepool @autoreleasepool
{ {
NSEventModifierFlags flags = 0; if(key != AvnKeyNone)
{
if (modifiers & Control) NSEventModifierFlags flags = 0;
flags |= NSEventModifierFlagControl;
if (modifiers & Shift) if (modifiers & Control)
flags |= NSEventModifierFlagShift; flags |= NSEventModifierFlagControl;
if (modifiers & Alt) if (modifiers & Shift)
flags |= NSEventModifierFlagOption; flags |= NSEventModifierFlagShift;
if (modifiers & Windows) if (modifiers & Alt)
flags |= NSEventModifierFlagCommand; flags |= NSEventModifierFlagOption;
if (modifiers & Windows)
[_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]]; flags |= NSEventModifierFlagCommand;
[_native setKeyEquivalentModifierMask:flags];
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;
}
}
}
}
// Nothing matched... clear.
[_native setKeyEquivalent: @""];
[_native setKeyEquivalentModifierMask: 0];
return S_OK; return S_OK;
} }

2
native/Avalonia.Native/src/OSX/platformthreading.mm

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

10
native/Avalonia.Native/src/OSX/rendertarget.mm

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

8
native/Avalonia.Native/src/OSX/window.mm

@ -106,13 +106,13 @@ public:
return Window; return Window;
} }
virtual HRESULT Show() override virtual HRESULT Show(bool activate) override
{ {
@autoreleasepool @autoreleasepool
{ {
SetPosition(lastPositionSet); SetPosition(lastPositionSet);
UpdateStyle(); UpdateStyle();
if(ShouldTakeFocusOnShow()) if(ShouldTakeFocusOnShow() && activate)
{ {
[Window makeKeyAndOrderFront:Window]; [Window makeKeyAndOrderFront:Window];
[NSApp activateIgnoringOtherApps:YES]; [NSApp activateIgnoringOtherApps:YES];
@ -561,11 +561,11 @@ private:
} }
} }
virtual HRESULT Show () override virtual HRESULT Show (bool activate) override
{ {
@autoreleasepool @autoreleasepool
{ {
WindowBaseImpl::Show(); WindowBaseImpl::Show(activate);
HideOrShowTrafficLights(); HideOrShowTrafficLights();

18
nukebuild/Build.cs

@ -107,7 +107,7 @@ partial class Build : NukeBuild
.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64"))) .AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64")))
.AddProperty("PackageVersion", Parameters.Version) .AddProperty("PackageVersion", Parameters.Version)
.AddProperty("iOSRoslynPathHackRequired", true) .AddProperty("iOSRoslynPathHackRequired", true)
.SetToolPath(MsBuildExe.Value) .SetProcessToolPath(MsBuildExe.Value)
.SetConfiguration(Parameters.Configuration) .SetConfiguration(Parameters.Configuration)
.SetVerbosity(MSBuildVerbosity.Minimal) .SetVerbosity(MSBuildVerbosity.Minimal)
.Apply(configurator)); .Apply(configurator));
@ -132,10 +132,10 @@ partial class Build : NukeBuild
var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp"; var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c NpmTasks.NpmInstall(c => c
.SetWorkingDirectory(webappDir) .SetProcessWorkingDirectory(webappDir)
.SetArgumentConfigurator(a => a.Add("--silent"))); .SetProcessArgumentConfigurator(a => a.Add("--silent")));
NpmTasks.NpmRun(c => c NpmTasks.NpmRun(c => c
.SetWorkingDirectory(webappDir) .SetProcessWorkingDirectory(webappDir)
.SetCommand("dist")); .SetCommand("dist"));
}); });
@ -157,7 +157,7 @@ partial class Build : NukeBuild
{ {
if (Parameters.IsRunningOnWindows) if (Parameters.IsRunningOnWindows)
MsBuildCommon(Parameters.MSBuildSolution, c => c MsBuildCommon(Parameters.MSBuildSolution, c => c
.SetArgumentConfigurator(a => a.Add("/r")) .SetProcessArgumentConfigurator(a => a.Add("/r"))
.AddTargets("Build") .AddTargets("Build")
); );
@ -194,7 +194,7 @@ partial class Build : NukeBuild
var eventsProject = Path.Combine(eventsDirectory, "Avalonia.ReactiveUI.Events.csproj"); var eventsProject = Path.Combine(eventsDirectory, "Avalonia.ReactiveUI.Events.csproj");
if (Parameters.IsRunningOnWindows) if (Parameters.IsRunningOnWindows)
MsBuildCommon(eventsProject, c => c MsBuildCommon(eventsProject, c => c
.SetArgumentConfigurator(a => a.Add("/r")) .SetProcessArgumentConfigurator(a => a.Add("/r"))
.AddTargets("Build") .AddTargets("Build")
); );
else else
@ -242,10 +242,10 @@ partial class Build : NukeBuild
var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp"; var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c NpmTasks.NpmInstall(c => c
.SetWorkingDirectory(webappTestDir) .SetProcessWorkingDirectory(webappTestDir)
.SetArgumentConfigurator(a => a.Add("--silent"))); .SetProcessArgumentConfigurator(a => a.Add("--silent")));
NpmTasks.NpmRun(c => c NpmTasks.NpmRun(c => c
.SetWorkingDirectory(webappTestDir) .SetProcessWorkingDirectory(webappTestDir)
.SetCommand("test")); .SetCommand("test"));
}); });

2
nukebuild/_build.csproj

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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="xunit.runner.console" Version="2.3.1" />
<PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" /> <PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " /> <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />

2
samples/BindingDemo/App.xaml.cs

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

3
samples/BindingDemo/BindingDemo.csproj

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

4
samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs

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

4
samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs

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

12
samples/BindingDemo/ViewModels/MainWindowViewModel.cs

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

8
samples/BindingDemo/ViewModels/NestedCommandViewModel.cs

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

4
samples/BindingDemo/ViewModels/TestItem.cs

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

4
samples/ControlCatalog.Desktop/Program.cs

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

2
samples/ControlCatalog.NetCore/Program.cs

@ -10,7 +10,6 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Dialogs; using Avalonia.Dialogs;
using Avalonia.Headless; using Avalonia.Headless;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
namespace ControlCatalog.NetCore namespace ControlCatalog.NetCore
@ -118,7 +117,6 @@ namespace ControlCatalog.NetCore
AllowEglInitialization = true AllowEglInitialization = true
}) })
.UseSkia() .UseSkia()
.UseReactiveUI()
.UseManagedSystemDialogs() .UseManagedSystemDialogs()
.LogToTrace(); .LogToTrace();

4
samples/ControlCatalog/App.xaml.cs

@ -23,7 +23,7 @@ namespace ControlCatalog
{ {
new StyleInclude(new Uri("avares://ControlCatalog/Styles")) 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 DataGridFluent
}; };
@ -32,7 +32,7 @@ namespace ControlCatalog
{ {
new StyleInclude(new Uri("avares://ControlCatalog/Styles")) 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 DataGridFluent
}; };

2
samples/ControlCatalog/ControlCatalog.csproj

@ -24,8 +24,8 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.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="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" /> <Import Project="..\..\build\BuildTargets.targets" />

30
samples/ControlCatalog/DecoratedWindow.xaml

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

66
samples/ControlCatalog/MainWindow.xaml

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

2
samples/ControlCatalog/MainWindow.xaml.cs

@ -67,7 +67,7 @@ namespace ControlCatalog
if (Application.Current.Styles.Contains(App.FluentDark) if (Application.Current.Styles.Contains(App.FluentDark)
|| Application.Current.Styles.Contains(App.FluentLight)) || 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 _); theme.TryGetResource("Button", out _);
} }
else else

29
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Dialogs; using Avalonia.Dialogs;
using Avalonia.Layout;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
#pragma warning disable 4014 #pragma warning disable 4014
@ -112,11 +113,29 @@ namespace ControlCatalog.Pages
private Window CreateSampleWindow() private Window CreateSampleWindow()
{ {
var window = new Window(); Button button;
window.Height = 200;
window.Width = 200; var window = new Window
window.Content = new TextBlock { Text = "Hello world!" }; {
window.WindowStartupLocation = WindowStartupLocation.CenterOwner; 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; return window;
} }

1
samples/ControlCatalog/Pages/LabelsPage.axaml.cs

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

2
samples/ControlCatalog/Pages/ListBoxPage.xaml

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

1
samples/ControlCatalog/Pages/MenuPage.xaml.cs

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

4
samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs

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

4
samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs

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

4
samples/ControlCatalog/Pages/TabControlPage.xaml.cs

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

14
samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs

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

6
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs

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

27
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

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

28
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -5,11 +5,11 @@ using Avalonia.Controls.Notifications;
using Avalonia.Dialogs; using Avalonia.Dialogs;
using Avalonia.Platform; using Avalonia.Platform;
using System; using System;
using ReactiveUI; using MiniMvvm;
namespace ControlCatalog.ViewModels namespace ControlCatalog.ViewModels
{ {
class MainWindowViewModel : ReactiveObject class MainWindowViewModel : ViewModelBase
{ {
private IManagedNotificationManager _notificationManager; private IManagedNotificationManager _notificationManager;
@ -27,22 +27,22 @@ namespace ControlCatalog.ViewModels
{ {
_notificationManager = notificationManager; _notificationManager = notificationManager;
ShowCustomManagedNotificationCommand = ReactiveCommand.Create(() => ShowCustomManagedNotificationCommand = MiniCommand.Create(() =>
{ {
NotificationManager.Show(new NotificationViewModel(NotificationManager) { Title = "Hey There!", Message = "Did you know that Avalonia now supports Custom In-Window Notifications?" }); NotificationManager.Show(new NotificationViewModel(NotificationManager) { Title = "Hey There!", Message = "Did you know that Avalonia now supports Custom In-Window Notifications?" });
}); });
ShowManagedNotificationCommand = ReactiveCommand.Create(() => ShowManagedNotificationCommand = MiniCommand.Create(() =>
{ {
NotificationManager.Show(new Avalonia.Controls.Notifications.Notification("Welcome", "Avalonia now supports Notifications.", NotificationType.Information)); NotificationManager.Show(new Avalonia.Controls.Notifications.Notification("Welcome", "Avalonia now supports Notifications.", NotificationType.Information));
}); });
ShowNativeNotificationCommand = ReactiveCommand.Create(() => ShowNativeNotificationCommand = MiniCommand.Create(() =>
{ {
NotificationManager.Show(new Avalonia.Controls.Notifications.Notification("Error", "Native Notifications are not quite ready. Coming soon.", NotificationType.Error)); NotificationManager.Show(new Avalonia.Controls.Notifications.Notification("Error", "Native Notifications are not quite ready. Coming soon.", NotificationType.Error));
}); });
AboutCommand = ReactiveCommand.CreateFromTask(async () => AboutCommand = MiniCommand.CreateFromTask(async () =>
{ {
var dialog = new AboutAvaloniaDialog(); var dialog = new AboutAvaloniaDialog();
@ -51,12 +51,12 @@ namespace ControlCatalog.ViewModels
await dialog.ShowDialog(mainWindow); await dialog.ShowDialog(mainWindow);
}); });
ExitCommand = ReactiveCommand.Create(() => ExitCommand = MiniCommand.Create(() =>
{ {
(App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown(); (App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown();
}); });
ToggleMenuItemCheckedCommand = ReactiveCommand.Create(() => ToggleMenuItemCheckedCommand = MiniCommand.Create(() =>
{ {
IsMenuItemChecked = !IsMenuItemChecked; IsMenuItemChecked = !IsMenuItemChecked;
}); });
@ -153,16 +153,16 @@ namespace ControlCatalog.ViewModels
set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); } set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); }
} }
public ReactiveCommand<Unit, Unit> ShowCustomManagedNotificationCommand { get; } public MiniCommand ShowCustomManagedNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> ShowManagedNotificationCommand { get; } public MiniCommand ShowManagedNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> ShowNativeNotificationCommand { get; } public MiniCommand ShowNativeNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> AboutCommand { get; } public MiniCommand AboutCommand { get; }
public ReactiveCommand<Unit, Unit> ExitCommand { get; } public MiniCommand ExitCommand { get; }
public ReactiveCommand<Unit, Unit> ToggleMenuItemCheckedCommand { get; } public MiniCommand ToggleMenuItemCheckedCommand { get; }
} }
} }

14
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@ -4,7 +4,7 @@ using System.Reactive.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using ReactiveUI; using MiniMvvm;
namespace ControlCatalog.ViewModels namespace ControlCatalog.ViewModels
{ {
@ -13,9 +13,9 @@ namespace ControlCatalog.ViewModels
public Control View { get; set; } public Control View { get; set; }
public MenuPageViewModel() public MenuPageViewModel()
{ {
OpenCommand = ReactiveCommand.CreateFromTask(Open); OpenCommand = MiniCommand.CreateFromTask(Open);
SaveCommand = ReactiveCommand.Create(Save, Observable.Return(false)); SaveCommand = MiniCommand.Create(Save);
OpenRecentCommand = ReactiveCommand.Create<string>(OpenRecent); OpenRecentCommand = MiniCommand.Create<string>(OpenRecent);
var recentItems = new[] var recentItems = new[]
{ {
@ -65,9 +65,9 @@ namespace ControlCatalog.ViewModels
public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; } public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
public IReadOnlyList<MenuItemViewModel> RecentItems { get; set; } public IReadOnlyList<MenuItemViewModel> RecentItems { get; set; }
public ReactiveCommand<Unit, Unit> OpenCommand { get; } public MiniCommand OpenCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; } public MiniCommand SaveCommand { get; }
public ReactiveCommand<string, Unit> OpenRecentCommand { get; } public MiniCommand OpenRecentCommand { get; }
public async Task Open() public async Task Open()
{ {

10
samples/ControlCatalog/ViewModels/NotificationViewModel.cs

@ -1,6 +1,6 @@
using System.Reactive; using System.Reactive;
using Avalonia.Controls.Notifications; using Avalonia.Controls.Notifications;
using ReactiveUI; using MiniMvvm;
namespace ControlCatalog.ViewModels namespace ControlCatalog.ViewModels
{ {
@ -8,12 +8,12 @@ namespace ControlCatalog.ViewModels
{ {
public NotificationViewModel(INotificationManager manager) public NotificationViewModel(INotificationManager manager)
{ {
YesCommand = ReactiveCommand.Create(() => YesCommand = MiniCommand.Create(() =>
{ {
manager.Show(new Avalonia.Controls.Notifications.Notification("Avalonia Notifications", "Start adding notifications to your app today.")); manager.Show(new Avalonia.Controls.Notifications.Notification("Avalonia Notifications", "Start adding notifications to your app today."));
}); });
NoCommand = ReactiveCommand.Create(() => NoCommand = MiniCommand.Create(() =>
{ {
manager.Show(new Avalonia.Controls.Notifications.Notification("Avalonia Notifications", "Start adding notifications to your app today. To find out more visit...")); manager.Show(new Avalonia.Controls.Notifications.Notification("Avalonia Notifications", "Start adding notifications to your app today. To find out more visit..."));
}); });
@ -22,9 +22,9 @@ namespace ControlCatalog.ViewModels
public string Title { get; set; } public string Title { get; set; }
public string Message { get; set; } public string Message { get; set; }
public ReactiveCommand<Unit, Unit> YesCommand { get; } public MiniCommand YesCommand { get; }
public ReactiveCommand<Unit, Unit> NoCommand { get; } public MiniCommand NoCommand { get; }
} }
} }

4
samples/ControlCatalog/ViewModels/SplitViewPageViewModel.cs

@ -1,10 +1,10 @@
using System; using System;
using Avalonia.Controls; using Avalonia.Controls;
using ReactiveUI; using MiniMvvm;
namespace ControlCatalog.ViewModels namespace ControlCatalog.ViewModels
{ {
public class SplitViewPageViewModel : ReactiveObject public class SplitViewPageViewModel : ViewModelBase
{ {
private bool _isLeft = true; private bool _isLeft = true;
private int _displayMode = 3; //CompactOverlay private int _displayMode = 3; //CompactOverlay

16
samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs

@ -3,11 +3,11 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reactive; using System.Reactive;
using Avalonia.Controls; using Avalonia.Controls;
using ReactiveUI; using MiniMvvm;
namespace ControlCatalog.ViewModels namespace ControlCatalog.ViewModels
{ {
public class TreeViewPageViewModel : ReactiveObject public class TreeViewPageViewModel : ViewModelBase
{ {
private readonly Node _root; private readonly Node _root;
private SelectionMode _selectionMode; private SelectionMode _selectionMode;
@ -19,16 +19,16 @@ namespace ControlCatalog.ViewModels
Items = _root.Children; Items = _root.Children;
SelectedItems = new ObservableCollection<Node>(); SelectedItems = new ObservableCollection<Node>();
AddItemCommand = ReactiveCommand.Create(AddItem); AddItemCommand = MiniCommand.Create(AddItem);
RemoveItemCommand = ReactiveCommand.Create(RemoveItem); RemoveItemCommand = MiniCommand.Create(RemoveItem);
SelectRandomItemCommand = ReactiveCommand.Create(SelectRandomItem); SelectRandomItemCommand = MiniCommand.Create(SelectRandomItem);
} }
public ObservableCollection<Node> Items { get; } public ObservableCollection<Node> Items { get; }
public ObservableCollection<Node> SelectedItems { get; } public ObservableCollection<Node> SelectedItems { get; }
public ReactiveCommand<Unit, Unit> AddItemCommand { get; } public MiniCommand AddItemCommand { get; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; } public MiniCommand RemoveItemCommand { get; }
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; } public MiniCommand SelectRandomItemCommand { get; }
public SelectionMode SelectionMode public SelectionMode SelectionMode
{ {

66
samples/MiniMvvm/MiniCommand.cs

@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MiniMvvm
{
public sealed class MiniCommand<T> : MiniCommand, ICommand
{
private readonly Action<T> _cb;
private bool _busy;
private Func<T, Task> _acb;
public MiniCommand(Action<T> cb)
{
_cb = cb;
}
public MiniCommand(Func<T, Task> cb)
{
_acb = cb;
}
private bool Busy
{
get => _busy;
set
{
_busy = value;
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
public override event EventHandler CanExecuteChanged;
public override bool CanExecute(object parameter) => !_busy;
public override async void Execute(object parameter)
{
if(Busy)
return;
try
{
Busy = true;
if (_cb != null)
_cb((T)parameter);
else
await _acb((T)parameter);
}
finally
{
Busy = false;
}
}
}
public abstract class MiniCommand : ICommand
{
public static MiniCommand Create(Action cb) => new MiniCommand<object>(_ => cb());
public static MiniCommand Create<TArg>(Action<TArg> cb) => new MiniCommand<TArg>(cb);
public static MiniCommand CreateFromTask(Func<Task> cb) => new MiniCommand<object>(_ => cb());
public abstract bool CanExecute(object parameter);
public abstract void Execute(object parameter);
public abstract event EventHandler CanExecuteChanged;
}
}

6
samples/MiniMvvm/MiniMvvm.csproj

@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Import Project="..\..\build\Rx.props" />
</Project>

108
samples/MiniMvvm/PropertyChangedExtensions.cs

@ -0,0 +1,108 @@
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reactive.Linq;
using System.Reflection;
namespace MiniMvvm
{
public static class PropertyChangedExtensions
{
class PropertyObservable<T> : IObservable<T>
{
private readonly INotifyPropertyChanged _target;
private readonly PropertyInfo _info;
public PropertyObservable(INotifyPropertyChanged target, PropertyInfo info)
{
_target = target;
_info = info;
}
class Subscription : IDisposable
{
private readonly INotifyPropertyChanged _target;
private readonly PropertyInfo _info;
private readonly IObserver<T> _observer;
public Subscription(INotifyPropertyChanged target, PropertyInfo info, IObserver<T> observer)
{
_target = target;
_info = info;
_observer = observer;
_target.PropertyChanged += OnPropertyChanged;
_observer.OnNext((T)_info.GetValue(_target));
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == _info.Name)
_observer.OnNext((T)_info.GetValue(_target));
}
public void Dispose()
{
_target.PropertyChanged -= OnPropertyChanged;
_observer.OnCompleted();
}
}
public IDisposable Subscribe(IObserver<T> observer)
{
return new Subscription(_target, _info, observer);
}
}
public static IObservable<TRes> WhenAnyValue<TModel, TRes>(this TModel model,
Expression<Func<TModel, TRes>> expr) where TModel : INotifyPropertyChanged
{
var l = (LambdaExpression)expr;
var ma = (MemberExpression)l.Body;
var prop = (PropertyInfo)ma.Member;
return new PropertyObservable<TRes>(model, prop);
}
public static IObservable<TRes> WhenAnyValue<TModel, T1, TRes>(this TModel model,
Expression<Func<TModel, T1>> v1,
Func<T1, TRes> cb
) where TModel : INotifyPropertyChanged
{
return model.WhenAnyValue(v1).Select(cb);
}
public static IObservable<TRes> WhenAnyValue<TModel, T1, T2, TRes>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2,
Func<T1, T2, TRes> cb
) where TModel : INotifyPropertyChanged =>
Observable.CombineLatest(
model.WhenAnyValue(v1),
model.WhenAnyValue(v2),
cb);
public static IObservable<ValueTuple<T1, T2>> WhenAnyValue<TModel, T1, T2>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2
) where TModel : INotifyPropertyChanged =>
model.WhenAnyValue(v1, v2, (a1, a2) => (a1, a2));
public static IObservable<TRes> WhenAnyValue<TModel, T1, T2, T3, TRes>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2,
Expression<Func<TModel, T3>> v3,
Func<T1, T2, T3, TRes> cb
) where TModel : INotifyPropertyChanged =>
Observable.CombineLatest(
model.WhenAnyValue(v1),
model.WhenAnyValue(v2),
model.WhenAnyValue(v3),
cb);
public static IObservable<ValueTuple<T1, T2, T3>> WhenAnyValue<TModel, T1, T2, T3>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2,
Expression<Func<TModel, T3>> v3
) where TModel : INotifyPropertyChanged =>
model.WhenAnyValue(v1, v2, v3, (a1, a2, a3) => (a1, a2, a3));
}
}

26
samples/MiniMvvm/ViewModelBase.cs

@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Joins;
using System.Runtime.CompilerServices;
namespace MiniMvvm
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool RaiseAndSetIfChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
RaisePropertyChanged(propertyName);
return true;
}
return false;
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

1
samples/Previewer/Previewer.csproj

@ -8,7 +8,6 @@
<DependentUpon>%(Filename)</DependentUpon> <DependentUpon>%(Filename)</DependentUpon>
</Compile> </Compile>
<EmbeddedResource Include="**\*.xaml" /> <EmbeddedResource Include="**\*.xaml" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\SampleApp.props" /> <Import Project="..\..\build\SampleApp.props" />

2
samples/RenderDemo/App.xaml

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="RenderDemo.App"> x:Class="RenderDemo.App">
<Application.Styles> <Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Accents/FluentLight.xaml"/> <FluentTheme/>
<StyleInclude Source="avares://RenderDemo/SideBar.xaml"/> <StyleInclude Source="avares://RenderDemo/SideBar.xaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/RenderDemo/App.xaml.cs

@ -1,7 +1,6 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace RenderDemo namespace RenderDemo
{ {
@ -32,7 +31,6 @@ namespace RenderDemo
OverlayPopups = true, OverlayPopups = true,
}) })
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI()
.LogToTrace(); .LogToTrace();
} }
} }

2
samples/RenderDemo/MainWindow.xaml.cs

@ -3,7 +3,7 @@ using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using RenderDemo.ViewModels; using RenderDemo.ViewModels;
using ReactiveUI; using MiniMvvm;
namespace RenderDemo namespace RenderDemo
{ {

3
samples/RenderDemo/RenderDemo.csproj

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

4
samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs

@ -1,10 +1,10 @@
using System; using System;
using ReactiveUI; using MiniMvvm;
using Avalonia.Animation; using Avalonia.Animation;
namespace RenderDemo.ViewModels namespace RenderDemo.ViewModels
{ {
public class AnimationsPageViewModel : ReactiveObject public class AnimationsPageViewModel : ViewModelBase
{ {
private bool _isPlaying = true; private bool _isPlaying = true;

17
samples/RenderDemo/ViewModels/MainWindowViewModel.cs

@ -1,11 +1,10 @@
using System.Reactive; using System.Reactive;
using System.Threading.Tasks; using System.Threading.Tasks;
using MiniMvvm;
using ReactiveUI;
namespace RenderDemo.ViewModels namespace RenderDemo.ViewModels
{ {
public class MainWindowViewModel : ReactiveObject public class MainWindowViewModel : ViewModelBase
{ {
private bool drawDirtyRects = false; private bool drawDirtyRects = false;
private bool drawFps = true; private bool drawFps = true;
@ -14,9 +13,9 @@ namespace RenderDemo.ViewModels
public MainWindowViewModel() public MainWindowViewModel()
{ {
ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects); ToggleDrawDirtyRects = MiniCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps); ToggleDrawFps = MiniCommand.Create(() => DrawFps = !DrawFps);
ResizeWindow = ReactiveCommand.CreateFromTask(ResizeWindowAsync); ResizeWindow = MiniCommand.CreateFromTask(ResizeWindowAsync);
} }
public bool DrawDirtyRects public bool DrawDirtyRects
@ -43,9 +42,9 @@ namespace RenderDemo.ViewModels
set => this.RaiseAndSetIfChanged(ref height, value); set => this.RaiseAndSetIfChanged(ref height, value);
} }
public ReactiveCommand<Unit, bool> ToggleDrawDirtyRects { get; } public MiniCommand ToggleDrawDirtyRects { get; }
public ReactiveCommand<Unit, bool> ToggleDrawFps { get; } public MiniCommand ToggleDrawFps { get; }
public ReactiveCommand<Unit, Unit> ResizeWindow { get; } public MiniCommand ResizeWindow { get; }
private async Task ResizeWindowAsync() private async Task ResizeWindowAsync()
{ {

2
samples/Sandbox/App.axaml

@ -3,6 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Sandbox.App"> x:Class="Sandbox.App">
<Application.Styles> <Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Accents/FluentDark.xaml"/> <FluentTheme Mode="Dark"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/Sandbox/Program.cs

@ -1,5 +1,4 @@
using Avalonia; using Avalonia;
using Avalonia.ReactiveUI;
namespace Sandbox namespace Sandbox
{ {
@ -9,7 +8,6 @@ namespace Sandbox
{ {
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI()
.LogToTrace() .LogToTrace()
.StartWithClassicDesktopLifetime(args); .StartWithClassicDesktopLifetime(args);
} }

1
samples/Sandbox/Sandbox.csproj

@ -8,7 +8,6 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.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="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
</ItemGroup> </ItemGroup>

2
samples/VirtualizationDemo/Program.cs

@ -1,5 +1,4 @@
using Avalonia; using Avalonia;
using Avalonia.ReactiveUI;
namespace VirtualizationDemo namespace VirtualizationDemo
{ {
@ -8,7 +7,6 @@ namespace VirtualizationDemo
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI()
.LogToTrace(); .LogToTrace();
public static int Main(string[] args) public static int Main(string[] args)

4
samples/VirtualizationDemo/ViewModels/ItemViewModel.cs

@ -1,9 +1,9 @@
using System; using System;
using ReactiveUI; using MiniMvvm;
namespace VirtualizationDemo.ViewModels namespace VirtualizationDemo.ViewModels
{ {
internal class ItemViewModel : ReactiveObject internal class ItemViewModel : ViewModelBase
{ {
private string _prefix; private string _prefix;
private int _index; private int _index;

24
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@ -5,13 +5,13 @@ using System.Reactive;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using ReactiveUI;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Controls.Selection; using Avalonia.Controls.Selection;
using MiniMvvm;
namespace VirtualizationDemo.ViewModels namespace VirtualizationDemo.ViewModels
{ {
internal class MainWindowViewModel : ReactiveObject internal class MainWindowViewModel : ViewModelBase
{ {
private int _itemCount = 200; private int _itemCount = 200;
private string _newItemString = "New Item"; private string _newItemString = "New Item";
@ -26,15 +26,15 @@ namespace VirtualizationDemo.ViewModels
public MainWindowViewModel() public MainWindowViewModel()
{ {
this.WhenAnyValue(x => x.ItemCount).Subscribe(ResizeItems); this.WhenAnyValue(x => x.ItemCount).Subscribe(ResizeItems);
RecreateCommand = ReactiveCommand.Create(() => Recreate()); RecreateCommand = MiniCommand.Create(() => Recreate());
AddItemCommand = ReactiveCommand.Create(() => AddItem()); AddItemCommand = MiniCommand.Create(() => AddItem());
RemoveItemCommand = ReactiveCommand.Create(() => Remove()); RemoveItemCommand = MiniCommand.Create(() => Remove());
SelectFirstCommand = ReactiveCommand.Create(() => SelectItem(0)); SelectFirstCommand = MiniCommand.Create(() => SelectItem(0));
SelectLastCommand = ReactiveCommand.Create(() => SelectItem(Items.Count - 1)); SelectLastCommand = MiniCommand.Create(() => SelectItem(Items.Count - 1));
} }
public string NewItemString public string NewItemString
@ -90,11 +90,11 @@ namespace VirtualizationDemo.ViewModels
public IEnumerable<ItemVirtualizationMode> VirtualizationModes => public IEnumerable<ItemVirtualizationMode> VirtualizationModes =>
Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>(); Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>();
public ReactiveCommand<Unit, Unit> AddItemCommand { get; private set; } public MiniCommand AddItemCommand { get; private set; }
public ReactiveCommand<Unit, Unit> RecreateCommand { get; private set; } public MiniCommand RecreateCommand { get; private set; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; private set; } public MiniCommand RemoveItemCommand { get; private set; }
public ReactiveCommand<Unit, Unit> SelectFirstCommand { get; private set; } public MiniCommand SelectFirstCommand { get; private set; }
public ReactiveCommand<Unit, Unit> SelectLastCommand { get; private set; } public MiniCommand SelectLastCommand { get; private set; }
public void RandomizeSize() public void RandomizeSize()
{ {

3
samples/VirtualizationDemo/VirtualizationDemo.csproj

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

2
samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj

@ -22,9 +22,9 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" /> <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" /> <ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
<ProjectReference Include="..\..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\build\Rx.props" /> <Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\ReferenceCoreLibraries.props" /> <Import Project="..\..\..\build\ReferenceCoreLibraries.props" />

4
samples/interop/Direct3DInteropSample/MainWindowViewModel.cs

@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ReactiveUI; using MiniMvvm;
namespace Direct3DInteropSample namespace Direct3DInteropSample
{ {
public class MainWindowViewModel : ReactiveObject public class MainWindowViewModel : ViewModelBase
{ {
private double _rotationX; private double _rotationX;

6
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@ -136,10 +136,6 @@
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project> <Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name> <Name>Avalonia.Layout</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Avalonia.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj"> <ProjectReference Include="..\..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project> <Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name> <Name>Avalonia.Visuals</Name>
@ -190,4 +186,4 @@
<Import Project="..\..\..\build\Rx.props" /> <Import Project="..\..\..\build\Rx.props" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\build\LegacyProject.targets" /> <Import Project="..\..\..\build\LegacyProject.targets" />
</Project> </Project>

4
src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj

@ -127,10 +127,6 @@
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project> <Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name> <Name>Avalonia.Layout</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Avalonia.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj"> <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project> <Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name> <Name>Avalonia.Visuals</Name>

4
src/Avalonia.Base/ApiCompatBaseline.txt

@ -1,4 +1,4 @@
Compat issues with assembly Avalonia.Base: Compat issues with assembly Avalonia.Base:
CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract. MembersMustExist : Member 'public void Avalonia.Threading.AvaloniaSynchronizationContext..ctor(Avalonia.Threading.AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider)' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Logging.DebugLogSink' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Threading.AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider' does not exist in the implementation but it does exist in the contract.
Total Issues: 2 Total Issues: 2

18
src/Avalonia.Base/Collections/AvaloniaList.cs

@ -63,6 +63,15 @@ namespace Avalonia.Collections
_inner = new List<T>(); _inner = new List<T>();
} }
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaList{T}"/>.
/// </summary>
/// <param name="capacity">Initial list capacity.</param>
public AvaloniaList(int capacity)
{
_inner = new List<T>(capacity);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AvaloniaList{T}"/> class. /// Initializes a new instance of the <see cref="AvaloniaList{T}"/> class.
/// </summary> /// </summary>
@ -175,6 +184,15 @@ namespace Avalonia.Collections
set { this[index] = (T)value; } set { this[index] = (T)value; }
} }
/// <summary>
/// Gets or sets the total number of elements the internal data structure can hold without resizing.
/// </summary>
public int Capacity
{
get => _inner.Capacity;
set => _inner.Capacity = value;
}
/// <summary> /// <summary>
/// Adds an item to the collection. /// Adds an item to the collection.
/// </summary> /// </summary>

2
src/Avalonia.Base/Properties/AssemblyInfo.cs

@ -11,10 +11,12 @@ using Avalonia.Metadata;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Visuals, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
#else #else
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")] [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Visuals")]
#endif #endif

25
src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs

@ -9,20 +9,6 @@ namespace Avalonia.Threading
/// </summary> /// </summary>
public class AvaloniaSynchronizationContext : SynchronizationContext public class AvaloniaSynchronizationContext : SynchronizationContext
{ {
public interface INonPumpingPlatformWaitProvider
{
int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
}
private readonly INonPumpingPlatformWaitProvider _waitProvider;
public AvaloniaSynchronizationContext(INonPumpingPlatformWaitProvider waitProvider)
{
_waitProvider = waitProvider;
if (_waitProvider != null)
SetWaitNotificationRequired();
}
/// <summary> /// <summary>
/// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer. /// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer.
/// </summary> /// </summary>
@ -38,8 +24,7 @@ namespace Avalonia.Threading
return; return;
} }
SetSynchronizationContext(new AvaloniaSynchronizationContext(AvaloniaLocator.Current SetSynchronizationContext(new AvaloniaSynchronizationContext());
.GetService<INonPumpingPlatformWaitProvider>()));
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -57,12 +42,6 @@ namespace Avalonia.Threading
Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait(); Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait();
} }
[PrePrepareMethod]
public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
if (_waitProvider != null)
return _waitProvider.Wait(waitHandles, waitAll, millisecondsTimeout);
return base.Wait(waitHandles, waitAll, millisecondsTimeout);
}
} }
} }

24
src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs

@ -1,5 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
#nullable enable
namespace Avalonia.Utilities namespace Avalonia.Utilities
{ {
@ -9,12 +12,14 @@ namespace Avalonia.Utilities
/// <typeparam name="TValue">Stored value type.</typeparam> /// <typeparam name="TValue">Stored value type.</typeparam>
internal sealed class AvaloniaPropertyValueStore<TValue> internal sealed class AvaloniaPropertyValueStore<TValue>
{ {
// The last item in the list is always int.MaxValue.
private static readonly Entry[] s_emptyEntries = { new Entry { PropertyId = int.MaxValue, Value = default! } };
private Entry[] _entries; private Entry[] _entries;
public AvaloniaPropertyValueStore() public AvaloniaPropertyValueStore()
{ {
// The last item in the list is always int.MaxValue _entries = s_emptyEntries;
_entries = new[] { new Entry { PropertyId = int.MaxValue, Value = default } };
} }
private (int, bool) TryFindEntry(int propertyId) private (int, bool) TryFindEntry(int propertyId)
@ -86,7 +91,7 @@ namespace Avalonia.Utilities
return (0, false); return (0, false);
} }
public bool TryGetValue(AvaloniaProperty property, out TValue value) public bool TryGetValue(AvaloniaProperty property, [MaybeNull] out TValue value)
{ {
(int index, bool found) = TryFindEntry(property.Id); (int index, bool found) = TryFindEntry(property.Id);
if (!found) if (!found)
@ -132,7 +137,18 @@ namespace Avalonia.Utilities
if (found) if (found)
{ {
Entry[] entries = new Entry[_entries.Length - 1]; var newLength = _entries.Length - 1;
// Special case - one element left means that value store is empty so we can just reuse our "empty" array.
if (newLength == 1)
{
_entries = s_emptyEntries;
return;
}
var entries = new Entry[newLength];
int ix = 0; int ix = 0;
for (int i = 0; i < _entries.Length; ++i) for (int i = 0; i < _entries.Length; ++i)

5
src/Avalonia.Base/Utilities/MathUtilities.cs

@ -5,7 +5,10 @@ namespace Avalonia.Utilities
/// <summary> /// <summary>
/// Provides math utilities not provided in System.Math. /// Provides math utilities not provided in System.Math.
/// </summary> /// </summary>
public static class MathUtilities #if !BUILDTASK
public
#endif
static class MathUtilities
{ {
// smallest such that 1.0+DoubleEpsilon != 1.0 // smallest such that 1.0+DoubleEpsilon != 1.0
internal static readonly double DoubleEpsilon = 2.2204460492503131e-016; internal static readonly double DoubleEpsilon = 2.2204460492503131e-016;

14
src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs

@ -0,0 +1,14 @@
using System;
namespace Avalonia.Utilities
{
public class NonPumpingLockHelper
{
public interface IHelperImpl
{
IDisposable Use();
}
public static IDisposable Use() => AvaloniaLocator.Current.GetService<IHelperImpl>()?.Use();
}
}

5
src/Avalonia.Base/Utilities/StringTokenizer.cs

@ -4,7 +4,10 @@ using static System.Char;
namespace Avalonia.Utilities namespace Avalonia.Utilities
{ {
public struct StringTokenizer : IDisposable #if !BUILDTASK
public
#endif
struct StringTokenizer : IDisposable
{ {
private const char DefaultSeparatorChar = ','; private const char DefaultSeparatorChar = ',';

35
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="$(Configuration) == 'Debug'">netstandard2.0;netcoreapp2.0</TargetFrameworks> <TargetFrameworks Condition="$(Configuration) == 'Debug'">netstandard2.0;netcoreapp3.1</TargetFrameworks>
<OutputType>exe</OutputType> <OutputType>exe</OutputType>
<GenerateDocumentationFile>false</GenerateDocumentationFile> <GenerateDocumentationFile>false</GenerateDocumentationFile>
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder> <BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
@ -45,6 +45,12 @@
<Compile Include="../Avalonia.Base/Utilities/IdentifierParser.cs"> <Compile Include="../Avalonia.Base/Utilities/IdentifierParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link> <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile> </Compile>
<Compile Include="../Avalonia.Base/Utilities/StringTokenizer.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Base/Utilities/MathUtilities.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\Markup\Avalonia.Markup\Markup\Parsers\ArgumentListParser.cs"> <Compile Include="..\Markup\Avalonia.Markup\Markup\Parsers\ArgumentListParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link> <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile> </Compile>
@ -57,6 +63,33 @@
<Compile Include="../Avalonia.Base/Utilities/StyleClassParser.cs"> <Compile Include="../Avalonia.Base/Utilities/StyleClassParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link> <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile> </Compile>
<Compile Include="../Avalonia.Visuals/Thickness.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Size.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Vector.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Point.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Matrix.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/CornerRadius.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Media/Color.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Media/KnownColors.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Controls/GridLength.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" /> <PackageReference Include="Mono.Cecil" Version="0.11.2" />

4
src/Avalonia.Build.Tasks/SpanCompat.cs

@ -1,3 +1,4 @@
#if !NETCOREAPP3_1
namespace System namespace System
{ {
// This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory // This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory
@ -63,6 +64,8 @@ namespace System
} }
public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length); public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length);
public static implicit operator ReadOnlySpan<T>(char[] arr) => new ReadOnlySpan<T>(new string(arr));
} }
static class SpanCompatExtensions static class SpanCompatExtensions
@ -71,3 +74,4 @@ namespace System
} }
} }
#endif

4
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -46,7 +46,9 @@ namespace Avalonia.Build.Tasks
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom, string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom,
bool skipXamlCompilation) bool skipXamlCompilation)
{ {
var typeSystem = new CecilTypeSystem(references.Concat(new[] { input }), input); var typeSystem = new CecilTypeSystem(references
.Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll"))
.Concat(new[] { input }), input);
var asm = typeSystem.TargetAssemblyDefinition; var asm = typeSystem.TargetAssemblyDefinition;

6
src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt

@ -1,5 +1 @@
Compat issues with assembly Avalonia.Controls.DataGrid: Total Issues: 0
MembersMustExist : Member 'public Avalonia.StyledProperty<System.String> Avalonia.StyledProperty<System.String> Avalonia.Controls.DataGridTextColumn.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.String Avalonia.Controls.DataGridTextColumn.FontFamily.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.DataGridTextColumn.FontFamily.set(System.String)' does not exist in the implementation but it does exist in the contract.
Total Issues: 3

29
src/Avalonia.Controls.DataGrid/Themes/Default.xaml

@ -137,12 +137,37 @@
</Style> </Style>
<Style Selector="DataGridRowHeader"> <Style Selector="DataGridRowHeader">
<Setter Property="Focusable" Value="False" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid x:Name="PART_Root" <Grid x:Name="PART_Root"
RowDefinitions="*,*,Auto" RowDefinitions="*,*,Auto"
ColumnDefinitions="Auto,*"> ColumnDefinitions="Auto,*">
<Border Grid.RowSpan="3"
Grid.ColumnSpan="2"
BorderBrush="{TemplateBinding SeparatorBrush}"
BorderThickness="0,0,1,0">
<Grid Background="{TemplateBinding Background}">
<Rectangle x:Name="RowInvalidVisualElement"
Stretch="Fill" />
<Rectangle x:Name="BackgroundRectangle"
Stretch="Fill" />
</Grid>
</Border>
<Rectangle x:Name="HorizontalSeparator"
Grid.Row="2"
Grid.ColumnSpan="2"
Height="1"
Margin="1,0,1,0"
HorizontalAlignment="Stretch"
Fill="{TemplateBinding SeparatorBrush}"
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
<ContentPresenter Grid.RowSpan="2"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid> </Grid>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>

29
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -1,26 +1,5 @@
Compat issues with assembly Avalonia.Controls: Compat issues with assembly Avalonia.Controls:
TypesMustExist : Type 'Avalonia.Controls.IndexPath' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show()' is present in the contract but not in the implementation.
TypesMustExist : Type 'Avalonia.Controls.ISelectedItemInfo' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Platform.IWindowBaseImpl.Show()' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.ISelectionModel' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.ListBox.SelectionProperty' does not exist in the implementation but it does exist in the contract. Total Issues: 3
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.ListBox.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.ContentProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.PaneProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Content.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Content.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Pane.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Pane.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.TreeView.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.Args' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.Args.get()' is present in the implementation but not in the contract.
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
Total Issues: 24

7
src/Avalonia.Controls/AutoCompleteBox.cs

@ -1405,8 +1405,11 @@ namespace Avalonia.Controls
break; break;
case Key.Enter: case Key.Enter:
OnAdapterSelectionComplete(this, new RoutedEventArgs()); if (IsDropDownOpen)
e.Handled = true; {
OnAdapterSelectionComplete(this, new RoutedEventArgs());
e.Handled = true;
}
break; break;
default: default:

32
src/Avalonia.Controls/ComboBox.cs

@ -173,11 +173,10 @@ namespace Avalonia.Controls
ComboBoxItem.ContentTemplateProperty); ComboBoxItem.ContentTemplateProperty);
} }
/// <inheritdoc/> protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{ {
base.OnAttachedToLogicalTree(e); base.OnAttachedToVisualTree(e);
this.UpdateSelectionBoxItem(this.SelectedItem); this.UpdateSelectionBoxItem(SelectedItem);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -373,19 +372,22 @@ namespace Avalonia.Controls
if (control != null) if (control != null)
{ {
control.Measure(Size.Infinity); if (VisualRoot is object)
SelectionBoxItem = new Rectangle
{ {
Width = control.DesiredSize.Width, control.Measure(Size.Infinity);
Height = control.DesiredSize.Height,
Fill = new VisualBrush SelectionBoxItem = new Rectangle
{ {
Visual = control, Width = control.DesiredSize.Width,
Stretch = Stretch.None, Height = control.DesiredSize.Height,
AlignmentX = AlignmentX.Left, Fill = new VisualBrush
} {
}; Visual = control,
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
}
};
}
} }
else else
{ {

10
src/Avalonia.Controls/ContextMenu.cs

@ -233,6 +233,16 @@ namespace Avalonia.Controls
} }
} }
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == WindowManagerAddShadowHintProperty && _popup != null)
{
_popup.WindowManagerAddShadowHint = change.NewValue.GetValueOrDefault<bool>();
}
}
/// <summary> /// <summary>
/// Opens the menu. /// Opens the menu.
/// </summary> /// </summary>

60
src/Avalonia.Controls/DefinitionList.cs

@ -1,8 +1,9 @@
using System; using System.Collections;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
using Avalonia.Collections; using Avalonia.Collections;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
public abstract class DefinitionList<T> : AvaloniaList<T> where T : DefinitionBase public abstract class DefinitionList<T> : AvaloniaList<T> where T : DefinitionBase
@ -14,44 +15,65 @@ namespace Avalonia.Controls
} }
internal bool IsDirty = true; internal bool IsDirty = true;
private Grid _parent; private Grid? _parent;
internal Grid Parent internal Grid? Parent
{ {
get => _parent; get => _parent;
set => SetParent(value); set => SetParent(value);
} }
private void SetParent(Grid value) private void SetParent(Grid? value)
{ {
_parent = value; _parent = value;
foreach (var pair in this.Select((definitions, index) => (definitions, index))) var idx = 0;
foreach (T definition in this)
{ {
pair.definitions.Parent = value; definition.Parent = value;
pair.definitions.Index = pair.index; definition.Index = idx++;
} }
} }
internal void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) internal void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
foreach (var nI in this.Select((d, i) => (d, i))) var idx = 0;
nI.d._parentIndex = nI.i;
foreach (var nD in e.NewItems?.Cast<DefinitionBase>() foreach (T definition in this)
?? Enumerable.Empty<DefinitionBase>())
{ {
nD.Parent = this.Parent; definition.Index = idx++;
nD.OnEnterParentTree();
} }
UpdateDefinitionParent(e.NewItems, false);
UpdateDefinitionParent(e.OldItems, true);
IsDirty = true;
}
foreach (var oD in e.OldItems?.Cast<DefinitionBase>() private void UpdateDefinitionParent(IList? items, bool wasRemoved)
?? Enumerable.Empty<DefinitionBase>()) {
if (items is null)
{ {
oD.OnExitParentTree(); return;
} }
var count = items.Count;
IsDirty = true; for (var i = 0; i < count; i++)
{
var definition = (DefinitionBase) items[i];
if (wasRemoved)
{
definition.OnExitParentTree();
}
else
{
definition.Parent = Parent;
definition.OnEnterParentTree();
}
}
} }
} }
} }

4
src/Avalonia.Controls/Generators/ItemContainerInfo.cs

@ -37,6 +37,6 @@ namespace Avalonia.Controls.Generators
/// <summary> /// <summary>
/// Gets the index of the item in the <see cref="ItemsControl.Items"/> collection. /// Gets the index of the item in the <see cref="ItemsControl.Items"/> collection.
/// </summary> /// </summary>
public int Index { get; internal set; } public int Index { get; set; }
} }
} }

10
src/Avalonia.Controls/GridLength.cs

@ -8,7 +8,10 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the valid units for a <see cref="GridLength"/>. /// Defines the valid units for a <see cref="GridLength"/>.
/// </summary> /// </summary>
public enum GridUnitType #if !BUILDTASK
public
#endif
enum GridUnitType
{ {
/// <summary> /// <summary>
/// The row or column is auto-sized to fit its content. /// The row or column is auto-sized to fit its content.
@ -29,7 +32,10 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Holds the width or height of a <see cref="Grid"/>'s column and row definitions. /// Holds the width or height of a <see cref="Grid"/>'s column and row definitions.
/// </summary> /// </summary>
public struct GridLength : IEquatable<GridLength> #if !BUILDTASK
public
#endif
struct GridLength : IEquatable<GridLength>
{ {
private readonly GridUnitType _type; private readonly GridUnitType _type;

3
src/Avalonia.Controls/NativeMenuBar.cs

@ -1,7 +1,6 @@
using System; using System;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Styling;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -16,7 +15,7 @@ namespace Avalonia.Controls
EnableMenuItemClickForwardingProperty.Changed.Subscribe(args => EnableMenuItemClickForwardingProperty.Changed.Subscribe(args =>
{ {
var item = (MenuItem)args.Sender; var item = (MenuItem)args.Sender;
if (args.NewValue.Equals(true)) if (args.NewValue.GetValueOrDefault<bool>())
item.Click += OnMenuItemClick; item.Click += OnMenuItemClick;
else else
item.Click -= OnMenuItemClick; item.Click -= OnMenuItemClick;

18
src/Avalonia.Controls/NativeMenuItem.cs

@ -2,6 +2,7 @@ using System;
using System.Windows.Input; using System.Windows.Input;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Metadata;
using Avalonia.Utilities; using Avalonia.Utilities;
namespace Avalonia.Controls namespace Avalonia.Controls
@ -62,6 +63,7 @@ namespace Avalonia.Controls
public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty = public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v); AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v);
[Content]
public NativeMenu Menu public NativeMenu Menu
{ {
get => _menu; get => _menu;
@ -151,7 +153,7 @@ namespace Avalonia.Controls
IsEnabled = _command?.CanExecute(null) ?? true; IsEnabled = _command?.CanExecute(null) ?? true;
} }
public bool HasClickHandlers => Clicked != null; public bool HasClickHandlers => Click != null;
public ICommand Command public ICommand Command
{ {
@ -182,11 +184,21 @@ namespace Avalonia.Controls
set { SetValue(CommandParameterProperty, value); } set { SetValue(CommandParameterProperty, value); }
} }
public event EventHandler Clicked; /// <summary>
/// Occurs when a <see cref="NativeMenuItem"/> is clicked.
/// </summary>
public event EventHandler Click;
[Obsolete("Use Click event.")]
public event EventHandler Clicked
{
add => Click += value;
remove => Click -= value;
}
void INativeMenuItemExporterEventsImplBridge.RaiseClicked() void INativeMenuItemExporterEventsImplBridge.RaiseClicked()
{ {
Clicked?.Invoke(this, new EventArgs()); Click?.Invoke(this, new EventArgs());
if (Command?.CanExecute(CommandParameter) == true) if (Command?.CanExecute(CommandParameter) == true)
{ {

2
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -231,7 +231,7 @@ namespace Avalonia.Controls.Platform
{ {
var direction = e.Key.ToNavigationDirection(); var direction = e.Key.ToNavigationDirection();
if (direction.HasValue) if (direction?.IsDirectional() == true)
{ {
if (item == null && _isContextMenu) if (item == null && _isContextMenu)
{ {

4
src/Avalonia.Controls/Platform/IWindowBaseImpl.cs

@ -5,9 +5,9 @@ namespace Avalonia.Platform
public interface IWindowBaseImpl : ITopLevelImpl public interface IWindowBaseImpl : ITopLevelImpl
{ {
/// <summary> /// <summary>
/// Shows the top level. /// Shows the window.
/// </summary> /// </summary>
void Show(); void Show(bool activate);
/// <summary> /// <summary>
/// Hides the window. /// Hides the window.

2
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -35,7 +35,7 @@ namespace Avalonia.Controls.Primitives
/// Defines the <see cref="Visibility"/> property. /// Defines the <see cref="Visibility"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<ScrollBarVisibility> VisibilityProperty = public static readonly StyledProperty<ScrollBarVisibility> VisibilityProperty =
AvaloniaProperty.Register<ScrollBar, ScrollBarVisibility>(nameof(Visibility)); AvaloniaProperty.Register<ScrollBar, ScrollBarVisibility>(nameof(Visibility), ScrollBarVisibility.Visible);
/// <summary> /// <summary>
/// Defines the <see cref="Orientation"/> property. /// Defines the <see cref="Orientation"/> property.

9
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@ -354,11 +354,14 @@ namespace Avalonia.Controls.Primitives
{ {
control.SetValue(TemplatedParentProperty, this); control.SetValue(TemplatedParentProperty, this);
foreach (var child in control.LogicalChildren) var children = control.LogicalChildren;
var count = children.Count;
for (var i = 0; i < count; i++)
{ {
if (child is IControl c) if (children[i] is IControl child)
{ {
ApplyTemplatedParent(c); ApplyTemplatedParent(child);
} }
} }
} }

11
src/Avalonia.Controls/Slider.cs

@ -3,6 +3,7 @@ using Avalonia.Collections;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins; using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
@ -94,6 +95,8 @@ namespace Avalonia.Controls
Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble); Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e), Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e),
RoutingStrategies.Bubble); RoutingStrategies.Bubble);
ValueProperty.OverrideMetadata<Slider>(new DirectPropertyMetadata<double>(enableDataValidation: true));
} }
/// <summary> /// <summary>
@ -225,6 +228,14 @@ namespace Avalonia.Controls
Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue; Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
} }
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
{
if (property == ValueProperty)
{
DataValidationErrors.SetError(this, value.Error);
}
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{ {
base.OnPropertyChanged(change); base.OnPropertyChanged(change);

5
src/Avalonia.Controls/TextBox.cs

@ -867,7 +867,10 @@ namespace Avalonia.Controls
{ {
var point = e.GetPosition(_presenter); var point = e.GetPosition(_presenter);
point = new Point(MathUtilities.Clamp(point.X, 0, _presenter.Bounds.Width - 1), MathUtilities.Clamp(point.Y, 0, _presenter.Bounds.Height - 1)); point = new Point(
MathUtilities.Clamp(point.X, 0, Math.Max(_presenter.Bounds.Width - 1, 0)),
MathUtilities.Clamp(point.Y, 0, Math.Max(_presenter.Bounds.Height - 1, 0)));
CaretIndex = SelectionEnd = _presenter.GetCaretIndex(point); CaretIndex = SelectionEnd = _presenter.GetCaretIndex(point);
} }
} }

20
src/Avalonia.Controls/Window.cs

@ -129,6 +129,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<SystemDecorations> SystemDecorationsProperty = public static readonly StyledProperty<SystemDecorations> SystemDecorationsProperty =
AvaloniaProperty.Register<Window, SystemDecorations>(nameof(SystemDecorations), SystemDecorations.Full); AvaloniaProperty.Register<Window, SystemDecorations>(nameof(SystemDecorations), SystemDecorations.Full);
/// <summary>
/// Defines the <see cref="ShowActivated"/> property.
/// </summary>
public static readonly StyledProperty<bool> ShowActivatedProperty =
AvaloniaProperty.Register<Window, bool>(nameof(ShowActivated), true);
/// <summary> /// <summary>
/// Enables or disables the taskbar icon /// Enables or disables the taskbar icon
/// </summary> /// </summary>
@ -352,13 +358,21 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Sets the system decorations (title bar, border, etc) /// Sets the system decorations (title bar, border, etc)
/// </summary> /// </summary>
///
public SystemDecorations SystemDecorations public SystemDecorations SystemDecorations
{ {
get { return GetValue(SystemDecorationsProperty); } get { return GetValue(SystemDecorationsProperty); }
set { SetValue(SystemDecorationsProperty, value); } set { SetValue(SystemDecorationsProperty, value); }
} }
/// <summary>
/// Gets or sets a value that indicates whether a window is activated when first shown.
/// </summary>
public bool ShowActivated
{
get { return GetValue(ShowActivatedProperty); }
set { SetValue(ShowActivatedProperty, value); }
}
/// <summary> /// <summary>
/// Enables or disables the taskbar icon /// Enables or disables the taskbar icon
/// </summary> /// </summary>
@ -650,7 +664,7 @@ namespace Avalonia.Controls
Owner = parent; Owner = parent;
parent?.AddChild(this, false); parent?.AddChild(this, false);
PlatformImpl?.Show(); PlatformImpl?.Show(ShowActivated);
Renderer?.Start(); Renderer?.Start();
SetWindowStartupLocation(Owner?.PlatformImpl); SetWindowStartupLocation(Owner?.PlatformImpl);
} }
@ -720,7 +734,7 @@ namespace Avalonia.Controls
PlatformImpl?.SetParent(owner.PlatformImpl); PlatformImpl?.SetParent(owner.PlatformImpl);
Owner = owner; Owner = owner;
owner.AddChild(this, true); owner.AddChild(this, true);
PlatformImpl?.Show(); PlatformImpl?.Show(ShowActivated);
Renderer?.Start(); Renderer?.Start();

2
src/Avalonia.Controls/WindowBase.cs

@ -162,7 +162,7 @@ namespace Avalonia.Controls
LayoutManager.ExecuteInitialLayoutPass(); LayoutManager.ExecuteInitialLayoutPass();
_hasExecutedInitialLayoutPass = true; _hasExecutedInitialLayoutPass = true;
} }
PlatformImpl?.Show(); PlatformImpl?.Show(true);
Renderer?.Start(); Renderer?.Start();
OnOpened(EventArgs.Empty); OnOpened(EventArgs.Empty);
} }

2
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -20,7 +20,7 @@ namespace Avalonia.DesignerSupport.Remote
ClientSize = new Size(1, 1); ClientSize = new Size(1, 1);
} }
public void Show() public void Show(bool activate)
{ {
} }

2
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -77,7 +77,7 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
public void Show() public void Show(bool activate)
{ {
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save