Browse Source

Merge branch 'master' into compiled-bindings-default

pull/7247/head
Dan Walmsley 5 years ago
committed by GitHub
parent
commit
f987569c4c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      Avalonia.sln
  2. 1
      Directory.Build.props
  3. 9
      azure-pipelines.yml
  4. 16
      build/AndroidWorkarounds.props
  5. 1
      build/CoreLibraries.props
  6. 4
      build/SharedVersion.props
  7. 5
      build/SourceLink.props
  8. 3
      build/System.Drawing.Common.props
  9. 11
      dirs.proj
  10. 1
      global.json
  11. 31
      native/Avalonia.Native/src/OSX/window.mm
  12. 5
      nukebuild/Build.cs
  13. 23
      readme.md
  14. 19
      samples/ControlCatalog.Android/Assets/AboutAssets.txt
  15. 183
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  16. 5
      samples/ControlCatalog.Android/MainActivity.cs
  17. 7
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  18. 30
      samples/ControlCatalog.Android/Properties/AssemblyInfo.cs
  19. 101
      samples/ControlCatalog.Android/Resources/Resource.Designer.cs
  20. 2
      samples/ControlCatalog.Android/Resources/values/styles.xml
  21. 2
      samples/ControlCatalog.Android/SplashActivity.cs
  22. 2
      samples/ControlCatalog.Web/ControlCatalog.Web.csproj
  23. 1
      samples/ControlCatalog/App.xaml
  24. 33
      samples/ControlCatalog/App.xaml.cs
  25. 4
      samples/ControlCatalog/MainView.xaml
  26. 2
      samples/ControlCatalog/MainView.xaml.cs
  27. 15
      samples/ControlCatalog/Models/Person.cs
  28. 45
      samples/ControlCatalog/Pages/ButtonPage.xaml
  29. 224
      samples/ControlCatalog/Pages/ButtonsPage.xaml
  30. 4
      samples/ControlCatalog/Pages/ButtonsPage.xaml.cs
  31. 5
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml
  32. 160
      samples/ControlCatalog/Pages/ComboBoxPage.xaml
  33. 2
      samples/ControlCatalog/Pages/ComboBoxPage.xaml.cs
  34. 12
      samples/ControlCatalog/Pages/DataGridPage.xaml
  35. 22
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  36. 2
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  37. 4
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  38. 220
      samples/ControlCatalog/Pages/PointersPage.cs
  39. 37
      samples/ControlCatalog/Pages/ScreenPage.cs
  40. 2
      samples/ControlCatalog/Pages/ToggleSwitchPage.xaml
  41. 22
      samples/ControlCatalog/Pages/ViewboxPage.xaml
  42. 19
      samples/ControlCatalog/Pages/ViewboxPage.xaml.cs
  43. 21
      samples/ControlCatalog/ViewModels/ComboBoxPageViewModel.cs
  44. 7
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  45. 13
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  46. 3
      samples/RenderDemo/MainWindow.xaml
  47. 54
      samples/RenderDemo/Pages/ClippingPage.xaml
  48. 17
      samples/RenderDemo/Pages/ClippingPage.xaml.cs
  49. 13
      samples/RenderDemo/Pages/CustomSkiaPage.cs
  50. 7
      samples/RenderDemo/Pages/FormattedTextPage.axaml
  51. 60
      samples/RenderDemo/Pages/FormattedTextPage.axaml.cs
  52. 7
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  53. 4
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  54. 12
      src/Android/Avalonia.Android/AndroidPlatform.cs
  55. 14
      src/Android/Avalonia.Android/AppBuilder.cs
  56. 15
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  57. 36
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  58. 11
      src/Android/Avalonia.Android/AvaloniaViewModel.cs
  59. 50
      src/Android/Avalonia.Android/Resources/AboutResources.txt
  60. 6
      src/Android/Avalonia.Android/Resources/Values/Strings.xml
  61. 18
      src/Android/Avalonia.Android/RuntimeInfo.cs
  62. 4
      src/Android/Avalonia.Android/SoftKeyboardListener.cs
  63. 19
      src/Android/Avalonia.AndroidTestApplication/Assets/AboutAssets.txt
  64. 172
      src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
  65. 2
      src/Android/Avalonia.AndroidTestApplication/MainActivity.cs
  66. 6
      src/Android/Avalonia.AndroidTestApplication/Properties/AndroidManifest.xml
  67. 30
      src/Android/Avalonia.AndroidTestApplication/Properties/AssemblyInfo.cs
  68. 79
      src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
  69. 11
      src/Android/Avalonia.AndroidTestApplication/app.config
  70. 16
      src/Avalonia.Animation/Animatable.cs
  71. 46
      src/Avalonia.Animation/Animation.cs
  72. 33
      src/Avalonia.Animation/AnimationInstance`1.cs
  73. 20
      src/Avalonia.Animation/AnimatorKeyFrame.cs
  74. 9
      src/Avalonia.Animation/Animators/Animator`1.cs
  75. 4
      src/Avalonia.Animation/Avalonia.Animation.csproj
  76. 2
      src/Avalonia.Animation/Clock.cs
  77. 8
      src/Avalonia.Animation/Cue.cs
  78. 8
      src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
  79. 4
      src/Avalonia.Animation/Easing/Easing.cs
  80. 4
      src/Avalonia.Animation/Easing/EasingTypeConverter.cs
  81. 2
      src/Avalonia.Animation/IAnimation.cs
  82. 4
      src/Avalonia.Animation/IAnimationSetter.cs
  83. 4
      src/Avalonia.Animation/IAnimator.cs
  84. 2
      src/Avalonia.Animation/ITransition.cs
  85. 2
      src/Avalonia.Animation/IterationCount.cs
  86. 4
      src/Avalonia.Animation/IterationCountTypeConverter.cs
  87. 4
      src/Avalonia.Animation/KeyFrame.cs
  88. 4
      src/Avalonia.Animation/KeySplineTypeConverter.cs
  89. 21
      src/Avalonia.Animation/Transition.cs
  90. 6
      src/Avalonia.Animation/TransitionInstance.cs
  91. 1
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  92. 21
      src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs
  93. 10
      src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
  94. 20
      src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
  95. 24
      src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
  96. 5
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  97. 2
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  98. 7
      src/Avalonia.Base/Threading/Dispatcher.cs
  99. 15
      src/Avalonia.Base/Threading/JobRunner.cs
  100. 12
      src/Avalonia.Base/Utilities/IWeakEventSubscriber.cs

50
Avalonia.sln

@ -60,27 +60,24 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BindingDemo", "samples\BindingDemo\BindingDemo.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-CC41-4F14-A8C8-267F579BF91E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.AndroidTestApplication", "src\Android\Avalonia.AndroidTestApplication\Avalonia.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.AndroidTestApplication", "src\Android\Avalonia.AndroidTestApplication\Avalonia.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}"
EndProject
@ -98,7 +95,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog", "samples\C
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{52F55355-D120-42AC-8116-8410A7D602FA}"
EndProject
@ -110,7 +107,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{A0CC
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderDemo", "samples\RenderDemo\RenderDemo.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Android", "samples\ControlCatalog.Android\ControlCatalog.Android.csproj", "{29132311-1848-4FD6-AE0C-4FF841151BD3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Android", "samples\ControlCatalog.Android\ControlCatalog.Android.csproj", "{29132311-1848-4FD6-AE0C-4FF841151BD3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia", "src\Skia\Avalonia.Skia\Avalonia.Skia.csproj", "{7D2D3083-71DD-4CC9-8907-39A0D86FB322}"
EndProject
@ -118,7 +115,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.NetCore", "s
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject
build\AndroidWorkarounds.props = build\AndroidWorkarounds.props
build\ApiDiff.props = build\ApiDiff.props
build\Base.props = build\Base.props
build\Binding.props = build\Binding.props
@ -235,15 +231,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "sampl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", "src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj", "{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 5
src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|iPhone = Ad-Hoc|iPhone
@ -1115,7 +1105,7 @@ Global
{57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhone.Build.0 = AppStore|iPhone
{57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.ActiveCfg = Debug|iPhone
{57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.Build.0 = Debug|iPhone
{57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
@ -2169,6 +2159,30 @@ Global
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2187,11 +2201,9 @@ Global
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
{6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}

1
Directory.Build.props

@ -4,5 +4,6 @@
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netcoreapp2.0\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<!-- https://github.com/dotnet/msbuild/issues/2661 -->
<AddSyntheticProjectReferencesForSolutionDependencies>false</AddSyntheticProjectReferencesForSolutionDependencies>
<MSBuildEnableWorkloadResolver>false</MSBuildEnableWorkloadResolver>
</PropertyGroup>
</Project>

9
azure-pipelines.yml

@ -1,6 +1,3 @@
variables:
MSBuildEnableWorkloadResolver: 'false'
jobs:
- job: GetPRNumber
@ -146,6 +143,12 @@ jobs:
inputs:
version: 6.0.100
- task: CmdLine@2
displayName: 'Install Workloads'
inputs:
script: |
dotnet workload install android
- task: CmdLine@2
displayName: 'Install Nuke'
inputs:

16
build/AndroidWorkarounds.props

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

1
build/CoreLibraries.props

@ -17,5 +17,6 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj" />
</ItemGroup>
</Project>

4
build/SharedVersion.props

@ -3,7 +3,7 @@
<PropertyGroup>
<Product>Avalonia</Product>
<Version>0.10.999</Version>
<Copyright>Copyright 2021 &#169; The AvaloniaUI Project</Copyright>
<Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@ -11,7 +11,7 @@
<LangVersion>latest</LangVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>
<PackageDescription>Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), MacOS and with experimental support for Android and iOS.</PackageDescription>
<PackageDescription>Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, MacOS and with experimental support for Android, iOS and WebAssembly.</PackageDescription>
<PackageTags>avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin</PackageTags>
<PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes>
<RepositoryType>git</RepositoryType>

5
build/SourceLink.props

@ -3,7 +3,6 @@
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>false</IncludeSymbols>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<DebugType>embedded</DebugType>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
@ -15,6 +14,10 @@
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<PropertyGroup>
<DebugType Condition="$(ContinuousIntegrationBuild) == 'true'">embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>

3
build/System.Drawing.Common.props

@ -1,5 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
<PackageReference Condition="'$(TargetFramework)'!='netstandard2.0'" Include="System.Drawing.Common" Version="6.0.0" />
<PackageReference Condition="'$(TargetFramework)'=='netstandard2.0'" Include="System.Drawing.Common" Version="4.5.0" />
</ItemGroup>
</Project>

11
dirs.proj

@ -1,5 +1,7 @@
<Project Sdk="Microsoft.Build.Traversal">
<ItemGroup>
<!-- Build Avalonia.Build.Tasks first because everything depends on it -->
<ProjectReference Include="src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" />
<ProjectReference Include="src/**/*.*proj" />
<ProjectReference Include="samples/**/*.*proj" />
<ProjectReference Include="tests/**/*.*proj" />
@ -8,11 +10,8 @@
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/**/*.*proj" />
<ProjectReference Remove="tests/Avalonia.ReactiveUI.Events.UnitTests/Avalonia.ReactiveUI.Events.UnitTests.csproj" />
</ItemGroup>
<!--<ItemGroup Condition="!Exists('$(MSBuildExtensionsPath)\Xamarin\Android')">-->
<ItemGroup>
<ProjectReference Remove="src/Android/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Android/ControlCatalog.Android.csproj" />
<ProjectReference Remove="src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj" />
</ItemGroup>
<ItemGroup Condition="!Exists('$(MSBuildExtensionsPath)\Xamarin\iOS')">
<ProjectReference Remove="src/iOS/**/*.*proj" />
@ -23,6 +22,10 @@
<ProjectReference Remove="samples/interop/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<!-- Build android projects only on Windows, where we have installed android workload -->
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows'))">
<ProjectReference Remove="src/Android/**/*.*proj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SlnGen" Version="2.0.40" PrivateAssets="all" />

1
global.json

@ -4,6 +4,7 @@
},
"msbuild-sdks": {
"Microsoft.Build.Traversal": "1.0.43",
"Xamarin.Legacy.Sdk": "0.1.2-alpha6",
"MSBuild.Sdk.Extras": "3.0.22",
"AggregatePackage.NuGet.Sdk" : "0.1.12"
}

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

@ -1627,6 +1627,19 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return;
}
}
else if (type == Magnify)
{
delta.X = delta.Y = [event magnification];
}
else if (type == Rotate)
{
delta.X = delta.Y = [event rotation];
}
else if (type == Swipe)
{
delta.X = [event deltaX];
delta.Y = [event deltaY];
}
auto timestamp = [event timestamp] * 1000;
auto modifiers = [self getModifiers:[event modifierFlags]];
@ -1753,6 +1766,24 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[super scrollWheel:event];
}
- (void)magnifyWithEvent:(NSEvent *)event
{
[self mouseEvent:event withType:Magnify];
[super magnifyWithEvent:event];
}
- (void)rotateWithEvent:(NSEvent *)event
{
[self mouseEvent:event withType:Rotate];
[super rotateWithEvent:event];
}
- (void)swipeWithEvent:(NSEvent *)event
{
[self mouseEvent:event withType:Swipe];
[super swipeWithEvent:event];
}
- (void)mouseEntered:(NSEvent *)event
{
_isMouseOver = true;

5
nukebuild/Build.cs

@ -87,7 +87,8 @@ partial class Build : NukeBuild
Console.WriteLine(preamble);
Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit();
}
ExecWait("dotnet version:", "dotnet", "--version");
ExecWait("dotnet version:", "dotnet", "--info");
ExecWait("dotnet workloads:", "dotnet", "workload list");
}
IReadOnlyCollection<Output> MsBuildCommon(
@ -99,7 +100,7 @@ partial class Build : NukeBuild
// This is required for VS2019 image on Azure Pipelines
.When(Parameters.IsRunningOnWindows &&
Parameters.IsRunningOnAzure, _ => _
.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64")))
.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64")))
.AddProperty("PackageVersion", Parameters.Version)
.AddProperty("iOSRoslynPathHackRequired", true)
.SetProcessToolPath(MsBuildExe.Value)

23
readme.md

@ -3,13 +3,11 @@
<br />
[![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg)
## 📖 About AvaloniaUI
## 📖 About
Avalonia is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows via .NET Framework and .NET Core, Linux via Xorg, macOS. Avalonia is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development.
Avalonia is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, MacOs. Avalonia is mature and production ready. We also have in beta release support for iOS, Android and in early stages support for browser via WASM.
<img src="https://user-images.githubusercontent.com/6759207/84751662-7c79da00-afc5-11ea-8780-dda28db70b76.png" width="700" />
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
![image](https://user-images.githubusercontent.com/4672627/152126443-932966cf-57e7-4e77-9be6-62463a66b9f8.png)
To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
@ -28,18 +26,15 @@ Install-Package Avalonia.Desktop
## Showcase
Examples of UIs built with Avalonia
![image](https://user-images.githubusercontent.com/4672627/84707589-5b69a880-af35-11ea-87a6-7ad57a31d314.png)
([Synfonia](https://github.com/jmacato/Synfonia))
<video src="https://user-images.githubusercontent.com/4672627/152325602-28df36ec-6444-44a6-aebe-90ad52c8f27a.mp4"></video>
([Lunacy](https://icons8.com/lunacy))
![image](https://user-images.githubusercontent.com/4672627/85069644-d8419000-b18a-11ea-8732-be9055bb61fd.PNG)
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
![image](https://user-images.githubusercontent.com/4672627/152325740-261c27a3-e6f0-4662-bff7-4796d4940e04.png)
([PlasticSCM](https://www.plasticscm.com/))
![image](https://user-images.githubusercontent.com/4672627/85069659-dc6dad80-b18a-11ea-8375-39ef95315b5c.PNG)
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
![image](https://user-images.githubusercontent.com/4672627/152326453-14944c4d-33da-4d50-a268-b87f80927adb.png)
([WasabiWallet](https://www.wasabiwallet.io/))
![image](https://user-images.githubusercontent.com/4672627/84708947-c3b98980-af37-11ea-8c9d-503334615bbf.png)
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
## JetBrains Rider

19
samples/ControlCatalog.Android/Assets/AboutAssets.txt

@ -1,19 +0,0 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with you package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

183
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -1,165 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{29132311-1848-4FD6-AE0C-4FF841151BD3}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ControlCatalog.Android</RootNamespace>
<AssemblyName>ControlCatalog.Android</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<TargetFramework>net6.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ApplicationId>com.Avalonia.ControlCatalog</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<EnableProguard>False</EnableProguard>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>Full</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a,x86;x86_64</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<EnableProguard>False</EnableProguard>
<DebugSymbols>False</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SplashActivity.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\splash_screen.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\colors.xml" />
<AndroidResource Include="Resources\values\styles.xml" />
<None Remove="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="..\..\build\Assets\Icon.png">
<Link>Resources\drawable\Icon.png</Link>
</AndroidResource>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release' and '$(TF_BUILD)' == ''">
<DebugSymbols>True</DebugSymbols>
<RunAOTCompilation>False</RunAOTCompilation>
<EnableLLVM>True</EnableLLVM>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
<RunAOTCompilation>False</RunAOTCompilation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.1.3" />
<PackageReference Include="Xamarin.AndroidX.Lifecycle.ViewModel" Version="2.3.1.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj">
<Project>{7B92AF71-6287-4693-9DCB-BD5B6E927E23}</Project>
<Name>Avalonia.Android</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Avalonia.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Avalonia.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj">
<Project>{c42d2fc1-a531-4ed4-84b9-89aec7c962fc}</Project>
<Name>Avalonia.Themes.Fluent</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Avalonia.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Avalonia.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Avalonia.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Avalonia.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj">
<Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project>
<Name>Avalonia.Skia</Name>
</ProjectReference>
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj">
<Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
<Name>ControlCatalog</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
<Import Project="..\..\build\Rx.props" />
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\build\AndroidWorkarounds.props" />
<Import Project="..\..\build\LegacyProject.targets" />
</Project>

5
samples/ControlCatalog.Android/MainActivity.cs

@ -5,10 +5,10 @@ using Avalonia.Android;
namespace ControlCatalog.Android
{
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)]
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
public class MainActivity : AvaloniaActivity
{
protected override void OnCreate(Bundle savedInstanceState)
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
@ -16,4 +16,3 @@ namespace ControlCatalog.Android
}
}
}

7
samples/ControlCatalog.Android/Properties/AndroidManifest.xml

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

30
samples/ControlCatalog.Android/Properties/AssemblyInfo.cs

@ -1,30 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ControlCatalog.Android")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ControlCatalog.Android")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

101
samples/ControlCatalog.Android/Resources/Resource.Designer.cs

@ -1,101 +0,0 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("ControlCatalog.Android.Resource", IsApplication=true)]
namespace ControlCatalog.Android
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public static void UpdateIdValues()
{
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class Color
{
// aapt resource value: 0x7F010000
public const int splash_background = 2130771968;
static Color()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Color()
{
}
}
public partial class Drawable
{
// aapt resource value: 0x7F020000
public const int Icon = 2130837504;
// aapt resource value: 0x7F020001
public const int splash_screen = 2130837505;
static Drawable()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Drawable()
{
}
}
public partial class Style
{
// aapt resource value: 0x7F030000
public const int MyTheme = 2130903040;
// aapt resource value: 0x7F030001
public const int MyTheme_NoActionBar = 2130903041;
// aapt resource value: 0x7F030002
public const int MyTheme_Splash = 2130903042;
static Style()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Style()
{
}
}
}
}
#pragma warning restore 1591

2
samples/ControlCatalog.Android/Resources/values/styles.xml

@ -4,7 +4,7 @@
<style name="MyTheme">
</style>
<style name="MyTheme.NoActionBar">
<style name="MyTheme.NoActionBar" parent="@style/Theme.AppCompat.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
</style>

2
samples/ControlCatalog.Android/SplashActivity.cs

@ -10,7 +10,7 @@ namespace ControlCatalog.Android
[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
}

2
samples/ControlCatalog.Web/ControlCatalog.Web.csproj

@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<MSBuildEnableWorkloadResolver>false</MSBuildEnableWorkloadResolver>
<Nullable>enable</Nullable>
<WasmBuildNative>True</WasmBuildNative>
</PropertyGroup>
<ItemGroup>

1
samples/ControlCatalog/App.xaml

@ -3,6 +3,7 @@
xmlns:vm="using:ControlCatalog.ViewModels"
x:DataType="vm:ApplicationViewModel"
x:CompileBindings="True"
Name="Avalonia ControlCatalog"
x:Class="ControlCatalog.App">
<Application.Styles>
<Style Selector="TextBlock.h1, TextBlock.h2, TextBlock.h3">

33
samples/ControlCatalog/App.xaml.cs

@ -5,6 +5,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling;
using Avalonia.Themes.Default;
using Avalonia.Themes.Fluent;
using ControlCatalog.ViewModels;
@ -29,6 +30,8 @@ namespace ControlCatalog
public static FluentTheme Fluent = new FluentTheme(new Uri("avares://ControlCatalog/Styles"));
public static SimpleTheme Default = new SimpleTheme(new Uri("avares://ControlCatalog/Styles"));
public static Styles DefaultLight = new Styles
{
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
@ -43,14 +46,7 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseLight.xaml")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseLight.xaml")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
}
Default
};
public static Styles DefaultDark = new Styles
@ -67,14 +63,7 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseDark.xaml")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseDark.xaml")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
}
Default
};
public override void Initialize()
@ -89,16 +78,18 @@ namespace ControlCatalog
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
{
desktopLifetime.MainWindow = new MainWindow();
this.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
{
StartupScreenIndex = 1,
});
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
{
singleViewLifetime.MainView = new MainView();
}
base.OnFrameworkInitializationCompleted();
this.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
{
StartupScreenIndex = 1,
});
}
}
}

4
samples/ControlCatalog/MainView.xaml

@ -22,8 +22,8 @@
<TabItem Header="Border">
<pages:BorderPage />
</TabItem>
<TabItem Header="Button">
<pages:ButtonPage />
<TabItem Header="Buttons">
<pages:ButtonsPage />
</TabItem>
<TabItem Header="ButtonSpinner">
<pages:ButtonSpinnerPage />

2
samples/ControlCatalog/MainView.xaml.cs

@ -63,11 +63,13 @@ namespace ControlCatalog
}
else if (theme == CatalogTheme.DefaultLight)
{
App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Light;
Application.Current.Styles[0] = App.DefaultLight;
Application.Current.Styles[1] = App.DataGridDefault;
}
else if (theme == CatalogTheme.DefaultDark)
{
App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Dark;
Application.Current.Styles[0] = App.DefaultDark;
Application.Current.Styles[1] = App.DataGridDefault;
}

15
samples/ControlCatalog/Models/Person.cs

@ -16,6 +16,7 @@ namespace ControlCatalog.Models
string _firstName;
string _lastName;
bool _isBanned;
private int _age;
public string FirstName
{
@ -59,6 +60,20 @@ namespace ControlCatalog.Models
}
}
/// <summary>
/// Gets or sets the age of the person
/// </summary>
public int Age
{
get => _age;
set
{
_age = value;
OnPropertyChanged(nameof(Age));
}
}
Dictionary<string, List<string>> _errorLookup = new Dictionary<string, List<string>>();
void SetError(string propertyName, string error)

45
samples/ControlCatalog/Pages/ButtonPage.xaml

@ -1,45 +0,0 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ButtonPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">A button control</TextBlock>
<StackPanel Orientation="Horizontal"
Margin="0,16,0,0"
HorizontalAlignment="Center"
Spacing="16">
<StackPanel Orientation="Vertical" Spacing="8" Width="200">
<Button>Standard _XAML Button</Button>
<Button Foreground="White">Foreground</Button>
<Button Background="{DynamicResource SystemAccentColor}">Background</Button>
<Button IsEnabled="False">Disabled</Button>
<Button Content="Re-themed">
<Button.Styles>
<Style>
<Style.Resources>
<SolidColorBrush x:Key="ThemeBorderMidBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="ThemeControlHighBrush">DarkRed</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBorderBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBackground">DarkRed</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBackgroundPointerOver">Red</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBackgroundPressed">OrangeRed</SolidColorBrush>
</Style.Resources>
</Style>
</Button.Styles>
</Button>
<RepeatButton Name="RepeatButton">
<TextBlock Name="RepeatButtonTextBlock" Text="Repeat Button: 0" />
</RepeatButton>
<ToggleButton Content="Toggle Button"/>
</StackPanel>
<StackPanel Orientation="Vertical" Spacing="8" Width="150">
<Button BorderThickness="0">No Border</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}">Border Color</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}" BorderThickness="4">Thick Border</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}" BorderThickness="4" IsEnabled="False">Disabled</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}" KeyboardNavigation.IsTabStop="False">IsTabStop=False</Button>
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>

224
samples/ControlCatalog/Pages/ButtonsPage.xaml

@ -0,0 +1,224 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ButtonsPage">
<UserControl.Resources>
<MenuFlyout x:Key="SharedMenuFlyout"
Placement="Bottom">
<MenuItem Header="Item 1">
<MenuItem Header="Subitem 1" />
<MenuItem Header="Subitem 2" />
<MenuItem Header="Subitem 3" />
</MenuItem>
<MenuItem Header="Item 2"
InputGesture="Ctrl+A" />
<MenuItem Header="Item 3" />
</MenuFlyout>
</UserControl.Resources>
<UserControl.Styles >
<Style Selector="Border.header-border">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Gray" Opacity="0.5" />
</Setter.Value>
</Setter>
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="0.5" />
<Setter Property="CornerRadius" Value="5,5,0,0" />
<Setter Property="MaxWidth" Value="450" />
<Setter Property="Padding" Value="10" />
</Style>
<Style Selector="TextBlock.header">
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="Border.thin">
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="0.5" />
<Setter Property="CornerRadius" Value="0,0,5,5" />
<Setter Property="Margin" Value="0,0,0,15" />
</Style>
</UserControl.Styles>
<!-- Styles and overall page design based on AcrylicPage -->
<StackPanel Orientation="Vertical"
Width="450">
<!-- Button -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="Button" Classes="header" />
<TextBlock TextWrapping="Wrap">A standard button control</TextBlock>
</StackPanel>
</Border>
<Border Classes="thin"
Padding="15">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Spacing="10">
<StackPanel Orientation="Vertical"
Spacing="8"
Width="200">
<Button>Standard _XAML Button</Button>
<Button Foreground="White">Foreground</Button>
<Button Background="{DynamicResource SystemAccentColor}">Background</Button>
<Button IsEnabled="False">Disabled</Button>
<Button Content="Re-themed">
<Button.Styles>
<Style>
<Style.Resources>
<SolidColorBrush x:Key="ThemeBorderMidBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="ThemeControlHighBrush">DarkRed</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBorderBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBackground">DarkRed</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBackgroundPointerOver">Red</SolidColorBrush>
<SolidColorBrush x:Key="ButtonBackgroundPressed">OrangeRed</SolidColorBrush>
<SolidColorBrush x:Key="ButtonForeground">White</SolidColorBrush>
<SolidColorBrush x:Key="ButtonForegroundPointerOver">Black</SolidColorBrush>
<SolidColorBrush x:Key="ButtonForegroundPressed">Black</SolidColorBrush>
</Style.Resources>
</Style>
</Button.Styles>
</Button>
</StackPanel>
<StackPanel Orientation="Vertical"
Spacing="8"
Width="200">
<Button BorderThickness="0">No Border</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}">Border Color</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}"
BorderThickness="4">Thick Border</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}"
BorderThickness="4"
IsEnabled="False">Disabled</Button>
<Button BorderBrush="{DynamicResource SystemAccentColor}"
KeyboardNavigation.IsTabStop="False">IsTabStop=False</Button>
</StackPanel>
</StackPanel>
</Border>
<!-- ToggleButton -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="ToggleButton"
Classes="header" />
<TextBlock TextWrapping="Wrap">A button control with multiple states: checked, unchecked or indeterminate.</TextBlock>
</StackPanel>
</Border>
<Border Classes="thin"
Padding="15">
<StackPanel Orientation="Vertical"
Spacing="8">
<ToggleButton Content="Toggle Button" />
</StackPanel>
</Border>
<!-- RepeatButton -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="RepeatButton"
Classes="header" />
<TextBlock TextWrapping="Wrap">A button control that raises its Click event repeatedly when it is pressed and held.</TextBlock>
</StackPanel>
</Border>
<Border Classes="thin"
Padding="15">
<StackPanel Orientation="Vertical"
Spacing="8">
<RepeatButton Name="RepeatButton">
<TextBlock Name="RepeatButtonTextBlock"
Text="Repeat Button: 0" />
</RepeatButton>
</StackPanel>
</Border>
<!-- SplitButton -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="SplitButton"
Classes="header" />
<TextBlock TextWrapping="Wrap">A button with primary and secondary parts that can each be pressed separately. The primary part behaves like a Button and the secondary part opens a flyout.</TextBlock>
</StackPanel>
</Border>
<Border Classes="thin"
Padding="15">
<StackPanel Orientation="Vertical"
Spacing="8">
<SplitButton Flyout="{StaticResource SharedMenuFlyout}">
<TextBlock Text="Content" />
</SplitButton>
<SplitButton IsEnabled="False"
Flyout="{StaticResource SharedMenuFlyout}">
<TextBlock Text="Disabled" />
</SplitButton>
<SplitButton Flyout="{StaticResource SharedMenuFlyout}"
Content="Re-themed">
<SplitButton.Styles>
<Style>
<Style.Resources>
<x:Double x:Key="SplitButtonSeparatorWidth">1.5</x:Double>
<Thickness x:Key="SplitButtonBorderThemeThickness">2</Thickness>
<SolidColorBrush x:Key="SplitButtonBorderBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonBorderBrushPointerOver">Red</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonBorderBrushPressed">Red</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonBackground">DarkRed</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonBackgroundPointerOver">Red</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonBackgroundPressed">OrangeRed</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonForeground">White</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonForegroundPointerOver">Black</SolidColorBrush>
<SolidColorBrush x:Key="SplitButtonForegroundPressed">Black</SolidColorBrush>
</Style.Resources>
</Style>
</SplitButton.Styles>
</SplitButton>
</StackPanel>
</Border>
<!-- ToggleSplitButton -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="ToggleSplitButton"
Classes="header" />
<TextBlock TextWrapping="Wrap">A button with primary and secondary parts that can each be pressed separately. The primary part behaves like a ToggleButton with two states and the secondary part opens a flyout.</TextBlock>
</StackPanel>
</Border>
<Border Classes="thin"
Padding="15">
<StackPanel Orientation="Vertical"
Spacing="8">
<ToggleSplitButton Flyout="{StaticResource SharedMenuFlyout}">
<TextBlock Text="Content" />
</ToggleSplitButton>
<ToggleSplitButton IsChecked="True"
Flyout="{StaticResource SharedMenuFlyout}">
<TextBlock Text="Content" />
</ToggleSplitButton>
<ToggleSplitButton IsChecked="True"
IsEnabled="False"
Flyout="{StaticResource SharedMenuFlyout}">
<TextBlock Text="Disabled" />
</ToggleSplitButton>
</StackPanel>
</Border>
</StackPanel>
</UserControl>

4
samples/ControlCatalog/Pages/ButtonPage.xaml.cs → samples/ControlCatalog/Pages/ButtonsPage.xaml.cs

@ -3,11 +3,11 @@ using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class ButtonPage : UserControl
public class ButtonsPage : UserControl
{
private int repeatButtonClickCount = 0;
public ButtonPage()
public ButtonsPage()
{
InitializeComponent();

5
samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml

@ -1,5 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ControlCatalog.ViewModels"
x:DataType="vm:MainWindowViewModel"
x:Class="ControlCatalog.Pages.CalendarDatePickerPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">A control for selecting dates with a calendar drop-down</TextBlock>
@ -39,6 +41,9 @@
<TextBlock Text="Disabled"/>
<CalendarDatePicker IsEnabled="False"/>
<TextBlock Text="Validation Example"/>
<CalendarDatePicker SelectedDate="{CompiledBinding ValidatedDateExample, Mode=TwoWay}"/>
</StackPanel>
</StackPanel>

160
samples/ControlCatalog/Pages/ComboBoxPage.xaml

@ -1,77 +1,95 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ComboBoxPage"
xmlns:sys="using:System"
xmlns:col="using:System.Collections">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">A drop-down list.</TextBlock>
<UserControl
x:Class="ControlCatalog.Pages.ComboBoxPage"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:col="using:System.Collections"
xmlns:sys="using:System">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">A drop-down list.</TextBlock>
<WrapPanel HorizontalAlignment="Center" Margin="0 16 0 0"
MaxWidth="660">
<WrapPanel.Styles>
<Style Selector="ComboBox">
<Setter Property="Width" Value="250" />
<Setter Property="Margin" Value="10" />
</Style>
</WrapPanel.Styles>
<ComboBox PlaceholderText="Pick an Item">
<ComboBoxItem>Inline Items</ComboBoxItem>
<ComboBoxItem>Inline Item 2</ComboBoxItem>
<ComboBoxItem>Inline Item 3</ComboBoxItem>
<ComboBoxItem>Inline Item 4</ComboBoxItem>
</ComboBox>
<StackPanel
Margin="0,16,0,0"
HorizontalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<WrapPanel
MaxWidth="660"
Margin="0,16,0,0"
HorizontalAlignment="Center">
<WrapPanel.Styles>
<Style Selector="ComboBox">
<Setter Property="Width" Value="250" />
<Setter Property="Margin" Value="10" />
</Style>
</WrapPanel.Styles>
<ComboBox>
<ComboBox.Items>
<col:ArrayList>
<x:Null />
<sys:String>Hello</sys:String>
<sys:String>World</sys:String>
</col:ArrayList>
</ComboBox.Items>
<ComboBox.ItemTemplate>
<DataTemplate>
<Panel>
<TextBlock Text="{Binding}" />
<TextBlock Text="Null object" IsVisible="{Binding Converter={x:Static ObjectConverters.IsNull}}" />
</Panel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox PlaceholderText="Pick an Item" WrapSelection="{Binding WrapSelection}">
<ComboBoxItem>Inline Items</ComboBoxItem>
<ComboBoxItem>Inline Item 2</ComboBoxItem>
<ComboBoxItem>Inline Item 3</ComboBoxItem>
<ComboBoxItem>Inline Item 4</ComboBoxItem>
</ComboBox>
<ComboBox SelectedIndex="0">
<ComboBoxItem>
<Panel>
<Rectangle Fill="{DynamicResource SystemAccentColor}"/>
<TextBlock Margin="8">Control Items</TextBlock>
</Panel>
</ComboBoxItem>
<ComboBoxItem>
<Ellipse Width="50" Height="50" Fill="Yellow"/>
</ComboBoxItem>
<ComboBoxItem>
<TextBox Text="TextBox"/>
</ComboBoxItem>
</ComboBox>
<ComboBox WrapSelection="{Binding WrapSelection}">
<ComboBox.Items>
<col:ArrayList>
<x:Null />
<sys:String>Hello</sys:String>
<sys:String>World</sys:String>
</col:ArrayList>
</ComboBox.Items>
<ComboBox.ItemTemplate>
<DataTemplate>
<Panel>
<TextBlock Text="{Binding}" />
<TextBlock IsVisible="{Binding Converter={x:Static ObjectConverters.IsNull}}" Text="Null object" />
</Panel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox x:Name="fontComboBox" SelectedIndex="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontFamily="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox PlaceholderText="Pick an Item">
<ComboBoxItem>Inline Items</ComboBoxItem>
<ComboBoxItem>Inline Item 2</ComboBoxItem>
<ComboBoxItem>Inline Item 3</ComboBoxItem>
<ComboBoxItem>Inline Item 4</ComboBoxItem>
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</ComboBox>
</WrapPanel>
<ComboBox SelectedIndex="0" WrapSelection="{Binding WrapSelection}">
<ComboBoxItem>
<Panel>
<Rectangle Fill="{DynamicResource SystemAccentColor}" />
<TextBlock Margin="8">Control Items</TextBlock>
</Panel>
</ComboBoxItem>
<ComboBoxItem>
<Ellipse
Width="50"
Height="50"
Fill="Yellow" />
</ComboBoxItem>
<ComboBoxItem>
<TextBox Text="TextBox" />
</ComboBoxItem>
</ComboBox>
</StackPanel>
<ComboBox
x:Name="fontComboBox"
SelectedIndex="0"
WrapSelection="{Binding WrapSelection}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock FontFamily="{Binding}" Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox PlaceholderText="Pick an Item" WrapSelection="{Binding WrapSelection}">
<ComboBoxItem>Inline Items</ComboBoxItem>
<ComboBoxItem>Inline Item 2</ComboBoxItem>
<ComboBoxItem>Inline Item 3</ComboBoxItem>
<ComboBoxItem>Inline Item 4</ComboBoxItem>
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</ComboBox>
</WrapPanel>
<CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>
</StackPanel>
</StackPanel>
</UserControl>

2
samples/ControlCatalog/Pages/ComboBoxPage.xaml.cs

@ -2,6 +2,7 @@ using System.Linq;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages
{
@ -10,6 +11,7 @@ namespace ControlCatalog.Pages
public ComboBoxPage()
{
this.InitializeComponent();
DataContext = new ComboBoxPageViewModel();
}
private void InitializeComponent()

12
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -64,6 +64,18 @@
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" IsThreeState="{Binding #IsThreeStateCheckBox.IsChecked, Mode=OneWay}" />
<DataGridTemplateColumn Header="Age" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="local:Person">
<TextBlock Text="{Binding Age, StringFormat='{}{0} years'}" VerticalAlignment="Center" HorizontalAlignment="Center" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="local:Person">
<NumericUpDown Value="{Binding Age}" FormatString="N0" HorizontalAlignment="Stretch" Minimum="0" Maximum="120" TemplateApplied="NumericUpDown_OnTemplateApplied" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Name="btnAdd" Margin="12,0,12,12" Content="Add" HorizontalAlignment="Right" />

22
samples/ControlCatalog/Pages/DataGridPage.xaml.cs

@ -6,7 +6,9 @@ using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.Models;
using Avalonia.Collections;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Threading;
namespace ControlCatalog.Pages
{
@ -48,9 +50,9 @@ namespace ControlCatalog.Pages
var items = new List<Person>
{
new Person { FirstName = "John", LastName = "Doe" },
new Person { FirstName = "Elizabeth", LastName = "Thomas", IsBanned = true },
new Person { FirstName = "Zack", LastName = "Ward" }
new Person { FirstName = "John", LastName = "Doe" , Age = 30},
new Person { FirstName = "Elizabeth", LastName = "Thomas", IsBanned = true , Age = 40 },
new Person { FirstName = "Zack", LastName = "Ward" , Age = 50 }
};
var collectionView3 = new DataGridCollectionView(items);
@ -84,5 +86,19 @@ namespace ControlCatalog.Pages
return Comparer.Default.Compare(x, y);
}
}
private void NumericUpDown_OnTemplateApplied(object sender, TemplateAppliedEventArgs e)
{
// We want to focus the TextBox of the NumericUpDown. To do so we search for this control when the template
// is applied, but we postpone the action until the control is actually loaded.
if (e.NameScope.Find<TextBox>("PART_TextBox") is {} textBox)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
textBox.Focus();
textBox.SelectAll();
}, DispatcherPriority.Loaded);
}
}
}
}

2
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs

@ -111,7 +111,7 @@ namespace ControlCatalog.Pages
private void ScrollTo(int index)
{
System.Diagnostics.Debug.WriteLine("Scroll to " + index);
var layoutManager = ((Window)this.GetVisualRoot()).LayoutManager;
var layoutManager = ((TopLevel)VisualRoot).LayoutManager;
var element = _repeater.GetOrCreateElement(index);
layoutManager.ExecuteLayoutPass();
element.BringIntoView();

4
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -21,6 +21,7 @@
<CheckBox IsChecked="{Binding Toggle}">Toggle</CheckBox>
<CheckBox IsChecked="{Binding AlwaysSelected}">AlwaysSelected</CheckBox>
<CheckBox IsChecked="{Binding AutoScrollToSelectedItem}">AutoScrollToSelectedItem</CheckBox>
<CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>
</StackPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="4">
<Button Command="{Binding AddItemCommand}">Add</Button>
@ -30,6 +31,7 @@
<ListBox Items="{Binding Items}"
Selection="{Binding Selection}"
AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}"
SelectionMode="{Binding SelectionMode^}"/>
SelectionMode="{Binding SelectionMode^}"
WrapSelection="{Binding WrapSelection}"/>
</DockPanel>
</UserControl>

220
samples/ControlCatalog/Pages/PointersPage.cs

@ -1,15 +1,37 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace ControlCatalog.Pages
namespace ControlCatalog.Pages;
public class PointersPage : Decorator
{
public class PointersPage : Control
public PointersPage()
{
Child = new TabControl
{
Items = new[]
{
new TabItem() { Header = "Contacts", Content = new PointerContactsTab() },
new TabItem() { Header = "IntermediatePoints", Content = new PointerIntermediatePointsTab() }
}
};
}
class PointerContactsTab : Control
{
class PointerInfo
{
@ -45,7 +67,7 @@ namespace ControlCatalog.Pages
private Dictionary<IPointer, PointerInfo> _pointers = new Dictionary<IPointer, PointerInfo>();
public PointersPage()
public PointerContactsTab()
{
ClipToBounds = true;
}
@ -104,4 +126,196 @@ namespace ControlCatalog.Pages
}
}
}
public class PointerIntermediatePointsTab : Decorator
{
public PointerIntermediatePointsTab()
{
this[TextBlock.ForegroundProperty] = Brushes.Black;
var slider = new Slider
{
Margin = new Thickness(5),
Minimum = 0,
Maximum = 500
};
var status = new TextBlock()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
};
Child = new Grid
{
Children =
{
new PointerCanvas(slider, status),
new Border
{
Background = Brushes.LightYellow,
Child = new StackPanel
{
Children =
{
new StackPanel
{
Orientation = Orientation.Horizontal,
Children =
{
new TextBlock { Text = "Thread sleep:" },
new TextBlock()
{
[!TextBlock.TextProperty] =slider.GetObservable(Slider.ValueProperty)
.Select(x=>x.ToString()).ToBinding()
}
}
},
slider
}
},
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
Width = 300,
Height = 60
},
status
}
};
}
class PointerCanvas : Control
{
private readonly Slider _slider;
private readonly TextBlock _status;
private int _events;
private Stopwatch _stopwatch = Stopwatch.StartNew();
private Dictionary<int, PointerPoints> _pointers = new();
class PointerPoints
{
struct CanvasPoint
{
public IBrush Brush;
public Point Point;
public double Radius;
}
readonly CanvasPoint[] _points = new CanvasPoint[1000];
int _index;
public void Render(DrawingContext context)
{
CanvasPoint? prev = null;
for (var c = 0; c < _points.Length; c++)
{
var i = (c + _index) % _points.Length;
var pt = _points[i];
if (prev.HasValue && prev.Value.Brush != null && pt.Brush != null)
context.DrawLine(new Pen(Brushes.Black), prev.Value.Point, pt.Point);
prev = pt;
if (pt.Brush != null)
context.DrawEllipse(pt.Brush, null, pt.Point, pt.Radius, pt.Radius);
}
}
void AddPoint(Point pt, IBrush brush, double radius)
{
_points[_index] = new CanvasPoint { Point = pt, Brush = brush, Radius = radius };
_index = (_index + 1) % _points.Length;
}
public void HandleEvent(PointerEventArgs e, Visual v)
{
e.Handled = true;
if (e.RoutedEvent == PointerPressedEvent)
AddPoint(e.GetPosition(v), Brushes.Green, 10);
else if (e.RoutedEvent == PointerReleasedEvent)
AddPoint(e.GetPosition(v), Brushes.Red, 10);
else
{
var pts = e.GetIntermediatePoints(v);
for (var c = 0; c < pts.Count; c++)
{
var pt = pts[c];
AddPoint(pt.Position, c == pts.Count - 1 ? Brushes.Blue : Brushes.Black,
c == pts.Count - 1 ? 5 : 2);
}
}
}
}
public PointerCanvas(Slider slider, TextBlock status)
{
_slider = slider;
_status = status;
DispatcherTimer.Run(() =>
{
if (_stopwatch.Elapsed.TotalSeconds > 1)
{
_status.Text = "Events per second: " + (_events / _stopwatch.Elapsed.TotalSeconds);
_stopwatch.Restart();
_events = 0;
}
return this.GetVisualRoot() != null;
}, TimeSpan.FromMilliseconds(10));
}
void HandleEvent(PointerEventArgs e)
{
_events++;
Thread.Sleep((int)_slider.Value);
InvalidateVisual();
if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)
{
_pointers.Remove(e.Pointer.Id);
return;
}
if (!_pointers.TryGetValue(e.Pointer.Id, out var pt))
_pointers[e.Pointer.Id] = pt = new PointerPoints();
pt.HandleEvent(e, this);
}
public override void Render(DrawingContext context)
{
context.FillRectangle(Brushes.White, Bounds);
foreach(var pt in _pointers.Values)
pt.Render(context);
base.Render(context);
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.ClickCount == 2)
{
_pointers.Clear();
InvalidateVisual();
return;
}
HandleEvent(e);
base.OnPointerPressed(e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
HandleEvent(e);
base.OnPointerMoved(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
HandleEvent(e);
base.OnPointerReleased(e);
}
}
}
}

37
samples/ControlCatalog/Pages/ScreenPage.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
@ -49,25 +50,33 @@ namespace ControlCatalog.Pages
context.DrawRectangle(p, boundsRect);
context.DrawRectangle(p, workingAreaRect);
var text = new FormattedText() { Typeface = new Typeface("Arial"), FontSize = 18 };
text.Text = $"Bounds: {screen.Bounds.TopLeft} {screen.Bounds.Width}:{screen.Bounds.Height}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text);
text.Text = $"WorkArea: {screen.WorkingArea.TopLeft} {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
var formattedText = CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height));
text.Text = $"Scaling: {screen.PixelDensity * 100}%";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
text.Text = $"Primary: {screen.Primary}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text);
formattedText =
CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20));
formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"Primary: {screen.Primary}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText =
CreateFormattedText(
$"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 80));
}
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10));
}
private FormattedText CreateFormattedText(string textToFormat)
{
return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
Typeface.Default, 12, Brushes.Green);
}
}
}

2
samples/ControlCatalog/Pages/ToggleSwitchPage.xaml

@ -11,7 +11,7 @@
</StackPanel>
</Border>
<TextBlock Text="headered ToggleSwitch" Classes="header"/>
<TextBlock Text="Headered ToggleSwitch" Classes="header"/>
<Border Classes="Thin">
<StackPanel>

22
samples/ControlCatalog/Pages/ViewboxPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="clr-namespace:System.Collections;assembly=netstandard"
x:Class="ControlCatalog.Pages.ViewboxPage">
<Grid RowDefinitions="Auto,*,*">
@ -12,8 +13,8 @@
<Border HorizontalAlignment="Center" Grid.Column="0" BorderThickness="1" BorderBrush="Orange" Width="200" Height="200">
<Border VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0" BorderThickness="1" BorderBrush="CornflowerBlue" Width="{Binding #WidthSlider.Value}" Height="{Binding #HeightSlider.Value}" >
<Viewbox
Stretch="{Binding #StretchSelector.SelectedItem}"
StretchDirection="{Binding #StretchDirectionSelector.SelectedItem}">
Stretch="{Binding #StretchSelector.SelectedItem, FallbackValue={x:Static Stretch.Uniform}}"
StretchDirection="{Binding #StretchDirectionSelector.SelectedItem, FallbackValue={x:Static StretchDirection.Both}}">
<Ellipse Width="50" Height="50" Fill="CornflowerBlue" />
</Viewbox>
</Border>
@ -25,9 +26,22 @@
<TextBlock Text="Height" />
<Slider Minimum="10" Maximum="200" Value="100" x:Name="HeightSlider" TickFrequency="25" TickPlacement="TopLeft" />
<TextBlock Text="Stretch" />
<ComboBox x:Name="StretchSelector" HorizontalAlignment="Stretch" Margin="0,0,0,2" />
<ComboBox x:Name="StretchSelector" HorizontalAlignment="Stretch" SelectedIndex="0" Margin="0,0,0,2">
<collections:ArrayList>
<Stretch>Uniform</Stretch>
<Stretch>UniformToFill</Stretch>
<Stretch>Fill</Stretch>
<Stretch>None</Stretch>
</collections:ArrayList>
</ComboBox>
<TextBlock Text="Stretch Direction" />
<ComboBox x:Name="StretchDirectionSelector" HorizontalAlignment="Stretch" />
<ComboBox x:Name="StretchDirectionSelector" SelectedIndex="0" HorizontalAlignment="Stretch">
<collections:ArrayList>
<StretchDirection>Both</StretchDirection>
<StretchDirection>DownOnly</StretchDirection>
<StretchDirection>UpOnly</StretchDirection>
</collections:ArrayList>
</ComboBox>
</StackPanel>
</Grid>

19
samples/ControlCatalog/Pages/ViewboxPage.xaml.cs

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

21
samples/ControlCatalog/ViewModels/ComboBoxPageViewModel.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
public class ComboBoxPageViewModel : ViewModelBase
{
private bool _wrapSelection;
public bool WrapSelection
{
get => _wrapSelection;
set => this.RaiseAndSetIfChanged(ref _wrapSelection, value);
}
}
}

7
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@ -14,6 +14,7 @@ namespace ControlCatalog.ViewModels
private bool _toggle;
private bool _alwaysSelected;
private bool _autoScrollToSelectedItem = true;
private bool _wrapSelection;
private int _counter;
private IObservable<SelectionMode> _selectionMode;
@ -85,6 +86,12 @@ namespace ControlCatalog.ViewModels
set => this.RaiseAndSetIfChanged(ref _autoScrollToSelectedItem, value);
}
public bool WrapSelection
{
get => _wrapSelection;
set => this.RaiseAndSetIfChanged(ref _wrapSelection, value);
}
public MiniCommand AddItemCommand { get; }
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }

13
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -5,6 +5,7 @@ using Avalonia.Controls.Notifications;
using Avalonia.Dialogs;
using Avalonia.Platform;
using System;
using System.ComponentModel.DataAnnotations;
using MiniMvvm;
namespace ControlCatalog.ViewModels
@ -164,5 +165,17 @@ namespace ControlCatalog.ViewModels
public MiniCommand ExitCommand { get; }
public MiniCommand ToggleMenuItemCheckedCommand { get; }
private DateTime? _validatedDateExample;
/// <summary>
/// A required DateTime which should demonstrate validation for the DateTimePicker
/// </summary>
[Required]
public DateTime? ValidatedDateExample
{
get => _validatedDateExample;
set => this.RaiseAndSetIfChanged(ref _validatedDateExample, value);
}
}
}

3
samples/RenderDemo/MainWindow.xaml

@ -57,6 +57,9 @@
<TabItem Header="GlyphRun">
<pages:GlyphRunPage />
</TabItem>
<TabItem Header="FormattedText">
<pages:FormattedTextPage />
</TabItem>
<TabItem Header="LineBounds">
<pages:LineBoundsPage />
</TabItem>

54
samples/RenderDemo/Pages/ClippingPage.xaml

@ -19,30 +19,36 @@
</Style>
</Styles>
</Grid.Styles>
<Border Name="clipped"
Background="Yellow"
Width="100"
Height="100"
Clip="M 58.625 0.07421875
C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703
C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594
C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312
C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875
C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422
C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125
C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172
C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438
C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953
C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078
C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594
C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859
C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766
C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359
C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531
C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609
C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344
C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812
C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z ">
<Border Name="clipped"
Background="Yellow"
Width="100"
Height="100"
Classes.clip="{Binding #useMask.IsChecked}">
<Border.Styles>
<Style Selector="Border.clip">
<Setter Property="Clip"
Value="M 58.625 0.07421875
C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703
C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594
C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312
C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875
C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422
C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125
C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172
C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438
C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953
C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078
C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594
C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859
C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766
C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359
C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531
C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609
C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344
C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812
C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z " />
</Style>
</Border.Styles>
<Border Name="clipChild" Background="Red" Margin="4">
<!-- Setting opacity puts the TextBox on a new layer -->
<TextBox Text="Avalonia" Opacity="0.9" VerticalAlignment="Center"/>

17
samples/RenderDemo/Pages/ClippingPage.xaml.cs

@ -1,35 +1,18 @@
using System;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace RenderDemo.Pages
{
public class ClippingPage : UserControl
{
private Geometry _clip;
public ClippingPage()
{
InitializeComponent();
WireUpCheckbox();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void WireUpCheckbox()
{
var useMask = this.FindControl<CheckBox>("useMask");
var clipped = this.FindControl<Border>("clipped");
_clip = clipped.Clip;
useMask.Click += (s, e) => clipped.Clip = clipped.Clip == null ? _clip : null;
}
}
}

13
samples/RenderDemo/Pages/CustomSkiaPage.cs

@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
@ -41,7 +42,10 @@ namespace RenderDemo.Pages
{
var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas;
if (canvas == null)
context.DrawText(Brushes.Black, new Point(), _noSkia.PlatformImpl);
using (var c = new DrawingContext(context, false))
{
c.DrawText(_noSkia, new Point());
}
else
{
canvas.Save();
@ -108,10 +112,9 @@ namespace RenderDemo.Pages
public override void Render(DrawingContext context)
{
var noSkia = new FormattedText()
{
Text = "Current rendering API is not Skia"
};
var noSkia = new FormattedText("Current rendering API is not Skia", CultureInfo.CurrentCulture,
FlowDirection.LeftToRight, Typeface.Default, 12, Brushes.Black);
context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), noSkia));
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
}

7
samples/RenderDemo/Pages/FormattedTextPage.axaml

@ -0,0 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="RenderDemo.Pages.FormattedTextPage">
</UserControl>

60
samples/RenderDemo/Pages/FormattedTextPage.axaml.cs

@ -0,0 +1,60 @@
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace RenderDemo.Pages
{
public class FormattedTextPage : UserControl
{
public FormattedTextPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public override void Render(DrawingContext context)
{
const string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor";
// Create the initial formatted text string.
var formattedText = new FormattedText(
testString,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
32,
Brushes.Black) { MaxTextWidth = 300, MaxTextHeight = 240 };
// Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
// Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
// The font size is calculated in terms of points -- not as device-independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);
// Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
formattedText.SetFontWeight(FontWeight.Bold, 6, 11);
var gradient = new LinearGradientBrush
{
GradientStops =
new GradientStops { new GradientStop(Colors.Orange, 0), new GradientStop(Colors.Teal, 1) },
StartPoint = new RelativePoint(0,0, RelativeUnit.Relative),
EndPoint = new RelativePoint(0,1, RelativeUnit.Relative)
};
// Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
formattedText.SetForegroundBrush(gradient, 6, 11);
// Use an Italic font style beginning at the 28th character and continuing for 28 characters.
formattedText.SetFontStyle(FontStyle.Italic, 28, 28);
context.DrawText(formattedText, new Point(10, 0));
}
}
}

7
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -13,6 +13,7 @@ namespace RenderDemo.Pages
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
private float _fontSize = 20;
private int _direction = 10;
@ -38,7 +39,7 @@ namespace RenderDemo.Pages
private void UpdateGlyphRun()
{
var c = (uint)_rand.Next(65, 90);
var c = (char)_rand.Next(65, 90);
if (_fontSize + _direction > 200)
{
@ -54,6 +55,8 @@ namespace RenderDemo.Pages
_glyphIndices[0] = _glyphTypeface.GetGlyph(c);
_characters[0] = c;
var scale = (double)_fontSize / _glyphTypeface.DesignEmHeight;
var drawingGroup = new DrawingGroup();
@ -61,7 +64,7 @@ namespace RenderDemo.Pages
var glyphRunDrawing = new GlyphRunDrawing
{
Foreground = Brushes.Black,
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices),
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _characters, _glyphIndices)
};
drawingGroup.Children.Add(glyphRunDrawing);

4
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -25,7 +25,7 @@ namespace Avalonia.Android
_host.Focusable = true;
_host.FocusableInTouchMode = true;
_host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListner(_host));
_host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host));
}
public void Reset()
@ -83,6 +83,8 @@ namespace Avalonia.Android
if (options.Multiline)
outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine;
outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi;
});
//_inputElement.PointerReleased += RestoreSoftKeyboard;

12
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -10,7 +10,6 @@ using Avalonia.Input.Platform;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Skia;
namespace Avalonia
@ -20,9 +19,9 @@ namespace Avalonia
public static T UseAndroid<T>(this T builder) where T : AppBuilderBase<T>, new()
{
var options = AvaloniaLocator.Current.GetService<AndroidPlatformOptions>() ?? new AndroidPlatformOptions();
builder.UseWindowingSubsystem(() => AndroidPlatform.Initialize(builder.ApplicationType, options), "Android");
builder.UseSkia();
return builder;
return builder
.UseWindowingSubsystem(() => AndroidPlatform.Initialize(options), "Android")
.UseSkia();
}
}
}
@ -44,7 +43,7 @@ namespace Avalonia.Android
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(500);
public static void Initialize(Type appType, AndroidPlatformOptions options)
public static void Initialize(AndroidPlatformOptions options)
{
Options = options;
@ -59,8 +58,7 @@ namespace Avalonia.Android
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IAssetLoader>().ToConstant(new AssetLoader(appType.Assembly));
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
SkiaPlatform.Initialize();

14
src/Android/Avalonia.Android/AppBuilder.cs

@ -1,14 +0,0 @@
using Avalonia.Controls;
using Avalonia.Shared.PlatformSupport;
namespace Avalonia
{
public sealed class AppBuilder : AppBuilderBase<AppBuilder>
{
public AppBuilder() : base(new StandardRuntimePlatform(),
builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType()?.Assembly))
{
}
}
}

15
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -1,13 +1,18 @@
<Project Sdk="MSBuild.Sdk.Extras">
<Project Sdk="Xamarin.Legacy.Sdk">
<PropertyGroup>
<TargetFramework>monoandroid11.0</TargetFramework>
<TargetFrameworks>net6.0-android;monoandroid11.0</TargetFrameworks>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.1.3" />
<PackageReference Include="Xamarin.AndroidX.Lifecycle.ViewModel" Version="2.3.1.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
<Import Project="..\..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\AndroidWorkarounds.props" />
</Project>

36
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -1,35 +1,55 @@
using Android.App;
using Android.OS;
using Android.Views;
using Android.Content.PM;
using AndroidX.AppCompat.App;
using Android.Content.Res;
using AndroidX.Lifecycle;
namespace Avalonia.Android
{
public abstract class AvaloniaActivity : Activity
public abstract class AvaloniaActivity : AppCompatActivity
{
internal AvaloniaView View;
object _content;
internal AvaloniaViewModel _viewModel;
protected override void OnCreate(Bundle savedInstanceState)
{
View = new AvaloniaView(this);
if (_content != null)
View.Content = _content;
SetContentView(View);
_viewModel = new ViewModelProvider(this).Get(Java.Lang.Class.FromType(typeof(AvaloniaViewModel))) as AvaloniaViewModel;
if (_viewModel.Content != null)
{
View.Content = _viewModel.Content;
}
base.OnCreate(savedInstanceState);
}
public object Content
{
get
{
return _content;
return _viewModel.Content;
}
set
{
_content = value;
_viewModel.Content = value;
if (View != null)
View.Content = value;
}
}
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
}
protected override void OnDestroy()
{
View.Content = null;
base.OnDestroy();
}
}
}

11
src/Android/Avalonia.Android/AvaloniaViewModel.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Android
{
internal class AvaloniaViewModel : AndroidX.Lifecycle.ViewModel
{
public object Content { get; set; }
}
}

50
src/Android/Avalonia.Android/Resources/AboutResources.txt

@ -1,50 +0,0 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

6
src/Android/Avalonia.Android/Resources/Values/Strings.xml

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="Hello">Hello World, Click Me!</string>
<string name="ApplicationName">$projectname$</string>
</resources>

18
src/Android/Avalonia.Android/RuntimeInfo.cs

@ -1,18 +0,0 @@
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform
{
public RuntimePlatformInfo GetRuntimeInfo() => new RuntimePlatformInfo
{
IsCoreClr = false,
IsDesktop = false,
IsMobile = true,
IsDotNetFramework = false,
IsMono = true,
IsUnix = true,
OperatingSystem = OperatingSystemType.Android
};
}
}

4
src/Android/Avalonia.Android/SoftKeyboardListner.cs → src/Android/Avalonia.Android/SoftKeyboardListener.cs

@ -9,7 +9,7 @@ using Avalonia.Input;
namespace Avalonia.Android
{
class SoftKeyboardListner : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
class SoftKeyboardListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
private const int DefaultKeyboardHeightDP = 100;
private static readonly int EstimatedKeyboardDP = DefaultKeyboardHeightDP + (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop ? 48 : 0);
@ -17,7 +17,7 @@ namespace Avalonia.Android
private readonly View _host;
private bool _wasKeyboard;
public SoftKeyboardListner(View view)
public SoftKeyboardListener(View view)
{
_host = view;
}

19
src/Android/Avalonia.AndroidTestApplication/Assets/AboutAssets.txt

@ -1,19 +0,0 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with you package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

172
src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj

@ -1,153 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{FF69B927-C545-49AE-8E16-3D14D621AA12}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Avalonia.AndroidTestApplication</RootNamespace>
<AssemblyName>Avalonia.AndroidTestApplication</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<TargetFramework>net6.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ApplicationId>com.Avalonia.AndroidTestApplication</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<DebugType>portable</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition="'$(Configuration)'=='Release' and '$(TF_BUILD)' == ''">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<DevInstrumentationEnabled>True</DevInstrumentationEnabled>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<EnableProguard>False</EnableProguard>
<RunAOTCompilation>True</RunAOTCompilation>
<EnableLLVM>True</EnableLLVM>
<!--<AndroidEnableProfiledAot>True</AndroidEnableProfiledAot>-->
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>Full</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a,x86</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<EnableProguard>False</EnableProguard>
<DevInstrumentationEnabled>False</DevInstrumentationEnabled>
<DebugSymbols>False</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
<None Remove="Assets\AboutAssets.txt" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<BundleAssemblies>True</BundleAssemblies>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<BundleAssemblies>True</BundleAssemblies>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj">
<Project>{7b92af71-6287-4693-9dcb-bd5b6e927e23}</Project>
<Name>Avalonia.Android</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Avalonia.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Avalonia.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Base\Avalonia.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Avalonia.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Avalonia.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Avalonia.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj">
<Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project>
<Name>Avalonia.Skia</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Avalonia.Android\Avalonia.Android.csproj" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\..\build\Base.props" />
<Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\System.Memory.props" />
<Import Project="..\..\..\build\AndroidWorkarounds.props" />
<Import Project="..\..\..\build\LegacyProject.targets" />
</Project>

2
src/Android/Avalonia.AndroidTestApplication/MainActivity.cs

@ -14,6 +14,8 @@ namespace Avalonia.AndroidTestApplication
[Activity(Label = "Main",
MainLauncher = true,
Icon = "@drawable/icon",
Theme = "@style/Theme.AppCompat.NoActionBar",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize,
LaunchMode = LaunchMode.SingleInstance/*,
ScreenOrientation = ScreenOrientation.Landscape*/)]
public class MainBaseActivity : AvaloniaActivity

6
src/Android/Avalonia.AndroidTestApplication/Properties/AndroidManifest.xml

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="Avalonia.AndroidTestApplication" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:targetSdkVersion="30" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:label="Avalonia.AndroidTestApplication" android:icon="@drawable/Icon" android:hardwareAccelerated="true"></application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
</manifest>

30
src/Android/Avalonia.AndroidTestApplication/Properties/AssemblyInfo.cs

@ -1,30 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.AndroidTestApplication")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.AndroidTestApplication")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

79
src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs

@ -1,79 +0,0 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("Avalonia.AndroidTestApplication.Resource", IsApplication=true)]
namespace Avalonia.AndroidTestApplication
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public static void UpdateIdValues()
{
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class Drawable
{
// aapt resource value: 0x7F010000
public const int Icon = 2130771968;
static Drawable()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Drawable()
{
}
}
public partial class String
{
// aapt resource value: 0x7F020000
public const int ApplicationName = 2130837504;
// aapt resource value: 0x7F020001
public const int Hello = 2130837505;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}
}
}
}
#pragma warning restore 1591

11
src/Android/Avalonia.AndroidTestApplication/app.config

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices.WindowsRuntime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

16
src/Avalonia.Animation/Animatable.cs

@ -157,7 +157,7 @@ namespace Avalonia.Animation
state.Instance?.Dispose();
state.Instance = transition.Apply(
this,
Clock ?? AvaloniaLocator.Current.GetService<IGlobalClock>(),
Clock ?? AvaloniaLocator.Current.GetRequiredService<IGlobalClock>(),
oldValue,
newValue);
return;
@ -169,7 +169,7 @@ namespace Avalonia.Animation
base.OnPropertyChangedCore(change);
}
private void TransitionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
private void TransitionsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (!_transitionsEnabled)
{
@ -179,14 +179,14 @@ namespace Avalonia.Animation
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
AddTransitions(e.NewItems);
AddTransitions(e.NewItems!);
break;
case NotifyCollectionChangedAction.Remove:
RemoveTransitions(e.OldItems);
RemoveTransitions(e.OldItems!);
break;
case NotifyCollectionChangedAction.Replace:
RemoveTransitions(e.OldItems);
AddTransitions(e.NewItems);
RemoveTransitions(e.OldItems!);
AddTransitions(e.NewItems!);
break;
case NotifyCollectionChangedAction.Reset:
throw new NotSupportedException("Transitions collection cannot be reset.");
@ -204,7 +204,7 @@ namespace Avalonia.Animation
for (var i = 0; i < items.Count; ++i)
{
var t = (ITransition)items[i];
var t = (ITransition)items[i]!;
_transitionState.Add(t, new TransitionState
{
@ -222,7 +222,7 @@ namespace Avalonia.Animation
for (var i = 0; i < items.Count; ++i)
{
var t = (ITransition)items[i];
var t = (ITransition)items[i]!;
if (_transitionState.TryGetValue(t, out var state))
{

46
src/Avalonia.Animation/Animation.cs

@ -203,7 +203,7 @@ namespace Avalonia.Animation
/// </summary>
/// <param name="setter">The animation setter.</param>
/// <returns>The property animator type.</returns>
public static Type GetAnimator(IAnimationSetter setter)
public static Type? GetAnimator(IAnimationSetter setter)
{
if (s_animators.TryGetValue(setter, out var type))
{
@ -254,7 +254,7 @@ namespace Avalonia.Animation
Animators.Insert(0, (condition, typeof(TAnimator)));
}
private static Type GetAnimatorType(AvaloniaProperty property)
private static Type? GetAnimatorType(AvaloniaProperty property)
{
foreach (var (condition, type) in Animators)
{
@ -276,6 +276,11 @@ namespace Avalonia.Animation
{
foreach (var setter in keyframe.Setters)
{
if (setter.Property is null)
{
throw new InvalidOperationException("No Setter property assigned.");
}
var handler = Animation.GetAnimator(setter) ?? GetAnimatorType(setter.Property);
if (handler == null)
@ -305,7 +310,7 @@ namespace Avalonia.Animation
foreach (var (handlerType, property) in handlerList)
{
var newInstance = (IAnimator)Activator.CreateInstance(handlerType);
var newInstance = (IAnimator)Activator.CreateInstance(handlerType)!;
newInstance.Property = property;
newAnimatorInstances.Add(newInstance);
}
@ -321,32 +326,43 @@ namespace Avalonia.Animation
}
/// <inheritdoc/>
public IDisposable Apply(Animatable control, IClock clock, IObservable<bool> match, Action onComplete)
public IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
{
var (animators, subscriptions) = InterpretKeyframes(control);
if (animators.Count == 1)
{
subscriptions.Add(animators[0].Apply(this, control, clock, match, onComplete));
var subscription = animators[0].Apply(this, control, clock, match, onComplete);
if (subscription is not null)
{
subscriptions.Add(subscription);
}
}
else
{
var completionTasks = onComplete != null ? new List<Task>() : null;
foreach (IAnimator animator in animators)
{
Action animatorOnComplete = null;
Action? animatorOnComplete = null;
if (onComplete != null)
{
var tcs = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object?>();
animatorOnComplete = () => tcs.SetResult(null);
completionTasks.Add(tcs.Task);
completionTasks!.Add(tcs.Task);
}
var subscription = animator.Apply(this, control, clock, match, animatorOnComplete);
if (subscription is not null)
{
subscriptions.Add(subscription);
}
subscriptions.Add(animator.Apply(this, control, clock, match, animatorOnComplete));
}
if (onComplete != null)
{
Task.WhenAll(completionTasks).ContinueWith(
(_, state) => ((Action)state).Invoke(),
Task.WhenAll(completionTasks!).ContinueWith(
(_, state) => ((Action)state!).Invoke(),
onComplete);
}
}
@ -354,25 +370,25 @@ namespace Avalonia.Animation
}
/// <inheritdoc/>
public Task RunAsync(Animatable control, IClock clock = null)
public Task RunAsync(Animatable control, IClock? clock = null)
{
return RunAsync(control, clock, default);
}
/// <inheritdoc/>
public Task RunAsync(Animatable control, IClock clock = null, CancellationToken cancellationToken = default)
public Task RunAsync(Animatable control, IClock? clock = null, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.CompletedTask;
}
var run = new TaskCompletionSource<object>();
var run = new TaskCompletionSource<object?>();
if (this.IterationCount == IterationCount.Infinite)
run.SetException(new InvalidOperationException("Looping animations must not use the Run method."));
IDisposable subscriptions = null, cancellation = null;
IDisposable? subscriptions = null, cancellation = null;
subscriptions = this.Apply(control, clock, Observable.Return(true), () =>
{
run.TrySetResult(null);

33
src/Avalonia.Animation/AnimationInstance`1.cs

@ -31,15 +31,15 @@ namespace Avalonia.Animation
private TimeSpan _initialDelay;
private TimeSpan _iterationDelay;
private TimeSpan _duration;
private Easings.Easing _easeFunc;
private Action _onCompleteAction;
private Easings.Easing? _easeFunc;
private Action? _onCompleteAction;
private Func<double, T, T> _interpolator;
private IDisposable _timerSub;
private IDisposable? _timerSub;
private readonly IClock _baseClock;
private IClock _clock;
private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChangedDelegate;
private IClock? _clock;
private EventHandler<AvaloniaPropertyChangedEventArgs>? _propertyChangedDelegate;
public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, IClock baseClock, Action OnComplete, Func<double, T, T> Interpolator)
public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, IClock baseClock, Action? OnComplete, Func<double, T, T> Interpolator)
{
_animator = animator;
_animation = animation;
@ -47,6 +47,9 @@ namespace Avalonia.Animation
_onCompleteAction = OnComplete;
_interpolator = Interpolator;
_baseClock = baseClock;
_lastInterpValue = default!;
_firstKFValue = default!;
_neutralValue = default!;
FetchProperties();
}
@ -82,7 +85,7 @@ namespace Avalonia.Animation
_targetControl.PropertyChanged -= _propertyChangedDelegate;
_timerSub?.Dispose();
_clock.PlayState = PlayState.Stop;
_clock!.PlayState = PlayState.Stop;
}
protected override void Subscribed()
@ -108,6 +111,8 @@ namespace Avalonia.Animation
private void ApplyFinalFill()
{
if (_animator.Property is null)
throw new InvalidOperationException("Animator has no property specified.");
if (_fillMode == FillMode.Forward || _fillMode == FillMode.Both)
_targetControl.SetValue(_animator.Property, _lastInterpValue, BindingPriority.LocalValue);
}
@ -130,12 +135,12 @@ namespace Avalonia.Animation
private void DoPlayStates()
{
if (_clock.PlayState == PlayState.Stop || _baseClock.PlayState == PlayState.Stop)
if (_clock!.PlayState == PlayState.Stop || _baseClock.PlayState == PlayState.Stop)
DoComplete();
if (!_gotFirstKFValue)
{
_firstKFValue = (T)_animator.First().Value;
_firstKFValue = (T)_animator.First().Value!;
_gotFirstKFValue = true;
}
}
@ -169,7 +174,7 @@ namespace Avalonia.Animation
// and snap the last iteration value to exact values.
if ((_currentIteration + 1) > _iterationCount)
{
var easedTime = _easeFunc.Ease(_playbackReversed ? 0.0 : 1.0);
var easedTime = _easeFunc!.Ease(_playbackReversed ? 0.0 : 1.0);
_lastInterpValue = _interpolator(easedTime, _neutralValue);
DoComplete();
}
@ -203,7 +208,7 @@ namespace Avalonia.Animation
normalizedTime = 1 - normalizedTime;
// Ease and interpolate
var easedTime = _easeFunc.Ease(normalizedTime);
var easedTime = _easeFunc!.Ease(normalizedTime);
_lastInterpValue = _interpolator(easedTime, _neutralValue);
PublishNext(_lastInterpValue);
@ -223,14 +228,14 @@ namespace Avalonia.Animation
private void UpdateNeutralValue()
{
var property = _animator.Property;
var property = _animator.Property ?? throw new InvalidOperationException("Animator has no property specified.");
var baseValue = _targetControl.GetBaseValue(property, BindingPriority.LocalValue);
_neutralValue = baseValue != AvaloniaProperty.UnsetValue ?
(T)baseValue : (T)_targetControl.GetValue(property);
(T)baseValue! : (T)_targetControl.GetValue(property)!;
}
private void ControlPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
private void ControlPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == _animator.Property && e.Priority > BindingPriority.Animation)
{

20
src/Avalonia.Animation/AnimatorKeyFrame.cs

@ -12,22 +12,22 @@ namespace Avalonia.Animation
/// </summary>
public class AnimatorKeyFrame : AvaloniaObject
{
public static readonly DirectProperty<AnimatorKeyFrame, object> ValueProperty =
AvaloniaProperty.RegisterDirect<AnimatorKeyFrame, object>(nameof(Value), k => k.Value, (k, v) => k.Value = v);
public static readonly DirectProperty<AnimatorKeyFrame, object?> ValueProperty =
AvaloniaProperty.RegisterDirect<AnimatorKeyFrame, object?>(nameof(Value), k => k.Value, (k, v) => k.Value = v);
public AnimatorKeyFrame()
{
}
public AnimatorKeyFrame(Type animatorType, Cue cue)
public AnimatorKeyFrame(Type? animatorType, Cue cue)
{
AnimatorType = animatorType;
Cue = cue;
KeySpline = null;
}
public AnimatorKeyFrame(Type animatorType, Cue cue, KeySpline keySpline)
public AnimatorKeyFrame(Type? animatorType, Cue cue, KeySpline? keySpline)
{
AnimatorType = animatorType;
Cue = cue;
@ -35,14 +35,14 @@ namespace Avalonia.Animation
}
internal bool isNeutral;
public Type AnimatorType { get; }
public Type? AnimatorType { get; }
public Cue Cue { get; }
public KeySpline KeySpline { get; }
public AvaloniaProperty Property { get; private set; }
public KeySpline? KeySpline { get; }
public AvaloniaProperty? Property { get; private set; }
private object _value;
private object? _value;
public object Value
public object? Value
{
get => _value;
set => SetAndRaise(ValueProperty, ref _value, value);
@ -80,7 +80,7 @@ namespace Avalonia.Animation
throw new InvalidCastException($"KeyFrame value doesnt match property type.");
}
return (T)typeConv.ConvertTo(Value, typeof(T));
return (T)typeConv.ConvertTo(Value, typeof(T))!;
}
}
}

9
src/Avalonia.Animation/Animators/Animator`1.cs

@ -24,7 +24,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Gets or sets the target property for the keyframe.
/// </summary>
public AvaloniaProperty Property { get; set; }
public AvaloniaProperty? Property { get; set; }
public Animator()
{
@ -33,7 +33,7 @@ namespace Avalonia.Animation.Animators
}
/// <inheritdoc/>
public virtual IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> match, Action onComplete)
public virtual IDisposable? Apply(Animation animation, Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
{
if (!_isVerifiedAndConverted)
VerifyConvertKeyFrames();
@ -106,13 +106,16 @@ namespace Avalonia.Animation.Animators
public virtual IDisposable BindAnimation(Animatable control, IObservable<T> instance)
{
if (Property is null)
throw new InvalidOperationException("Animator has no property specified.");
return control.Bind((AvaloniaProperty<T>)Property, instance, BindingPriority.Animation);
}
/// <summary>
/// Runs the KeyFrames Animation.
/// </summary>
internal IDisposable Run(Animation animation, Animatable control, IClock clock, Action onComplete)
internal IDisposable Run(Animation animation, Animatable control, IClock? clock, Action? onComplete)
{
var instance = new AnimationInstance<T>(
animation,

4
src/Avalonia.Animation/Avalonia.Animation.csproj

@ -2,9 +2,13 @@
<PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
</ItemGroup>
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project>

2
src/Avalonia.Animation/Clock.cs

@ -4,7 +4,7 @@ namespace Avalonia.Animation
{
public class Clock : ClockBase
{
public static IClock GlobalClock => AvaloniaLocator.Current.GetService<IGlobalClock>();
public static IClock GlobalClock => AvaloniaLocator.Current.GetRequiredService<IGlobalClock>();
private readonly IDisposable _parentSubscription;

8
src/Avalonia.Animation/Cue.cs

@ -30,7 +30,7 @@ namespace Avalonia.Animation
/// <summary>
/// Parses a string to a <see cref="Cue"/> object.
/// </summary>
public static Cue Parse(string value, CultureInfo culture)
public static Cue Parse(string value, CultureInfo? culture)
{
string v = value;
@ -72,14 +72,14 @@ namespace Avalonia.Animation
public class CueTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return Cue.Parse((string)value, culture);
}
}
}
}

8
src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs

@ -8,15 +8,15 @@ namespace Avalonia.Animation
/// </summary>
internal class DisposeAnimationInstanceSubject<T> : IObserver<bool>, IDisposable
{
private IDisposable _lastInstance;
private IDisposable? _lastInstance;
private bool _lastMatch;
private Animator<T> _animator;
private Animation _animation;
private Animatable _control;
private Action _onComplete;
private IClock _clock;
private Action? _onComplete;
private IClock? _clock;
public DisposeAnimationInstanceSubject(Animator<T> animator, Animation animation, Animatable control, IClock clock, Action onComplete)
public DisposeAnimationInstanceSubject(Animator<T> animator, Animation animation, Animatable control, IClock? clock, Action? onComplete)
{
this._animator = animator;
this._animation = animation;

4
src/Avalonia.Animation/Easing/Easing.cs

@ -15,7 +15,7 @@ namespace Avalonia.Animation.Easings
/// <inheritdoc/>
public abstract double Ease(double progress);
static Dictionary<string, Type> _easingTypes;
static Dictionary<string, Type>? _easingTypes;
static readonly Type s_thisType = typeof(Easing);
@ -48,7 +48,7 @@ namespace Avalonia.Animation.Easings
if (_easingTypes.ContainsKey(e))
{
var type = _easingTypes[e];
return (Easing)Activator.CreateInstance(type);
return (Easing)Activator.CreateInstance(type)!;
}
else
{

4
src/Avalonia.Animation/Easing/EasingTypeConverter.cs

@ -6,12 +6,12 @@ namespace Avalonia.Animation.Easings
{
public class EasingTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return Easing.Parse((string)value);
}

2
src/Avalonia.Animation/IAnimation.cs

@ -12,7 +12,7 @@ namespace Avalonia.Animation
/// <summary>
/// Apply the animation to the specified control and run it when <paramref name="match" /> produces <c>true</c>.
/// </summary>
IDisposable Apply(Animatable control, IClock clock, IObservable<bool> match, Action onComplete = null);
IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete = null);
/// <summary>
/// Run the animation on the specified control.

4
src/Avalonia.Animation/IAnimationSetter.cs

@ -2,7 +2,7 @@ namespace Avalonia.Animation
{
public interface IAnimationSetter
{
AvaloniaProperty Property { get; set; }
object Value { get; set; }
AvaloniaProperty? Property { get; set; }
object? Value { get; set; }
}
}

4
src/Avalonia.Animation/IAnimator.cs

@ -11,11 +11,11 @@ namespace Avalonia.Animation
/// <summary>
/// The target property.
/// </summary>
AvaloniaProperty Property {get; set;}
AvaloniaProperty? Property {get; set;}
/// <summary>
/// Applies the current KeyFrame group to the specified control.
/// </summary>
IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> match, Action onComplete);
IDisposable? Apply(Animation animation, Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete);
}
}

2
src/Avalonia.Animation/ITransition.cs

@ -10,7 +10,7 @@ namespace Avalonia.Animation
/// <summary>
/// Applies the transition to the specified <see cref="Animatable"/>.
/// </summary>
IDisposable Apply(Animatable control, IClock clock, object oldValue, object newValue);
IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
/// <summary>
/// Gets the property to be animated.

2
src/Avalonia.Animation/IterationCount.cs

@ -97,7 +97,7 @@ namespace Avalonia.Animation
/// </summary>
/// <param name="o">The object with which to test equality.</param>
/// <returns>True if the objects are equal, otherwise false.</returns>
public override bool Equals(object o)
public override bool Equals(object? o)
{
if (o == null)
{

4
src/Avalonia.Animation/IterationCountTypeConverter.cs

@ -6,12 +6,12 @@ namespace Avalonia.Animation
{
public class IterationCountTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return IterationCount.Parse((string)value);
}

4
src/Avalonia.Animation/KeyFrame.cs

@ -19,7 +19,7 @@ namespace Avalonia.Animation
{
private TimeSpan _ktimeSpan;
private Cue _kCue;
private KeySpline _kKeySpline;
private KeySpline? _kKeySpline;
public KeyFrame()
{
@ -79,7 +79,7 @@ namespace Avalonia.Animation
/// Gets or sets the KeySpline of this <see cref="KeyFrame"/>.
/// </summary>
/// <value>The key spline.</value>
public KeySpline KeySpline
public KeySpline? KeySpline
{
get
{

4
src/Avalonia.Animation/KeySplineTypeConverter.cs

@ -12,12 +12,12 @@ namespace Avalonia.Animation
/// </summary>
public class KeySplineTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return KeySpline.Parse((string)value, CultureInfo.InvariantCulture);
}

21
src/Avalonia.Animation/Transition.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation.Easings;
namespace Avalonia.Animation
@ -8,7 +9,7 @@ namespace Avalonia.Animation
/// </summary>
public abstract class Transition<T> : AvaloniaObject, ITransition
{
private AvaloniaProperty _prop;
private AvaloniaProperty? _prop;
/// <summary>
/// Gets or sets the duration of the transition.
@ -26,7 +27,8 @@ namespace Avalonia.Animation
public Easing Easing { get; set; } = new LinearEasing();
/// <inheritdocs/>
public AvaloniaProperty Property
[DisallowNull]
public AvaloniaProperty? Property
{
get
{
@ -42,16 +44,25 @@ namespace Avalonia.Animation
}
}
AvaloniaProperty ITransition.Property
{
get => Property ?? throw new InvalidOperationException("Transition has no property specified.");
set => Property = value;
}
/// <summary>
/// Apply interpolation to the property.
/// </summary>
public abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
/// <inheritdocs/>
public virtual IDisposable Apply(Animatable control, IClock clock, object oldValue, object newValue)
public virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
{
var transition = DoTransition(new TransitionInstance(clock, Delay, Duration), (T)oldValue, (T)newValue);
if (Property is null)
throw new InvalidOperationException("Transition has no property specified.");
var transition = DoTransition(new TransitionInstance(clock, Delay, Duration), (T)oldValue!, (T)newValue!);
return control.Bind<T>((AvaloniaProperty<T>)Property, transition, Data.BindingPriority.Animation);
}
}
}
}

6
src/Avalonia.Animation/TransitionInstance.cs

@ -10,11 +10,11 @@ namespace Avalonia.Animation
/// </summary>
internal class TransitionInstance : SingleSubscriberObservableBase<double>, IObserver<TimeSpan>
{
private IDisposable _timerSubscription;
private IDisposable? _timerSubscription;
private TimeSpan _delay;
private TimeSpan _duration;
private readonly IClock _baseClock;
private TransitionClock _clock;
private TransitionClock? _clock;
public TransitionInstance(IClock clock, TimeSpan delay, TimeSpan duration)
{
@ -67,7 +67,7 @@ namespace Avalonia.Animation
protected override void Unsubscribed()
{
_timerSubscription?.Dispose();
_clock.PlayState = PlayState.Stop;
_clock!.PlayState = PlayState.Stop;
}
protected override void Subscribed()

1
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@ -146,6 +146,7 @@ namespace Avalonia.Collections
{
if (_inner.TryGetValue(key, out var value))
{
_inner.Remove(key);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));

21
src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs

@ -59,7 +59,7 @@ namespace Avalonia.Collections
}
private class WeakCollectionChangedObservable : LightweightObservableBase<NotifyCollectionChangedEventArgs>,
IWeakSubscriber<NotifyCollectionChangedEventArgs>
IWeakEventSubscriber<NotifyCollectionChangedEventArgs>
{
private WeakReference<INotifyCollectionChanged> _sourceReference;
@ -68,31 +68,22 @@ namespace Avalonia.Collections
_sourceReference = source;
}
public void OnEvent(object? sender, NotifyCollectionChangedEventArgs e)
public void OnEvent(object? sender,
WeakEvent ev,
NotifyCollectionChangedEventArgs e)
{
PublishNext(e);
}
protected override void Initialize()
{
if (_sourceReference.TryGetTarget(out var instance))
{
WeakSubscriptionManager.Subscribe(
instance,
nameof(instance.CollectionChanged),
this);
}
WeakEvents.CollectionChanged.Subscribe(instance, this);
}
protected override void Deinitialize()
{
if (_sourceReference.TryGetTarget(out var instance))
{
WeakSubscriptionManager.Unsubscribe(
instance,
nameof(instance.CollectionChanged),
this);
}
WeakEvents.CollectionChanged.Unsubscribe(instance, this);
}
}
}

10
src/Avalonia.Base/Data/Core/IndexerNodeBase.cs

@ -23,18 +23,16 @@ namespace Avalonia.Data.Core
if (incc != null)
{
inputs.Add(WeakObservable.FromEventPattern<INotifyCollectionChanged, NotifyCollectionChangedEventArgs>(
incc,
nameof(incc.CollectionChanged))
inputs.Add(WeakObservable.FromEventPattern(
incc, WeakEvents.CollectionChanged)
.Where(x => ShouldUpdate(x.Sender, x.EventArgs))
.Select(_ => GetValue(target)));
}
if (inpc != null)
{
inputs.Add(WeakObservable.FromEventPattern<INotifyPropertyChanged, PropertyChangedEventArgs>(
inpc,
nameof(inpc.PropertyChanged))
inputs.Add(WeakObservable.FromEventPattern(
inpc, WeakEvents.PropertyChanged)
.Where(x => ShouldUpdate(x.Sender, x.EventArgs))
.Select(_ => GetValue(target)));
}

20
src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs

@ -11,6 +11,12 @@ namespace Avalonia.Data.Core.Plugins
/// </summary>
public class IndeiValidationPlugin : IDataValidationPlugin
{
private static readonly WeakEvent<INotifyDataErrorInfo, DataErrorsChangedEventArgs>
ErrorsChangedWeakEvent = WeakEvent.Register<INotifyDataErrorInfo, DataErrorsChangedEventArgs>(
(s, h) => s.ErrorsChanged += h,
(s, h) => s.ErrorsChanged -= h
);
/// <inheritdoc/>
public bool Match(WeakReference<object?> reference, string memberName)
{
@ -25,7 +31,7 @@ namespace Avalonia.Data.Core.Plugins
return new Validator(reference, name, accessor);
}
private class Validator : DataValidationBase, IWeakSubscriber<DataErrorsChangedEventArgs>
private class Validator : DataValidationBase, IWeakEventSubscriber<DataErrorsChangedEventArgs>
{
private readonly WeakReference<object?> _reference;
private readonly string _name;
@ -37,7 +43,7 @@ namespace Avalonia.Data.Core.Plugins
_name = name;
}
void IWeakSubscriber<DataErrorsChangedEventArgs>.OnEvent(object? sender, DataErrorsChangedEventArgs e)
void IWeakEventSubscriber<DataErrorsChangedEventArgs>.OnEvent(object? notifyDataErrorInfo, WeakEvent ev, DataErrorsChangedEventArgs e)
{
if (e.PropertyName == _name || string.IsNullOrEmpty(e.PropertyName))
{
@ -51,10 +57,7 @@ namespace Avalonia.Data.Core.Plugins
if (target != null)
{
WeakSubscriptionManager.Subscribe(
target,
nameof(target.ErrorsChanged),
this);
ErrorsChangedWeakEvent.Subscribe(target, this);
}
base.SubscribeCore();
@ -66,10 +69,7 @@ namespace Avalonia.Data.Core.Plugins
if (target != null)
{
WeakSubscriptionManager.Unsubscribe(
target,
nameof(target.ErrorsChanged),
this);
ErrorsChangedWeakEvent.Unsubscribe(target, this);
}
base.UnsubscribeCore();

24
src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using Avalonia.Utilities;
@ -85,7 +86,7 @@ namespace Avalonia.Data.Core.Plugins
return found;
}
private class Accessor : PropertyAccessorBase, IWeakSubscriber<PropertyChangedEventArgs>
private class Accessor : PropertyAccessorBase, IWeakEventSubscriber<PropertyChangedEventArgs>
{
private readonly WeakReference<object?> _reference;
private readonly PropertyInfo _property;
@ -129,7 +130,8 @@ namespace Avalonia.Data.Core.Plugins
return false;
}
void IWeakSubscriber<PropertyChangedEventArgs>.OnEvent(object? sender, PropertyChangedEventArgs e)
void IWeakEventSubscriber<PropertyChangedEventArgs>.
OnEvent(object? notifyPropertyChanged, WeakEvent ev, PropertyChangedEventArgs e)
{
if (e.PropertyName == _property.Name || string.IsNullOrEmpty(e.PropertyName))
{
@ -148,13 +150,8 @@ namespace Avalonia.Data.Core.Plugins
{
var inpc = GetReferenceTarget() as INotifyPropertyChanged;
if (inpc != null)
{
WeakSubscriptionManager.Unsubscribe(
inpc,
nameof(inpc.PropertyChanged),
this);
}
if (inpc != null)
WeakEvents.PropertyChanged.Unsubscribe(inpc, this);
}
private object? GetReferenceTarget()
@ -178,13 +175,8 @@ namespace Avalonia.Data.Core.Plugins
{
var inpc = GetReferenceTarget() as INotifyPropertyChanged;
if (inpc != null)
{
WeakSubscriptionManager.Subscribe(
inpc,
nameof(inpc.PropertyChanged),
this);
}
if (inpc != null)
WeakEvents.PropertyChanged.Subscribe(inpc, this);
}
}
}

5
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@ -1,5 +1,4 @@
using System;
using System.Reflection;
namespace Avalonia.Platform
{
@ -23,6 +22,7 @@ namespace Avalonia.Platform
public OperatingSystemType OperatingSystem { get; set; }
public bool IsDesktop { get; set; }
public bool IsMobile { get; set; }
public bool IsBrowser { get; set; }
public bool IsCoreClr { get; set; }
public bool IsMono { get; set; }
public bool IsDotNetFramework { get; set; }
@ -36,6 +36,7 @@ namespace Avalonia.Platform
Linux,
OSX,
Android,
iOS
iOS,
Browser
}
}

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

@ -30,7 +30,7 @@ namespace Avalonia.Threading
/// <inheritdoc/>
public override void Post(SendOrPostCallback d, object? state)
{
Dispatcher.UIThread.Post(() => d(state), DispatcherPriority.Send);
Dispatcher.UIThread.Post(() => d(state), DispatcherPriority.Background);
}
/// <inheritdoc/>

7
src/Avalonia.Base/Threading/Dispatcher.cs

@ -74,6 +74,13 @@ namespace Avalonia.Threading
/// </summary>
/// <param name="minimumPriority"></param>
public void RunJobs(DispatcherPriority minimumPriority) => _jobRunner.RunJobs(minimumPriority);
/// <summary>
/// Use this method to check if there are more prioritized tasks
/// </summary>
/// <param name="minimumPriority"></param>
public bool HasJobsWithPriority(DispatcherPriority minimumPriority) =>
_jobRunner.HasJobsWithPriority(minimumPriority);
/// <inheritdoc/>
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)

15
src/Avalonia.Base/Threading/JobRunner.cs

@ -121,6 +121,21 @@ namespace Avalonia.Threading
return null;
}
public bool HasJobsWithPriority(DispatcherPriority minimumPriority)
{
for (int c = (int)minimumPriority; c < (int)DispatcherPriority.MaxValue; c++)
{
var q = _queues[c];
lock (q)
{
if (q.Count > 0)
return true;
}
}
return false;
}
private interface IJob
{
/// <summary>

12
src/Avalonia.Base/Utilities/IWeakEventSubscriber.cs

@ -0,0 +1,12 @@
using System;
namespace Avalonia.Utilities;
/// <summary>
/// Defines a listener to a event subscribed vis the <see cref="WeakEvent{TTarget, TEventArgs}"/>.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event arguments.</typeparam>
public interface IWeakEventSubscriber<in TEventArgs> where TEventArgs : EventArgs
{
void OnEvent(object? sender, WeakEvent ev, TEventArgs e);
}

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

Loading…
Cancel
Save