Browse Source

Merge branch 'master' into feat/color-tostring-formats

pull/20919/head
Jumar Macato 7 months ago
committed by GitHub
parent
commit
be9bb8d1eb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .github/PULL_REQUEST_TEMPLATE.md
  2. 3
      .github/copilot-instructions.md
  3. 4
      .github/workflows/update-api.yml
  4. 2
      Avalonia.Desktop.slnf
  5. 764
      Avalonia.sln
  6. 197
      Avalonia.slnx
  7. 0
      Avalonia.slnx.DotSettings
  8. 22
      Directory.Packages.props
  9. 11
      SECURITY.md
  10. 28
      api/Avalonia.Skia.nupkg.xml
  11. 16
      api/Avalonia.Win32.nupkg.xml
  12. 252
      api/Avalonia.nupkg.xml
  13. 26
      build/MicroCOM.props
  14. 2
      docs/build.md
  15. 2
      external/Avalonia.DBus
  16. 87
      native/Avalonia.Native/README.md
  17. 81
      native/Avalonia.Native/inc/comimpl.h
  18. 13
      native/Avalonia.Native/src/OSX/AvnString.mm
  19. 8
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  20. 4
      native/Avalonia.Native/src/OSX/TopLevelImpl.mm
  21. 2
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  22. 2
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  23. 10
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  24. 37
      native/Avalonia.Native/src/OSX/automation.mm
  25. 2
      native/Avalonia.Native/src/OSX/cgl.mm
  26. 37
      native/Avalonia.Native/src/OSX/clipboard.mm
  27. 3
      native/Avalonia.Native/src/OSX/common.h
  28. 1
      native/Avalonia.Native/src/OSX/cursor.h
  29. 34
      native/Avalonia.Native/src/OSX/cursor.mm
  30. 4
      native/Avalonia.Native/src/OSX/menu.h
  31. 24
      native/Avalonia.Native/src/OSX/menu.mm
  32. 2
      native/Avalonia.Native/src/OSX/metal.mm
  33. 2
      nukebuild/Build.cs
  34. 4
      nukebuild/_build.csproj
  35. 100
      readme.md
  36. 2
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  37. 2
      samples/ControlCatalog/MainView.xaml
  38. 4
      samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs
  39. 8
      samples/ControlCatalog/Pages/CarouselPage/SanctuaryMainPage.xaml
  40. 9
      samples/ControlCatalog/Pages/ClipboardPage.xaml.cs
  41. 24
      samples/ControlCatalog/Pages/CommandBar/CommandBarCustomizationPage.xaml
  42. 40
      samples/ControlCatalog/Pages/CommandBar/CommandBarDynamicOverflowPage.xaml
  43. 64
      samples/ControlCatalog/Pages/CommandBar/CommandBarDynamicOverflowPage.xaml.cs
  44. 10
      samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml
  45. 18
      samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml.cs
  46. 56
      samples/ControlCatalog/Pages/CommandBar/CommandBarFirstLookPage.xaml
  47. 4
      samples/ControlCatalog/Pages/CommandBar/CommandBarFirstLookPage.xaml.cs
  48. 121
      samples/ControlCatalog/Pages/CommandBar/CommandBarKeyboardPage.xaml
  49. 93
      samples/ControlCatalog/Pages/CommandBar/CommandBarKeyboardPage.xaml.cs
  50. 24
      samples/ControlCatalog/Pages/CommandBar/CommandBarLabelPositionPage.xaml
  51. 10
      samples/ControlCatalog/Pages/CommandBar/CommandBarOverflowPage.xaml
  52. 4
      samples/ControlCatalog/Pages/CommandBar/CommandBarOverflowPage.xaml.cs
  53. 28
      samples/ControlCatalog/Pages/CommandBar/CommandBarTogglePage.xaml
  54. 3
      samples/ControlCatalog/Pages/CommandBarPage.xaml.cs
  55. 20
      samples/ControlCatalog/Pages/ContentPage/ContentPageCommandBarPage.xaml.cs
  56. 16
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml
  57. 127
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml.cs
  58. 8
      samples/ControlCatalog/Pages/DrawerPage/EcoTrackerAppPage.xaml
  59. 215
      samples/ControlCatalog/Pages/GesturePage.cs
  60. 173
      samples/ControlCatalog/Pages/GesturePage.xaml
  61. 59
      samples/ControlCatalog/Pages/Gestures/GesturePinchRotationPage.xaml
  62. 33
      samples/ControlCatalog/Pages/Gestures/GesturePinchRotationPage.xaml.cs
  63. 51
      samples/ControlCatalog/Pages/Gestures/GesturePinchZoomPage.xaml
  64. 134
      samples/ControlCatalog/Pages/Gestures/GesturePinchZoomPage.xaml.cs
  65. 113
      samples/ControlCatalog/Pages/Gestures/GesturePullPage.xaml
  66. 100
      samples/ControlCatalog/Pages/Gestures/GesturePullPage.xaml.cs
  67. 123
      samples/ControlCatalog/Pages/Gestures/GestureSwipePage.xaml
  68. 125
      samples/ControlCatalog/Pages/Gestures/GestureSwipePage.xaml.cs
  69. 51
      samples/ControlCatalog/Pages/NavigationPage/LAvenirAppPage.xaml.cs
  70. 16
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageToolbarPage.xaml.cs
  71. 6
      samples/ControlCatalog/Pages/NavigationPage/PulseAppPage.xaml.cs
  72. 43
      samples/ControlCatalog/Pages/NavigationPage/RetroGamingAppPage.xaml.cs
  73. 26
      samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml
  74. 11
      samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml.cs
  75. 11
      samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonsPage.xaml.cs
  76. 6
      samples/ControlCatalog/Pages/PipsPagerPage.xaml.cs
  77. 68
      samples/SampleControls/HamburgerMenu/HamburgerMenu.cs
  78. 17
      samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml
  79. 21
      src/Android/Avalonia.Android/AndroidDispatcherImpl.cs
  80. 17
      src/Android/Avalonia.Android/AvaloniaAccessHelper.cs
  81. 16
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  82. 25
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  83. 60
      src/Avalonia.Base/Animation/Animation.cs
  84. 59
      src/Avalonia.Base/Animation/AnimationInstance`1.cs
  85. 9
      src/Avalonia.Base/Animation/Animators/Animator`1.cs
  86. 6
      src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs
  87. 9
      src/Avalonia.Base/Animation/Animators/TransformAnimator.cs
  88. 24
      src/Avalonia.Base/Animation/DisposeAnimationInstanceSubject.cs
  89. 3
      src/Avalonia.Base/Animation/IAnimation.cs
  90. 5
      src/Avalonia.Base/Animation/IAnimator.cs
  91. 29
      src/Avalonia.Base/Animation/PlaybackBehavior.cs
  92. 21
      src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs
  93. 2
      src/Avalonia.Base/Input/DragDrop.cs
  94. 4
      src/Avalonia.Base/Input/DragEventArgs.cs
  95. 2
      src/Avalonia.Base/Input/FocusChangedEventArgs.cs
  96. 2
      src/Avalonia.Base/Input/FocusChangingEventArgs.cs
  97. 64
      src/Avalonia.Base/Input/FocusManager.cs
  98. 22
      src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs
  99. 24
      src/Avalonia.Base/Input/GestureRecognizers/VelocityTracker.cs
  100. 4
      src/Avalonia.Base/Input/IFocusManager.cs

2
.github/PULL_REQUEST_TEMPLATE.md

@ -26,7 +26,7 @@
<!--- List any breaking changes here. -->
## Obsoletions / Deprecations
<!--- Obsolete and Deprecated attributes on APIs MUST only be included when discussed with Core team. @grokys, @kekekeks & @danwalmsley -->
<!--- Obsolete and Deprecated attributes on APIs MUST only be included when discussed with Core team. @grokys, @kekekeks & @MrJul -->
## Fixed issues
<!--- If the pull request fixes issue(s) list them like this:

3
.github/copilot-instructions.md

@ -0,0 +1,3 @@
When running code review, please refer to the following documents if they are relevant to the changed parts of the codebase:
- `native/Avalonia.Native/**` -> `native/Avalonia.Native/README.md`

4
.github/workflows/update-api.yml

@ -59,7 +59,9 @@ jobs:
repo: context.repo.repo,
pull_number: context.issue.number,
});
if (pr.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`) {
const isFork = pr.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`;
const isTrustedOverride = context.payload.comment.body.includes('/trusted');
if (isFork && !isTrustedOverride) {
core.setFailed('Cannot run /update-api on fork PRs — would execute untrusted code with write permissions.');
return;
}

2
Avalonia.Desktop.slnf

@ -1,6 +1,6 @@
{
"solution": {
"path": "Avalonia.sln",
"path": "Avalonia.slnx",
"projects": [
"packages\\Avalonia\\Avalonia.csproj",
"samples\\AppWithoutLifetime\\AppWithoutLifetime.csproj",

764
Avalonia.sln

@ -1,764 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A8919-9F95-48FE-AD7B-76E08B509888}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Simple", "src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.UnitTests", "tests\Avalonia.Controls.UnitTests\Avalonia.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base.UnitTests", "tests\Avalonia.Base.UnitTests\Avalonia.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml", "src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj", "{3E53A01A-B331-47F3-B828-4A5717E77A24}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9B9E3891-2366-4253-A952-D08BCEB71098}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\Shared\CallerArgumentExpressionAttribute.cs = src\Shared\CallerArgumentExpressionAttribute.cs
src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
src\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs
src\Shared\StreamCompatibilityExtensions.cs = src\Shared\StreamCompatibilityExtensions.cs
src\Shared\StringCompatibilityExtensions.cs = src\Shared\StringCompatibilityExtensions.cs
EndProjectSection
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("{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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LeakTests", "tests\Avalonia.LeakTests\Avalonia.LeakTests.csproj", "{E1AA3DBF-9056-4530-9376-18119A7A3FFE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.UnitTests", "tests\Avalonia.UnitTests\Avalonia.UnitTests.csproj", "{88060192-33D5-4932-B0F9-8BD2763E857D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Benchmarks", "tests\Avalonia.Benchmarks\Avalonia.Benchmarks.csproj", "{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport", "src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj", "{799A7BB5-3C2C-48B6-85A7-406A12C420DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D0A739B9-3C68-4BA6-A328-41606954B6BD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.TestApp", "tests\Avalonia.DesignerSupport.TestApp\Avalonia.DesignerSupport.TestApp.csproj", "{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VirtualizationDemo", "samples\VirtualizationDemo\VirtualizationDemo.csproj", "{FBCAF3D0-2808-4934-8E96-3F607594517B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{A0CC0258-D18C-4AB3-854F-7101680FC3F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderDemo", "samples\RenderDemo\RenderDemo.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
EndProject
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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject
build\AnalyzerProject.targets = build\AnalyzerProject.targets
build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props
build\Base.props = build\Base.props
build\CoreLibraries.props = build\CoreLibraries.props
build\DevAnalyzers.props = build\DevAnalyzers.props
build\EmbedXaml.props = build\EmbedXaml.props
build\HarfBuzzSharp.props = build\HarfBuzzSharp.props
build\NetAnalyzers.props = build\NetAnalyzers.props
build\NullableEnable.props = build\NullableEnable.props
build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
build\SampleApp.props = build\SampleApp.props
build\SharedVersion.props = build\SharedVersion.props
build\SkiaSharp.props = build\SkiaSharp.props
build\SourceGenerators.props = build\SourceGenerators.props
build\SourceLink.props = build\SourceLink.props
build\TargetFrameworks.props = build\TargetFrameworks.props
build\TrimmingEnable.props = build\TrimmingEnable.props
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\XUnit.props = build\XUnit.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
ProjectSection(SolutionItems) = preProject
build\BuildTargets.targets = build\BuildTargets.targets
build\DevSingleProject.targets = build\DevSingleProject.targets
build\UnitTests.NetCore.targets = build\UnitTests.NetCore.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interoperability", "src\Windows\Avalonia.Win32.Interoperability\Avalonia.Win32.Interoperability.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Remote.Protocol", "src\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj", "{D78A720C-C0C6-478B-8564-F167F9BDD01B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{4ED8B739-6F4E-4CD4-B993-545E6B5CE637}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp", "src\tools\Avalonia.Designer.HostApp\Avalonia.Designer.HostApp.csproj", "{050CC912-FF49-4A8B-B534-9544017446DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{E870DCD7-F46A-498D-83FC-D0FD13E0A11C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia", "packages\Avalonia\Avalonia.csproj", "{D49233F8-F29C-47DD-9975-C4C9E4502720}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Avalonia.Desktop\Avalonia.Desktop.csproj", "{3C471044-3640-45E3-B1B2-16D2FF8399EE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Build.Tasks", "src\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj", "{BF28998D-072C-439A-AFBB-2FE5021241E0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "nukebuild\_build.csproj", "{3F00BC43-5095-477F-93D8-E65B08179A00}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{41B02319-965D-4945-8005-C1A3D1224165}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Avalonia.Dialogs\Avalonia.Dialogs.csproj", "{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Fluent", "src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj", "{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Headless\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.Vnc", "src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj", "{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.Loader", "src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj", "{909A8CBD-7D0E-42FD-B841-022AD8925820}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox", "samples\Sandbox\Sandbox.csproj", "{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestApp", "samples\IntegrationTestApp\IntegrationTestApp.csproj", "{676D6BFD-029D-4E43-BFC7-3892265CE251}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextTestApp", "samples\TextTestApp\TextTestApp.csproj", "{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.IntegrationTests.Appium", "tests\Avalonia.IntegrationTests.Appium\Avalonia.IntegrationTests.Appium.csproj", "{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Browser", "Browser", "{86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ColorPicker", "src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj", "{7BF6C69D-FC14-43EB-9ED0-782C16F3D5D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{EABE2161-989B-42BF-BD8D-1E34B20C21F1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevGenerators", "src\tools\DevGenerators\DevGenerators.csproj", "{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SingleProjectSandbox", "samples\SingleProjectSandbox\SingleProjectSandbox.csproj", "{3B8519C1-2F51-4F12-A348-120AB91D4532}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers.CSharp", "src\tools\Avalonia.Analyzers.CSharp\Avalonia.Analyzers.CSharp.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
azure-pipelines-integrationtests.yml = azure-pipelines-integrationtests.yml
azure-pipelines.yml = azure-pipelines.yml
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
CONTRIBUTING.md = CONTRIBUTING.md
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
dirs.proj = dirs.proj
global.json = global.json
licence.md = licence.md
NOTICE.md = NOTICE.md
NuGet.Config = NuGet.Config
readme.md = readme.md
Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppWithoutLifetime", "samples\AppWithoutLifetime\AppWithoutLifetime.csproj", "{F8928267-688E-4A51-989C-612A72446D33}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Desktop", "samples\SafeAreaDemo.Desktop\SafeAreaDemo.Desktop.csproj", "{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples\SafeAreaDemo.iOS\SafeAreaDemo.iOS.csproj", "{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.NUnit", "src\Headless\Avalonia.Headless.NUnit\Avalonia.Headless.NUnit.csproj", "{ED976634-B118-43F8-8B26-0279C7A7044F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Metal", "src\Avalonia.Metal\Avalonia.Metal.csproj", "{60B4ED1F-ECFA-453B-8A70-1788261C8355}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Build.Tasks.UnitTest", "tests\Avalonia.Build.Tasks.UnitTest\Avalonia.Build.Tasks.UnitTest.csproj", "{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestFiles", "TestFiles", "{9D6AEF22-221F-4F4B-B335-A4BA510F002C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildTasks", "BuildTasks", "{5BF0C3B8-E595-4940-AB30-2DA206C2F085}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PInvoke", "tests\TestFiles\BuildTasks\PInvoke\PInvoke.csproj", "{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnloadableAssemblyLoadContext", "UnloadableAssemblyLoadContext", "{9CCA131B-DE95-4D44-8788-C3CAE28574CD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnloadableAssemblyLoadContext", "samples\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContext.csproj", "{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnloadableAssemblyLoadContextPlug", "samples\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContextPlug\UnloadableAssemblyLoadContextPlug.csproj", "{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Vulkan", "src\Avalonia.Vulkan\Avalonia.Vulkan.csproj", "{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.RenderTests.WpfCompare", "tests\Avalonia.RenderTests.WpfCompare\Avalonia.RenderTests.WpfCompare.csproj", "{9AE1B827-21AC-4063-AB22-C8804B7F931E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Automation", "src\Windows\Avalonia.Win32.Automation\Avalonia.Win32.Automation.csproj", "{0097673D-DBCE-476E-82FE-E78A56E58AA2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XEmbedSample", "samples\XEmbedSample\XEmbedSample.csproj", "{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.MacCatalyst", "samples\ControlCatalog.MacCatalyst\ControlCatalog.MacCatalyst.csproj", "{DE3C28DD-B602-4750-831D-345102A54CA0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.tvOS", "samples\ControlCatalog.tvOS\ControlCatalog.tvOS.csproj", "{14342787-B4EF-4076-8C91-BA6C523DE8DF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HarfBuzz", "HarfBuzz", "{7670D720-6E84-4AFC-8331-A5C399481905}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.HarfBuzz", "src\HarfBuzz\Avalonia.HarfBuzz\Avalonia.HarfBuzz.csproj", "{E2BFA463-6402-4EF8-8945-FD9A10A914D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit.PerAssembly.UnitTests", "tests\Avalonia.Headless.NUnit.PerAssembly.UnitTests\Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj", "{A175EFAE-476C-4DAA-87D5-742C18CFCC27}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit.PerTest.UnitTests", "tests\Avalonia.Headless.NUnit.PerTest.UnitTests\Avalonia.Headless.NUnit.PerTest.UnitTests.csproj", "{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit.PerAssembly.UnitTests", "tests\Avalonia.Headless.XUnit.PerAssembly.UnitTests\Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj", "{342D2657-2F84-493C-B74B-9D2CAE5D9DAB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit.PerTest.UnitTests", "tests\Avalonia.Headless.XUnit.PerTest.UnitTests\Avalonia.Headless.XUnit.PerTest.UnitTests.csproj", "{26918642-829D-4FA2-B60A-BE8D83F4E063}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.IntegrationTests.Win32", "tests\Avalonia.IntegrationTests.Win32\Avalonia.IntegrationTests.Win32.csproj", "{11522B0D-BF31-42D5-8FC5-41E58F319AF9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Analyzers.CodeFixes.CSharp", "src\tools\Avalonia.Analyzers.CodeFixes.CSharp\Avalonia.Analyzers.CodeFixes.CSharp.csproj", "{FDFB9C25-552D-420B-9D4A-DB0BB6472239}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Analyzers.VisualBasic", "src\tools\Avalonia.Analyzers.VisualBasic\Avalonia.Analyzers.VisualBasic.csproj", "{A7644C3B-B843-44F1-9940-560D56CB0936}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.FreeDesktop.AtSpi", "src\Avalonia.FreeDesktop.AtSpi\Avalonia.FreeDesktop.AtSpi.csproj", "{742C3613-514C-4D6B-804A-2A7925F278F3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DBus.Generators", "src\tools\Avalonia.DBus.Generators\Avalonia.DBus.Generators.csproj", "{98A16FFD-0C99-4665-AC64-DC17E86879A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.Build.0 = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.Build.0 = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.Build.0 = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.Build.0 = Release|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.Build.0 = Release|Any CPU
{8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.Build.0 = Release|Any CPU
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.Build.0 = Release|Any CPU
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.Build.0 = Release|Any CPU
{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.Build.0 = Release|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.Build.0 = Release|Any CPU
{D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.Build.0 = Release|Any CPU
{2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.Build.0 = Release|Any CPU
{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|Any CPU.Build.0 = Release|Any CPU
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|Any CPU.Build.0 = Release|Any CPU
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|Any CPU.Build.0 = Release|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.Build.0 = Release|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.Deploy.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.Build.0 = Release|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.Build.0 = Release|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.Build.0 = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|Any CPU.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.Build.0 = Release|Any CPU
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|Any CPU.Build.0 = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.Build.0 = Release|Any CPU
{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.Build.0 = Release|Any CPU
{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|Any CPU.Build.0 = Release|Any CPU
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|Any CPU.Build.0 = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.Build.0 = Release|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.Build.0 = Release|Any CPU
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.Build.0 = Release|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|Any CPU.Build.0 = Release|Any CPU
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|Any CPU.Build.0 = Release|Any CPU
{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|Any CPU.Build.0 = Release|Any CPU
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|Any CPU.Build.0 = Release|Any CPU
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|Any CPU.Build.0 = Release|Any CPU
{909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|Any CPU.Build.0 = Debug|Any CPU
{909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|Any CPU.ActiveCfg = Release|Any CPU
{909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|Any CPU.Build.0 = Release|Any CPU
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|Any CPU.Build.0 = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|Any CPU.Build.0 = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.Build.0 = Release|Any CPU
{676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|Any CPU.Build.0 = Debug|Any CPU
{676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|Any CPU.ActiveCfg = Release|Any CPU
{676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|Any CPU.Build.0 = Release|Any CPU
{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Release|Any CPU.Build.0 = Release|Any CPU
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.Build.0 = Release|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.Build.0 = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|Any CPU.Build.0 = Release|Any CPU
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|Any CPU.Build.0 = Release|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|Any CPU.Build.0 = Release|Any CPU
{7BF6C69D-FC14-43EB-9ED0-782C16F3D5D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BF6C69D-FC14-43EB-9ED0-782C16F3D5D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BF6C69D-FC14-43EB-9ED0-782C16F3D5D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BF6C69D-FC14-43EB-9ED0-782C16F3D5D9}.Release|Any CPU.Build.0 = Release|Any CPU
{EABE2161-989B-42BF-BD8D-1E34B20C21F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EABE2161-989B-42BF-BD8D-1E34B20C21F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EABE2161-989B-42BF-BD8D-1E34B20C21F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EABE2161-989B-42BF-BD8D-1E34B20C21F1}.Release|Any CPU.Build.0 = Release|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.Build.0 = Release|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Release|Any CPU.Build.0 = Release|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.Build.0 = Release|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.Build.0 = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.Build.0 = Release|Any CPU
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.Build.0 = Release|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.Build.0 = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.Build.0 = Release|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.Release|Any CPU.Build.0 = Release|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.Build.0 = Release|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Deploy.0 = Release|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.Build.0 = Release|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Build.0 = Release|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.0 = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Release|Any CPU.Build.0 = Release|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Release|Any CPU.Build.0 = Release|Any CPU
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Release|Any CPU.Build.0 = Release|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Release|Any CPU.Build.0 = Release|Any CPU
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Release|Any CPU.Build.0 = Release|Any CPU
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Release|Any CPU.Build.0 = Release|Any CPU
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Release|Any CPU.Build.0 = Release|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Release|Any CPU.Build.0 = Release|Any CPU
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.Build.0 = Release|Any CPU
{0097673D-DBCE-476E-82FE-E78A56E58AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0097673D-DBCE-476E-82FE-E78A56E58AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0097673D-DBCE-476E-82FE-E78A56E58AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0097673D-DBCE-476E-82FE-E78A56E58AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Release|Any CPU.Build.0 = Release|Any CPU
{DE3C28DD-B602-4750-831D-345102A54CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE3C28DD-B602-4750-831D-345102A54CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE3C28DD-B602-4750-831D-345102A54CA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE3C28DD-B602-4750-831D-345102A54CA0}.Release|Any CPU.Build.0 = Release|Any CPU
{14342787-B4EF-4076-8C91-BA6C523DE8DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14342787-B4EF-4076-8C91-BA6C523DE8DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14342787-B4EF-4076-8C91-BA6C523DE8DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14342787-B4EF-4076-8C91-BA6C523DE8DF}.Release|Any CPU.Build.0 = Release|Any CPU
{E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Release|Any CPU.Build.0 = Release|Any CPU
{A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Release|Any CPU.Build.0 = Release|Any CPU
{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Release|Any CPU.Build.0 = Release|Any CPU
{342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Release|Any CPU.Build.0 = Release|Any CPU
{26918642-829D-4FA2-B60A-BE8D83F4E063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26918642-829D-4FA2-B60A-BE8D83F4E063}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26918642-829D-4FA2-B60A-BE8D83F4E063}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26918642-829D-4FA2-B60A-BE8D83F4E063}.Release|Any CPU.Build.0 = Release|Any CPU
{11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Release|Any CPU.Build.0 = Release|Any CPU
{FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Debug|Any CPU.Build.0 = Release|Any CPU
{FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Release|Any CPU.Build.0 = Release|Any CPU
{A7644C3B-B843-44F1-9940-560D56CB0936}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{A7644C3B-B843-44F1-9940-560D56CB0936}.Debug|Any CPU.Build.0 = Release|Any CPU
{A7644C3B-B843-44F1-9940-560D56CB0936}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7644C3B-B843-44F1-9940-560D56CB0936}.Release|Any CPU.Build.0 = Release|Any CPU
{742C3613-514C-4D6B-804A-2A7925F278F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{742C3613-514C-4D6B-804A-2A7925F278F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{742C3613-514C-4D6B-804A-2A7925F278F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{742C3613-514C-4D6B-804A-2A7925F278F3}.Release|Any CPU.Build.0 = Release|Any CPU
{98A16FFD-0C99-4665-AC64-DC17E86879A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98A16FFD-0C99-4665-AC64-DC17E86879A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98A16FFD-0C99-4665-AC64-DC17E86879A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98A16FFD-0C99-4665-AC64-DC17E86879A2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{2905FF23-53FB-45E6-AA49-6AF47A172056} = {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}
{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}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}
{E1AA3DBF-9056-4530-9376-18119A7A3FFE} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{88060192-33D5-4932-B0F9-8BD2763E857D} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{D0A739B9-3C68-4BA6-A328-41606954B6BD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{2B888490-D14A-4BCA-AB4B-48676FA93C9B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F1381F98-4D24-409A-A6C5-1C5B1E08BB08} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{FBCAF3D0-2808-4934-8E96-3F607594517B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{A0CC0258-D18C-4AB3-854F-7101680FC3F9} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{050CC912-FF49-4A8B-B534-9544017446DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{E1240B49-7B4B-4371-A00E-068778C5CF0B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{D49233F8-F29C-47DD-9975-C4C9E4502720} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
{3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{676D6BFD-029D-4E43-BFC7-3892265CE251} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{EABE2161-989B-42BF-BD8D-1E34B20C21F1} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{3B8519C1-2F51-4F12-A348-120AB91D4532} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4A39637C-9338-4925-A4DB-D072E292EC78} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{15B93A4C-1B46-43F6-B534-7B25B6E99932} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F8928267-688E-4A51-989C-612A72446D33} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
{ED976634-B118-43F8-8B26-0279C7A7044F} = {FF237916-7150-496B-89ED-6CA3292896E7}
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{9D6AEF22-221F-4F4B-B335-A4BA510F002C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{5BF0C3B8-E595-4940-AB30-2DA206C2F085} = {9D6AEF22-221F-4F4B-B335-A4BA510F002C}
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4} = {5BF0C3B8-E595-4940-AB30-2DA206C2F085}
{9CCA131B-DE95-4D44-8788-C3CAE28574CD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD}
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD}
{9AE1B827-21AC-4063-AB22-C8804B7F931E} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{0097673D-DBCE-476E-82FE-E78A56E58AA2} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{DE3C28DD-B602-4750-831D-345102A54CA0} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{14342787-B4EF-4076-8C91-BA6C523DE8DF} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{E2BFA463-6402-4EF8-8945-FD9A10A914D1} = {7670D720-6E84-4AFC-8331-A5C399481905}
{A175EFAE-476C-4DAA-87D5-742C18CFCC27} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{342D2657-2F84-493C-B74B-9D2CAE5D9DAB} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{26918642-829D-4FA2-B60A-BE8D83F4E063} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{11522B0D-BF31-42D5-8FC5-41E58F319AF9} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{FDFB9C25-552D-420B-9D4A-DB0BB6472239} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{A7644C3B-B843-44F1-9940-560D56CB0936} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{742C3613-514C-4D6B-804A-2A7925F278F3} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{98A16FFD-0C99-4665-AC64-DC17E86879A2} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
EndGlobalSection
EndGlobal

197
Avalonia.slnx

@ -0,0 +1,197 @@
<Solution>
<Folder Name="/Android/">
<Project Path="src/Android/Avalonia.Android/Avalonia.Android.csproj" />
</Folder>
<Folder Name="/Browser/">
<Project Path="src/Browser/Avalonia.Browser/Avalonia.Browser.csproj" />
</Folder>
<Folder Name="/HarfBuzz/">
<Project Path="src/HarfBuzz/Avalonia.HarfBuzz/Avalonia.HarfBuzz.csproj" />
</Folder>
<Folder Name="/Headless/">
<Project Path="src/Headless/Avalonia.Headless.NUnit/Avalonia.Headless.NUnit.csproj" />
<Project Path="src/Headless/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj" />
<Project Path="src/Headless/Avalonia.Headless.XUnit/Avalonia.Headless.XUnit.csproj" />
<Project Path="src/Headless/Avalonia.Headless/Avalonia.Headless.csproj" />
</Folder>
<Folder Name="/iOS/">
<Project Path="src/iOS/Avalonia.iOS/Avalonia.iOS.csproj" />
</Folder>
<Folder Name="/Linux/">
<Project Path="src/Avalonia.FreeDesktop.AtSpi/Avalonia.FreeDesktop.AtSpi.csproj" />
<Project Path="src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj" />
<Project Path="src/Avalonia.X11/Avalonia.X11.csproj" />
<Project Path="src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj" />
</Folder>
<Folder Name="/Markup/">
<Project Path="src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj" />
<Project Path="src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
<Project Path="src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" />
</Folder>
<Folder Name="/Packages/">
<Project Path="packages/Avalonia/Avalonia.csproj" />
<Project Path="src/Avalonia.Desktop/Avalonia.Desktop.csproj" />
</Folder>
<Folder Name="/Props/">
<File Path="build/AvaloniaPublicKey.props" />
<File Path="build/Base.props" />
<File Path="build/CoreLibraries.props" />
<File Path="build/DevAnalyzers.props" />
<File Path="build/EmbedXaml.props" />
<File Path="build/HarfBuzzSharp.props" />
<File Path="build/MicroCOM.props" />
<File Path="build/NetAnalyzers.props" />
<File Path="build/NullableEnable.props" />
<File Path="build/ReferenceCoreLibraries.props" />
<File Path="build/SampleApp.props" />
<File Path="build/SharedVersion.props" />
<File Path="build/SkiaSharp.props" />
<File Path="build/SourceGenerators.props" />
<File Path="build/SourceLink.props" />
<File Path="build/TargetFrameworks.props" />
<File Path="build/TrimmingEnable.props" />
<File Path="build/UnitTests.NetFX.props" />
<File Path="build/XUnit.props" />
</Folder>
<Folder Name="/Samples/">
<Project Path="samples/AppWithoutLifetime/AppWithoutLifetime.csproj" />
<Project Path="samples/BindingDemo/BindingDemo.csproj" />
<Project Path="samples/ControlCatalog.Android/ControlCatalog.Android.csproj">
<Deploy />
</Project>
<Project Path="samples/ControlCatalog.Browser/ControlCatalog.Browser.csproj" />
<Project Path="samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj" />
<Project Path="samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj" />
<Project Path="samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj" />
<Project Path="samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj" />
<Project Path="samples/ControlCatalog/ControlCatalog.csproj" />
<Project Path="samples/Generators.Sandbox/Generators.Sandbox.csproj" />
<Project Path="samples/GpuInterop/GpuInterop.csproj" />
<Project Path="samples/IntegrationTestApp/IntegrationTestApp.csproj" />
<Project Path="samples/MiniMvvm/MiniMvvm.csproj" />
<Project Path="samples/PlatformSanityChecks/PlatformSanityChecks.csproj" />
<Project Path="samples/RenderDemo/RenderDemo.csproj" />
<Project Path="samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj">
<Deploy />
</Project>
<Project Path="samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj" />
<Project Path="samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj">
<Deploy />
</Project>
<Project Path="samples/SafeAreaDemo/SafeAreaDemo.csproj" />
<Project Path="samples/SampleControls/ControlSamples.csproj" />
<Project Path="samples/Sandbox/Sandbox.csproj" />
<Project Path="samples/SingleProjectSandbox/SingleProjectSandbox.csproj" />
<Project Path="samples/TextTestApp/TextTestApp.csproj" />
<Project Path="samples/VirtualizationDemo/VirtualizationDemo.csproj" />
<Project Path="samples/XEmbedSample/XEmbedSample.csproj" />
</Folder>
<Folder Name="/Samples/Interop/">
<Project Path="samples/interop/WindowsInteropTest/WindowsInteropTest.csproj" />
</Folder>
<Folder Name="/Samples/UnloadableAssemblyLoadContext/">
<Project Path="samples/UnloadableAssemblyLoadContext/UnloadableAssemblyLoadContext/UnloadableAssemblyLoadContext.csproj" />
<Project Path="samples/UnloadableAssemblyLoadContext/UnloadableAssemblyLoadContextPlug/UnloadableAssemblyLoadContextPlug.csproj" />
</Folder>
<Folder Name="/Shared/">
<File Path=".editorconfig" />
<File Path="src/Shared/CallerArgumentExpressionAttribute.cs" />
<File Path="src/Shared/IsExternalInit.cs" />
<File Path="src/Shared/ModuleInitializer.cs" />
<File Path="src/Shared/SourceGeneratorAttributes.cs" />
<File Path="src/Shared/StreamCompatibilityExtensions.cs" />
<File Path="src/Shared/StringCompatibilityExtensions.cs" />
</Folder>
<Folder Name="/Skia/">
<Project Path="src/Skia/Avalonia.Skia/Avalonia.Skia.csproj" />
</Folder>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path="azure-pipelines-integrationtests.yml" />
<File Path="azure-pipelines.yml" />
<File Path="CODE_OF_CONDUCT.md" />
<File Path="CONTRIBUTING.md" />
<File Path="Directory.Build.props" />
<File Path="Directory.Build.targets" />
<File Path="Directory.Packages.props" />
<File Path="dirs.proj" />
<File Path="global.json" />
<File Path="licence.md" />
<File Path="NOTICE.md" />
<File Path="NuGet.Config" />
<File Path="readme.md" />
</Folder>
<Folder Name="/Targets/">
<File Path="build/AnalyzerProject.targets" />
<File Path="build/BuildTargets.targets" />
<File Path="build/DevSingleProject.targets" />
<File Path="build/UnitTests.NetCore.targets" />
</Folder>
<Folder Name="/Tests/">
<Project Path="tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj" />
<Project Path="tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj" />
<Project Path="tests/Avalonia.Build.Tasks.UnitTest/Avalonia.Build.Tasks.UnitTest.csproj" />
<Project Path="tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj" />
<Project Path="tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj" />
<Project Path="tests/Avalonia.DesignerSupport.Tests/Avalonia.DesignerSupport.Tests.csproj" />
<Project Path="tests/Avalonia.Generators.Tests/Avalonia.Generators.Tests.csproj" />
<Project Path="tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj" />
<Project Path="tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj" />
<Project Path="tests/Avalonia.Headless.XUnit.PerAssembly.UnitTests/Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj" />
<Project Path="tests/Avalonia.Headless.XUnit.PerTest.UnitTests/Avalonia.Headless.XUnit.PerTest.UnitTests.csproj" />
<Project Path="tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj" />
<Project Path="tests/Avalonia.IntegrationTests.Win32/Avalonia.IntegrationTests.Win32.csproj" />
<Project Path="tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj" />
<Project Path="tests/Avalonia.Markup.UnitTests/Avalonia.Markup.UnitTests.csproj" />
<Project Path="tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj" />
<Project Path="tests/Avalonia.RenderTests.WpfCompare/Avalonia.RenderTests.WpfCompare.csproj" />
<Project Path="tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj" />
<Project Path="tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj" />
<Project Path="tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj" />
</Folder>
<Folder Name="/Tests/TestFiles/" />
<Folder Name="/Tests/TestFiles/BuildTasks/">
<Project Path="tests/TestFiles/BuildTasks/PInvoke/PInvoke.csproj" />
</Folder>
<Folder Name="/Themes/">
<Project Path="src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj" />
<Project Path="src/Avalonia.Themes.Simple/Avalonia.Themes.Simple.csproj" />
</Folder>
<Folder Name="/Tools/">
<Project Path="src/tools/Avalonia.Analyzers.CodeFixes.CSharp/Avalonia.Analyzers.CodeFixes.CSharp.csproj">
<BuildType Project="Release" />
</Project>
<Project Path="src/tools/Avalonia.Analyzers.CSharp/Avalonia.Analyzers.CSharp.csproj">
<BuildType Project="Release" />
</Project>
<Project Path="src/tools/Avalonia.Analyzers.VisualBasic/Avalonia.Analyzers.VisualBasic.csproj">
<BuildType Project="Release" />
</Project>
<Project Path="src/tools/Avalonia.DBus.Generators/Avalonia.DBus.Generators.csproj" />
<Project Path="src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj" />
<Project Path="src/tools/Avalonia.Generators/Avalonia.Generators.csproj" />
<Project Path="src/tools/DevAnalyzers/DevAnalyzers.csproj" />
<Project Path="src/tools/DevGenerators/DevGenerators.csproj" />
</Folder>
<Folder Name="/Windows/">
<Project Path="src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj" />
<Project Path="src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj" />
<Project Path="src/Windows/Avalonia.Win32/Avalonia.Win32.csproj" />
</Folder>
<Project Path="nukebuild/_build.csproj">
<Build Project="false" />
</Project>
<Project Path="src/Avalonia.Base/Avalonia.Base.csproj" />
<Project Path="src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" />
<Project Path="src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj" />
<Project Path="src/Avalonia.Controls/Avalonia.Controls.csproj" />
<Project Path="src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj" />
<Project Path="src/Avalonia.Dialogs/Avalonia.Dialogs.csproj" />
<Project Path="src/Avalonia.Fonts.Inter/Avalonia.Fonts.Inter.csproj" />
<Project Path="src/Avalonia.Metal/Avalonia.Metal.csproj" />
<Project Path="src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" />
<Project Path="src/Avalonia.Native/Avalonia.Native.csproj" />
<Project Path="src/Avalonia.OpenGL/Avalonia.OpenGL.csproj" />
<Project Path="src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<Project Path="src/Avalonia.Vulkan/Avalonia.Vulkan.csproj" />
</Solution>

0
Avalonia.sln.DotSettings → Avalonia.slnx.DotSettings

22
Directory.Packages.props

@ -7,7 +7,7 @@
<PackageVersion Include="Appium.WebDriver" Version="5.2.0" />
<PackageVersion Include="Avalonia.Angle.Windows.Natives" Version="2.1.25547.20250602" />
<PackageVersion Include="Avalonia.BuildServices" Version="11.3.2" />
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.0-beta2" />
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.0-beta3" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.6" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="Dotnet.Bundle" Version="0.9.13" />
@ -15,9 +15,9 @@
<PackageVersion Include="HarfBuzzSharp" Version="8.3.1.3" />
<PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="8.3.1.3" />
<PackageVersion Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="8.3.1.3" />
<PackageVersion Include="MicroCom.CodeGenerator" Version="0.11.0" />
<PackageVersion Include="MicroCom.CodeGenerator.MSBuild" Version="0.11.0" />
<PackageVersion Include="MicroCom.Runtime" Version="0.11.0" />
<PackageVersion Include="MicroCom.CodeGenerator" Version="0.11.4" />
<PackageVersion Include="MicroCom.CodeGenerator.MSBuild" Version="0.11.4" />
<PackageVersion Include="MicroCom.Runtime" Version="0.11.4" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
<PackageVersion Include="Microsoft.Build.Framework" Version="18.0.2" />
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="15.1.548" />
@ -37,8 +37,8 @@
<PackageVersion Include="NuGet.Protocol" Version="7.0.1" />
<PackageVersion Include="Nuke.Common" Version="10.1.0" />
<PackageVersion Include="Numerge" Version="1.0.0" />
<PackageVersion Include="NUnit" Version="4.4.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageVersion Include="NUnit" Version="4.5.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageVersion Include="Quamotion.RemoteViewing" Version="1.1.211" />
<PackageVersion Include="SharpCompress" Version="0.41.0" />
<PackageVersion Include="Silk.NET.Direct3D.Compilers" Version="2.22.0" />
@ -62,13 +62,13 @@
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="Tmds.DBus.Protocol" Version="0.90.3" />
<PackageVersion Include="Tmds.DBus.SourceGenerator" Version="0.0.22" />
<PackageVersion Include="Xamarin.AndroidX.AppCompat" Version="1.7.1.1" />
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.2.0" />
<PackageVersion Include="Xamarin.AndroidX.Window" Version="1.5.1" />
<PackageVersion Include="Xamarin.AndroidX.AppCompat" Version="1.7.1.3" />
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.2.0.2" />
<PackageVersion Include="Xamarin.AndroidX.Window" Version="1.5.1.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Xunit.StaFact" Version="3.0.13" />
<PackageVersion Include="xunit.v3.extensibility.core" Version="3.2.1" />
<PackageVersion Include="xunit.v3.mtp-v2" Version="3.2.1" />
<PackageVersion Include="xunit.v3.extensibility.core" Version="3.2.2" />
<PackageVersion Include="xunit.v3.mtp-v2" Version="3.2.2" />
</ItemGroup>
<ItemGroup>

11
SECURITY.md

@ -0,0 +1,11 @@
# Security Policy
## Reporting a Vulnerability
If you discover a security vulnerability in any of our SDKs, tools, services, or repositories, please help us keep the community safe by reporting it responsibly.
You can report security vulnerabilities by emailing **[security@avaloniaui.net](mailto:security@avaloniaui.net)**.
Please avoid disclosing the issue publicly until we have had a reasonable amount of time to investigate and release a patch or mitigation. We review all legitimate reports and will work with you to quickly resolve the issue.
Please note that Avalonia does not operate a bug bounty programme.

28
api/Avalonia.Skia.nupkg.xml

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
@ -61,6 +61,18 @@
<Left>baseline/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Skia.ISkiaGpuRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Skia.ISkiaGpuRenderTarget.get_IsReady</Target>
<Left>baseline/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Skia.Helpers.DrawingContextHelper.WrapSkiaCanvas(SkiaSharp.SKCanvas,Avalonia.Vector)</Target>
@ -85,6 +97,18 @@
<Left>baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Skia.ISkiaGpuRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Skia.ISkiaGpuRenderTarget.get_IsReady</Target>
<Left>baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Skia.ISkiaGpu.TryCreateRenderTarget(System.Collections.Generic.IEnumerable{Avalonia.Platform.Surfaces.IPlatformRenderSurface})</Target>
@ -169,4 +193,4 @@
<Left>baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Right>
</Suppression>
</Suppressions>
</Suppressions>

16
api/Avalonia.Win32.nupkg.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Win32.DirectX.IDirect3D11TextureRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia.Win32/lib/net10.0/Avalonia.Win32.dll</Left>
<Right>current/Avalonia.Win32/lib/net10.0/Avalonia.Win32.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Win32.DirectX.IDirect3D11TextureRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia.Win32/lib/net8.0/Avalonia.Win32.dll</Left>
<Right>current/Avalonia.Win32/lib/net8.0/Avalonia.Win32.dll</Right>
</Suppression>
</Suppressions>

252
api/Avalonia.nupkg.xml

@ -247,6 +247,24 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AppBarButton</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AppBarSeparator</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AppBarToggleButton</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetimeOptions</Target>
@ -727,6 +745,24 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AppBarButton</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AppBarSeparator</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AppBarToggleButton</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetimeOptions</Target>
@ -1117,6 +1153,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.DragDrop.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.DragEventArgs.#ctor(Avalonia.Interactivity.RoutedEvent{Avalonia.Input.DragEventArgs},Avalonia.Input.IDataObject,Avalonia.Interactivity.Interactive,Avalonia.Point,Avalonia.Input.KeyModifiers)</Target>
@ -1417,6 +1459,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.Raw.RawDragEvent.#ctor(Avalonia.Input.Raw.IDragDropDevice,Avalonia.Input.Raw.RawDragEventType,Avalonia.Input.IInputRoot,Avalonia.Point,Avalonia.Input.IDataObject,Avalonia.Input.DragDropEffects,Avalonia.Input.RawInputModifiers)</Target>
@ -1693,12 +1741,30 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.get_IsReady</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.LockedFramebuffer.#ctor(System.IntPtr,Avalonia.PixelSize,System.Int32,Avalonia.Vector,Avalonia.Platform.PixelFormat,System.Action)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.Surfaces.IPlatformRenderSurfaceRenderTarget.get_IsReady</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.Composition.ICompositionGpuImportedObject.get_ImportCompeted</Target>
@ -1867,6 +1933,24 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NavigationPage.IsBackButtonEffectivelyVisibleProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.NextButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.PreviousButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Primitives.FlyoutBase.IsOpenProperty</Target>
@ -1939,6 +2023,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Window.WindowStateProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.AppBuilder.get_LifetimeOverride</Target>
@ -2095,12 +2185,42 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NavigationPage.get_IsBackButtonEffectivelyVisible</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PageSelectionChangedEventArgs.#ctor(Avalonia.Controls.Page,Avalonia.Controls.Page)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_NextButtonStyle</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_PreviousButtonStyle</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_NextButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_PreviousButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Platform.DefaultMenuInteractionHandler.GotFocus(System.Object,Avalonia.Input.GotFocusEventArgs)</Target>
@ -2389,6 +2509,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Window.ExtendClientAreaToDecorationsChanged(System.Boolean)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Window.get_ExtendClientAreaChromeHints</Target>
@ -2575,6 +2701,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.OpenGL.Surfaces.IGlPlatformSurfaceRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Vulkan.IVulkanKhrSurfacePlatformSurfaceFactory.CanRenderToSurface(Avalonia.Vulkan.IVulkanPlatformGraphicsContext,System.Object)</Target>
@ -2779,6 +2911,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.DragDrop.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.DragEventArgs.#ctor(Avalonia.Interactivity.RoutedEvent{Avalonia.Input.DragEventArgs},Avalonia.Input.IDataObject,Avalonia.Interactivity.Interactive,Avalonia.Point,Avalonia.Input.KeyModifiers)</Target>
@ -3079,6 +3217,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.Raw.RawDragEvent.#ctor(Avalonia.Input.Raw.IDragDropDevice,Avalonia.Input.Raw.RawDragEventType,Avalonia.Input.IInputRoot,Avalonia.Point,Avalonia.Input.IDataObject,Avalonia.Input.DragDropEffects,Avalonia.Input.RawInputModifiers)</Target>
@ -3355,12 +3499,30 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.get_IsReady</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.LockedFramebuffer.#ctor(System.IntPtr,Avalonia.PixelSize,System.Int32,Avalonia.Vector,Avalonia.Platform.PixelFormat,System.Action)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.Surfaces.IPlatformRenderSurfaceRenderTarget.get_IsReady</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.Composition.ICompositionGpuImportedObject.get_ImportCompeted</Target>
@ -3529,6 +3691,24 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NavigationPage.IsBackButtonEffectivelyVisibleProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.NextButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.PreviousButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Primitives.FlyoutBase.IsOpenProperty</Target>
@ -3601,6 +3781,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Window.WindowStateProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.AppBuilder.get_LifetimeOverride</Target>
@ -3757,12 +3943,42 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NavigationPage.get_IsBackButtonEffectivelyVisible</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PageSelectionChangedEventArgs.#ctor(Avalonia.Controls.Page,Avalonia.Controls.Page)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_NextButtonStyle</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_PreviousButtonStyle</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_NextButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_PreviousButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Platform.DefaultMenuInteractionHandler.GotFocus(System.Object,Avalonia.Input.GotFocusEventArgs)</Target>
@ -4051,6 +4267,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Window.ExtendClientAreaToDecorationsChanged(System.Boolean)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Window.get_ExtendClientAreaChromeHints</Target>
@ -4243,6 +4465,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.OpenGL.Surfaces.IGlPlatformSurfaceRenderTarget.get_IsCorrupted</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Vulkan.IVulkanKhrSurfacePlatformSurfaceFactory.CanRenderToSurface(Avalonia.Vulkan.IVulkanPlatformGraphicsContext,System.Object)</Target>
@ -4399,6 +4627,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerPressedEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.ICursorFactory.CreateCursor(Avalonia.Media.Imaging.Bitmap,Avalonia.PixelPoint)</Target>
@ -4561,6 +4795,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Platform.IWindowImpl.WindowStateGetterIsUsable</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.OpenGL.IGlPlatformSurfaceRenderTargetFactory.CanRenderToSurface(Avalonia.OpenGL.IGlContext,Avalonia.Platform.Surfaces.IPlatformRenderSurface)</Target>
@ -4741,6 +4981,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerPressedEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.ICursorFactory.CreateCursor(Avalonia.Media.Imaging.Bitmap,Avalonia.PixelPoint)</Target>
@ -4915,6 +5161,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Platform.IWindowImpl.WindowStateGetterIsUsable</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)</Target>

26
build/MicroCOM.props

@ -0,0 +1,26 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Uncomment to use local MicroCOM build -->
<!--<UseLocalMicroComBuild>true</UseLocalMicroComBuild>-->
<LocalMicroComPath Condition="'$(LocalMicroComPath)' == ''">$(MSBuildThisFileDirectory)/../../MicroCom</LocalMicroComPath>
</PropertyGroup>
<!-- Local build: delegate to MicroCom's own targets -->
<Import Condition="'$(UseLocalMicroComBuild)' == 'true'"
Project="$(LocalMicroComPath)/UseLocalBuild.targets" />
<!-- NuGet packages: include based on property flags -->
<ItemGroup Condition="'$(UseLocalMicroComBuild)' != 'true'">
<PackageReference Condition="'$(UseMicroCom)' == 'true'"
Include="MicroCom.Runtime" />
<PackageReference Condition="'$(UseMicroComGenerator)' == 'true'"
Include="MicroCom.CodeGenerator" />
<PackageReference Condition="'$(UseMicroComGeneratorMSBuild)' == 'true'"
Include="MicroCom.CodeGenerator.MSBuild"
PrivateAssets="all" />
<PackageReference Condition="'$(UseMicroComGeneratorRoslyn)' == 'true'"
Include="MicroCom.CodeGenerator.Roslyn"
PrivateAssets="all" />
</ItemGroup>
</Project>

2
docs/build.md

@ -42,7 +42,7 @@ dotnet run
If you want to open Avalonia in Visual Studio you have two options:
- Avalonia.sln: This contains the whole of Avalonia in including desktop, mobile and web. You must have a number of dotnet workloads installed in order to build everything in this solution
- Avalonia.slnx: This contains the whole of Avalonia in including desktop, mobile and web. You must have a number of dotnet workloads installed in order to build everything in this solution
- Avalonia.Desktop.slnf: This solution filter opens only the parts of Avalonia required to run on desktop. This requires no extra workloads to be installed.
Avalonia requires Visual Studio 2022 or newer. The free Visual Studio Community edition works fine.

2
external/Avalonia.DBus

@ -1 +1 @@
Subproject commit f91a822c258476f185e51112388775591e6ef9d6
Subproject commit 864a05282841bf04006890f04d11d60d1a046aa9

87
native/Avalonia.Native/README.md

@ -0,0 +1,87 @@
# Avalonia.Native
This project implements the macOS native platform backend for Avalonia using Objective-C++ and COM (Component Object Model) interfaces.
## COM Reference Management
This codebase uses COM for cross-boundary object lifetime management. COM types are typically prefixed with `IAvn` (interfaces) or `Avn` (implementations). All COM objects ultimately derive from `IUnknown` and use reference counting (`AddRef`/`Release`).
**No raw COM pointer should ever be stored in class fields, instance variables, closures, or containers.** Raw COM pointers are only acceptable as function parameters and local variables with the lifetime of the current function call.
### COM Return Value Convention
By convention, any COM interface reference returned from a COM call has its reference counter incremented — it is the caller's responsibility to release it. With the `IFoo* GetFoo()` pattern it is hard to track this correctly, so all methods in `avn.idl` should use the out-parameter pattern instead:
```cpp
// WRONG — easy to leak or forget Release:
IFoo* GetFoo();
// CORRECT — use HRESULT + out-parameter:
HRESULT GetFoo(IFoo** ppv);
```
# Smart pointer types
### Objective-C Objects
For Objective-C objects, reference counting is provided by the compiler. Objective-C pointers _look_ like raw pointers, however every `NSObject*` reference is properly ref-counted by ARC (Automatic Reference Counting). No manual wrapping is needed for `NSObject*` fields.
### COM Smart Pointer Types
All retained COM references must use one of the following wrappers defined in `inc/comimpl.h`:
#### `ComPtr<T>` — Owning Reference
Use for any COM pointer that the holder needs to keep alive.
```cpp
ComPtr<IAvnWindow> _window; // correct
IAvnWindow* _window; // WRONG — raw COM pointer in a field
```
#### `ComObjectWeakPtr<T>` — Non-Owning Weak Reference
Use for intentional non-owning references to `ComObject`-derived objects (internal implementations). Allows safely referencing COM objects without extending their lifetime.
```cpp
ComObjectWeakPtr<WindowBaseImpl> _parent; // correct
WindowBaseImpl* _parent; // WRONG
```
Access weak references with `tryGet()`, which returns a `ComPtr<T>` (null if the object was destroyed):
```cpp
auto parent = _parent.tryGet();
if (parent) {
parent->DoSomething();
}
```
#### `ComStaticPtr<T>` — Process-Lifetime Static Reference
Use for static/global COM singletons that must live for the entire process lifetime. Intentionally does **not** Release in its destructor to avoid crashes during app teardown.
```cpp
static ComStaticPtr<IAvnGlDisplay> GlDisplay; // correct
static IAvnGlDisplay* GlDisplay; // WRONG
```
Assign via `set()`:
```cpp
GlDisplay.set(comnew<AvnGlDisplay>());
```
### `comnew<T>(args...)` — COM Object Factory
A convenience template similar to `std::make_shared`. Creates a new COM object and returns it wrapped in a `ComPtr<T>` with correct ownership (no double-AddRef):
```cpp
// Instead of:
ComPtr<Cursor> cursor(new Cursor(nsCursor), true);
// Write:
ComPtr<Cursor> cursor = comnew<Cursor>(nsCursor);
```
This works because `new T()` on a `ComObject`-derived type starts with refcount=1, and `comnew` wraps it in a `ComPtr` that takes ownership without an additional `AddRef`.

81
native/Avalonia.Native/inc/comimpl.h

@ -8,6 +8,7 @@
#include <cstring>
#include <memory>
#include <utility>
/**
START_COM_CALL causes AddRef to be called at the beginning of a function.
@ -110,6 +111,11 @@ public:
TInterface** getPPV()
{
if(_obj)
{
_obj->Release();
_obj = nullptr;
}
return &_obj;
}
@ -138,6 +144,78 @@ public:
}
};
template<class T, class... Args>
ComPtr<T> comnew(Args&&... args)
{
return ComPtr<T>(new T(std::forward<Args>(args)...), true);
}
/**
* ComStaticPtr is a COM smart pointer for process-lifetime static singletons.
* It AddRef/Release on set/reset, but intentionally does NOT Release in its destructor
* to avoid crashes during app teardown when destruction order is undefined.
*/
template<class TInterface>
class ComStaticPtr
{
private:
TInterface* _obj = nullptr;
public:
ComStaticPtr() = default;
~ComStaticPtr() = default;
ComStaticPtr(const ComPtr<TInterface>& ptr)
{
_obj = ptr;
if (_obj)
_obj->AddRef();
}
ComStaticPtr(const ComStaticPtr&) = delete;
ComStaticPtr(ComStaticPtr&&) = delete;
ComStaticPtr& operator=(const ComStaticPtr&) = delete;
ComStaticPtr& operator=(ComStaticPtr&&) = delete;
void set(TInterface* obj)
{
if (_obj == obj)
return;
if (_obj)
_obj->Release();
_obj = obj;
if (_obj)
_obj->AddRef();
}
void setNoAddRef(TInterface* obj)
{
if (_obj)
_obj->Release();
_obj = obj;
}
void reset()
{
if (_obj)
{
_obj->Release();
_obj = nullptr;
}
}
TInterface* getRaw() const { return _obj; }
template<class TCast> ComPtr<TCast> getComPtr()
{
if (_obj == nullptr)
return nullptr;
return dynamic_cast<TCast*>(_obj);
}
operator TInterface*() const { return _obj; }
TInterface* operator->() const { return _obj; }
};
class ComObjectWeakRefToken
{
public:
@ -249,6 +327,9 @@ public:
_rawPtr = nullptr;
_token = nullptr;
}
bool operator==(const ComObjectWeakPtr& other) const { return _rawPtr == other._rawPtr; }
bool operator!=(const ComObjectWeakPtr& other) const { return _rawPtr != other._rawPtr; }
};
#define FORWARD_IUNKNOWN() \

13
native/Avalonia.Native/src/OSX/AvnString.mm

@ -79,16 +79,14 @@ public:
class AvnStringArrayImpl : public virtual ComSingleObject<IAvnStringArray, &IID_IAvnStringArray>
{
private:
std::vector<ComPtr<IAvnString>> _list;
std::vector<ComPtr<AvnStringImpl>> _list;
public:
FORWARD_IUNKNOWN()
AvnStringArrayImpl(NSArray<NSString*>* array)
{
for(int c = 0; c < [array count]; c++)
{
ComPtr<IAvnString> s;
*s.getPPV() = new AvnStringImpl([array objectAtIndex:c]);
_list.push_back(s);
_list.push_back(comnew<AvnStringImpl>([array objectAtIndex:c]));
}
}
@ -96,17 +94,14 @@ public:
{
for(int c = 0; c < [array count]; c++)
{
ComPtr<IAvnString> s;
*s.getPPV() = new AvnStringImpl([array objectAtIndex:c].absoluteString);
auto s = comnew<AvnStringImpl>([array objectAtIndex:c].absoluteString);
_list.push_back(s);
}
}
AvnStringArrayImpl(NSString* string)
{
ComPtr<IAvnString> s;
*s.getPPV() = new AvnStringImpl(string);
_list.push_back(s);
_list.push_back(comnew<AvnStringImpl>(string));
}
virtual unsigned int GetCount() override

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

@ -37,7 +37,7 @@
bool _isTransitioningToFullScreen;
bool _isTitlebarSession;
AvnMenu* _menu;
IAvnAutomationPeer* _automationPeer;
ComPtr<IAvnAutomationPeer> _automationPeer;
AvnAutomationNode* _automationNode;
}
@ -144,8 +144,6 @@
{
auto appMenu = ::GetAppMenu();
auto nativeAppMenu = dynamic_cast<AvnAppMenu*>(appMenu);
[[appMenuItem menu] removeItem:appMenuItem];
if(_menu != nullptr)
@ -153,9 +151,9 @@
[_menu setHasGlobalMenuItem:false];
}
[nativeAppMenu->GetNative() addItem:appMenuItem];
[appMenu->GetNative() addItem:appMenuItem];
[NSApp setMenu:nativeAppMenu->GetNative()];
[NSApp setMenu:appMenu->GetNative()];
}
}

4
native/Avalonia.Native/src/OSX/TopLevelImpl.mm

@ -311,7 +311,9 @@ HRESULT TopLevelImpl::BeginDragAndDropOperation(
for (auto i = 0; i < itemCount; ++i)
{
auto item = source->GetItem(i);
ComPtr<IAvnClipboardDataItem> item;
if(S_OK != source->GetItem(i, item.getPPV()))
continue;
auto writeableItem = [[WriteableClipboardItem alloc] initWithItem:item source:source];
auto draggingItem = [[NSDraggingItem alloc] initWithPasteboardWriter:writeableItem];
[draggingItem setDraggingFrame:dragItemRect contents:dragItemImage];

2
native/Avalonia.Native/src/OSX/WindowBaseImpl.h

@ -101,7 +101,7 @@ protected:
AutoFitContentView *StandardContainer;
AvnPoint lastPositionSet;
bool _shown;
std::list<WindowBaseImpl*> _children;
std::list<ComObjectWeakPtr<WindowBaseImpl>> _children;
public:
ComObjectWeakPtr<WindowBaseImpl> Parent = nullptr;

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

@ -27,7 +27,7 @@ WindowBaseImpl::~WindowBaseImpl() {
}
WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, bool usePanel) : TopLevelImpl(events) {
_children = std::list<WindowBaseImpl*>();
_children = std::list<ComObjectWeakPtr<WindowBaseImpl>>();
_shown = false;
_inResize = false;
BaseEvents = events;

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

@ -100,11 +100,14 @@ void WindowImpl::ZOrderChildWindows()
{
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
auto window = (*iterator)->Window;
auto child = (*iterator).tryGet();
if (!child) continue;
auto window = child->Window;
// #9565: Only bring window to front if it's on the currently active space
if ([window isOnActiveSpace]) {
(*iterator)->BringToFront();
child->BringToFront();
}
}
}
@ -113,7 +116,8 @@ bool WindowImpl::CanBecomeKeyWindow()
{
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
if((*iterator)->IsModal())
auto child = (*iterator).tryGet();
if(child && child->IsModal())
{
return false;
}

37
native/Avalonia.Native/src/OSX/automation.mm

@ -8,7 +8,7 @@
@implementation AvnAccessibilityElement
{
IAvnAutomationPeer* _peer;
ComPtr<IAvnAutomationPeer> _peer;
AvnAutomationNode* _node;
NSMutableArray* _children;
NSArray<NSString*>* _attributeNames;
@ -70,7 +70,7 @@
return [NSString stringWithFormat:@"%@ '%@' (%p)",
GetNSStringAndRelease(_peer->GetClassName()),
GetNSStringAndRelease(_peer->GetName()),
_peer];
_peer.getRaw()];
}
- (IAvnAutomationPeer *)peer
@ -317,7 +317,30 @@
- (id)accessibilityParent
{
auto parentPeer = _peer->GetParent();
return parentPeer ? [AvnAccessibilityElement acquire:parentPeer] : [NSApplication sharedApplication];
if (parentPeer == nullptr)
return [NSApplication sharedApplication];
// When the parent is a root provider, return the AvnView (content view)
// rather than the AvnWindow. macOS accessibility requires that the parent
// chain is consistent with the children chain: AvnView exposes these
// elements as its accessibilityChildren, so the elements must report
// AvnView as their accessibilityParent. A mismatch causes macOS to be
// unable to resolve AXUIElementRefs back to the correct object, which
// makes setter calls like AXUIElementSetAttributeValue silently land on
// AvnView instead of the target AvnAccessibilityElement.
if (parentPeer->IsRootProvider())
{
auto window = parentPeer->RootProvider_GetWindow();
if (window != nullptr)
{
auto holder = dynamic_cast<INSViewHolder*>(window);
if (holder != nullptr)
return holder->GetNSView();
}
}
return [AvnAccessibilityElement acquire:parentPeer];
}
- (id)accessibilityTopLevelUIElement
@ -403,7 +426,11 @@
- (BOOL)isAccessibilitySelectorAllowed:(SEL)selector
{
if (selector == @selector(accessibilityPerformShowMenu))
if (selector == @selector(setAccessibilityValue:))
{
return _peer->IsValueProvider() || _peer->IsRangeValueProvider();
}
else if (selector == @selector(accessibilityPerformShowMenu))
{
return _peer->IsExpandCollapseProvider() && _peer->ExpandCollapseProvider_GetShowsMenu();
}
@ -422,7 +449,7 @@
{
return _peer->IsRangeValueProvider();
}
return [super isAccessibilitySelectorAllowed:selector];
}

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

@ -219,7 +219,7 @@ public:
}
};
static IAvnGlDisplay* GlDisplay = new AvnGlDisplay();
static ComStaticPtr<AvnGlDisplay> GlDisplay(comnew<AvnGlDisplay>());
extern IAvnGlDisplay* GetGlDisplay()

37
native/Avalonia.Native/src/OSX/clipboard.mm

@ -183,7 +183,9 @@ public:
for (auto i = 0; i < count; ++i)
{
auto item = source->GetItem(i);
ComPtr<IAvnClipboardDataItem> item;
if(S_OK != source->GetItem(i, item.getPPV()))
continue;
auto writeableItem = [[WriteableClipboardItem alloc] initWithItem:item source:source];
[writeableItems addObject:writeableItem];
}
@ -219,8 +221,8 @@ extern IAvnClipboard* CreateClipboard(NSPasteboard* pb)
@implementation WriteableClipboardItem
{
IAvnClipboardDataItem* _item;
IAvnClipboardDataSource* _source;
ComPtr<IAvnClipboardDataItem> _item;
ComPtr<IAvnClipboardDataSource> _source;
}
- (nonnull WriteableClipboardItem*) initWithItem:(nonnull IAvnClipboardDataItem*)item source:(nonnull IAvnClipboardDataSource*)source
@ -229,9 +231,6 @@ extern IAvnClipboard* CreateClipboard(NSPasteboard* pb)
_item = item;
_source = source;
// Each item references its source so it doesn't get disposed too early.
source->AddRef();
return self;
}
@ -283,8 +282,9 @@ NSString* TryConvertFormatToUti(NSString* format)
- (nonnull NSArray<NSPasteboardType>*) writableTypesForPasteboard:(nonnull NSPasteboard*)pasteboard
{
auto formats = _item->ProvideFormats();
if (formats == nullptr)
ComPtr<IAvnStringArray> formats;
auto hr = _item->ProvideFormats(formats.getPPV());
if (hr != S_OK || formats == nullptr)
return [NSArray array];
auto count = formats->GetCount();
@ -304,7 +304,6 @@ NSString* TryConvertFormatToUti(NSString* format)
if (uti != nil)
[utis addObject:uti];
}
formats->Release();
[utis addObject:GetAvnCustomDataType()];
@ -323,8 +322,9 @@ NSString* TryConvertFormatToUti(NSString* format)
if ([type isEqualToString:GetAvnCustomDataType()])
return @"";
ComPtr<IAvnClipboardDataValue> value(_item->GetValue([type UTF8String]), true);
if (value.getRaw() == nullptr)
ComPtr<IAvnClipboardDataValue> value;
HRESULT hr = _item->GetValue([type UTF8String], value.getPPV());
if (hr != S_OK || value.getRaw() == nullptr)
return nil;
if (value->IsString())
@ -336,19 +336,4 @@ NSString* TryConvertFormatToUti(NSString* format)
return [NSData dataWithBytesNoCopy:buffer length:length];
}
- (void) dealloc
{
if (_item != nullptr)
{
_item->Release();
_item = nullptr;
}
if (_source != nullptr)
{
_source->Release();
_source = nullptr;
}
}
@end

3
native/Avalonia.Native/src/OSX/common.h

@ -36,7 +36,8 @@ extern IAvnPlatformRenderTimer* CreatePlatformRenderTimer();
extern IAvnNativeObjectsMemoryManagement* CreateMemoryManagementHelper();
extern void SetAppMenu(IAvnMenu *menu);
extern void SetServicesMenu (IAvnMenu* menu);
extern IAvnMenu* GetAppMenu ();
class AvnAppMenu;
extern AvnAppMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
extern void SetDockMenu(NSMenu* menu);

1
native/Avalonia.Native/src/OSX/cursor.h

@ -28,5 +28,4 @@ public:
}
};
extern std::map<AvnStandardCursorType, Cursor*> s_cursorMap;
#endif /* cursor_h */

34
native/Avalonia.Native/src/OSX/cursor.mm

@ -3,24 +3,24 @@
class CursorFactory : public ComSingleObject<IAvnCursorFactory, &IID_IAvnCursorFactory>
{
Cursor* arrowCursor = new Cursor([NSCursor arrowCursor]);
Cursor* crossCursor = new Cursor([NSCursor crosshairCursor]);
Cursor* resizeUpCursor = new Cursor([NSCursor resizeUpCursor]);
Cursor* resizeDownCursor = new Cursor([NSCursor resizeDownCursor]);
Cursor* resizeUpDownCursor = new Cursor([NSCursor resizeUpDownCursor]);
Cursor* dragCopyCursor = new Cursor([NSCursor dragCopyCursor]);
Cursor* openHandCursor = new Cursor([NSCursor openHandCursor]);
Cursor* dragLinkCursor = new Cursor([NSCursor dragLinkCursor]);
Cursor* pointingHandCursor = new Cursor([NSCursor pointingHandCursor]);
Cursor* contextualMenuCursor = new Cursor([NSCursor contextualMenuCursor]);
Cursor* IBeamCursor = new Cursor([NSCursor IBeamCursor]);
Cursor* resizeLeftCursor = new Cursor([NSCursor resizeLeftCursor]);
Cursor* resizeRightCursor = new Cursor([NSCursor resizeRightCursor]);
Cursor* resizeWestEastCursor = new Cursor([NSCursor resizeLeftRightCursor]);
Cursor* operationNotAllowedCursor = new Cursor([NSCursor operationNotAllowedCursor]);
Cursor* noCursor = new Cursor([NSCursor arrowCursor], true);
ComPtr<Cursor> arrowCursor = comnew<Cursor>([NSCursor arrowCursor]);
ComPtr<Cursor> crossCursor = comnew<Cursor>([NSCursor crosshairCursor]);
ComPtr<Cursor> resizeUpCursor = comnew<Cursor>([NSCursor resizeUpCursor]);
ComPtr<Cursor> resizeDownCursor = comnew<Cursor>([NSCursor resizeDownCursor]);
ComPtr<Cursor> resizeUpDownCursor = comnew<Cursor>([NSCursor resizeUpDownCursor]);
ComPtr<Cursor> dragCopyCursor = comnew<Cursor>([NSCursor dragCopyCursor]);
ComPtr<Cursor> openHandCursor = comnew<Cursor>([NSCursor openHandCursor]);
ComPtr<Cursor> dragLinkCursor = comnew<Cursor>([NSCursor dragLinkCursor]);
ComPtr<Cursor> pointingHandCursor = comnew<Cursor>([NSCursor pointingHandCursor]);
ComPtr<Cursor> contextualMenuCursor = comnew<Cursor>([NSCursor contextualMenuCursor]);
ComPtr<Cursor> IBeamCursor = comnew<Cursor>([NSCursor IBeamCursor]);
ComPtr<Cursor> resizeLeftCursor = comnew<Cursor>([NSCursor resizeLeftCursor]);
ComPtr<Cursor> resizeRightCursor = comnew<Cursor>([NSCursor resizeRightCursor]);
ComPtr<Cursor> resizeWestEastCursor = comnew<Cursor>([NSCursor resizeLeftRightCursor]);
ComPtr<Cursor> operationNotAllowedCursor = comnew<Cursor>([NSCursor operationNotAllowedCursor]);
ComPtr<Cursor> noCursor = comnew<Cursor>([NSCursor arrowCursor], true);
std::map<AvnStandardCursorType, Cursor*> s_cursorMap =
std::map<AvnStandardCursorType, ComPtr<Cursor>> s_cursorMap =
{
{ CursorArrow, arrowCursor },
{ CursorAppStarting, arrowCursor },

4
native/Avalonia.Native/src/OSX/menu.h

@ -29,8 +29,8 @@ class AvnAppMenuItem : public ComSingleObject<IAvnMenuItem, &IID_IAvnMenuItem>
{
private:
NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem
IAvnActionCallback* _callback;
IAvnPredicateCallback* _predicate;
ComPtr<IAvnActionCallback> _callback;
ComPtr<IAvnPredicateCallback> _predicate;
bool _isCheckable;
public:

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

@ -35,7 +35,7 @@
@implementation AvnMenuItem
{
AvnAppMenuItem* _item;
ComObjectWeakPtr<AvnAppMenuItem> _item;
}
- (id) initWithAvnAppMenuItem: (AvnAppMenuItem*)menuItem
@ -61,13 +61,19 @@
{
return YES;
}
auto item = _item.tryGet();
if(item == nullptr)
return NO;
return _item->EvaluateItemEnabled();
return item->EvaluateItemEnabled();
}
- (void)didSelectItem:(nullable id)sender
{
_item->RaiseOnClicked();
auto item = _item.tryGet();
if(item == nullptr)
return;
item->RaiseOnClicked();
}
@end
@ -478,17 +484,15 @@ extern IAvnMenuItem* CreateAppMenuItemSeparator()
}
}
static IAvnMenu* s_appMenu = nullptr;
static ComStaticPtr<AvnAppMenu> s_appMenu;
static NSMenuItem* s_appMenuItem = nullptr;
extern void SetAppMenu(IAvnMenu *menu)
{
s_appMenu = menu;
s_appMenu.set(dynamic_cast<AvnAppMenu*>(menu));
if(s_appMenu != nullptr)
{
auto nativeMenu = dynamic_cast<AvnAppMenu*>(s_appMenu);
auto currentMenu = [s_appMenuItem menu];
if (currentMenu != nullptr)
@ -496,7 +500,7 @@ extern void SetAppMenu(IAvnMenu *menu)
[currentMenu removeItem:s_appMenuItem];
}
s_appMenuItem = [nativeMenu->GetNative() itemAtIndex:0];
s_appMenuItem = [s_appMenu->GetNative() itemAtIndex:0];
if (currentMenu == nullptr)
{
@ -524,9 +528,9 @@ extern void SetServicesMenu (IAvnMenu* menu)
[NSApplication sharedApplication].servicesMenu = nativeMenu->GetNative();
}
extern IAvnMenu* GetAppMenu ()
extern AvnAppMenu* GetAppMenu ()
{
return s_appMenu;
return s_appMenu.getRaw();
}
extern NSMenuItem* GetAppMenuItem ()

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

@ -304,7 +304,7 @@ public:
}
};
static AvnMetalDisplay* _display = new AvnMetalDisplay();
static ComStaticPtr<AvnMetalDisplay> _display(comnew<AvnMetalDisplay>());
extern IAvnMetalDisplay* GetMetalDisplay()
{

2
nukebuild/Build.cs

@ -481,7 +481,7 @@ partial class Build : NukeBuild
.SetProperty("AvaloniaVersion", Parameters.Version)
.SetProperty("NuGetPackageRoot", nugetCacheDirectory)
.SetPackageDirectory(nugetCacheDirectory)
.SetProjectFile(buildTestsDirectory / "BuildTests.sln")
.SetProjectFile(buildTestsDirectory / "BuildTests.slnx")
.SetProcessAdditionalArguments("--nodeReuse:false"));
// Standard compilation - should have compiled XAML

4
nukebuild/_build.csproj

@ -7,11 +7,11 @@
<NoWarn>$(NoWarn);CS0649;CA1847</NoWarn>
<NukeTelemetryVersion>1</NukeTelemetryVersion>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<UseMicroComGenerator>true</UseMicroComGenerator>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nuke.Common" />
<PackageReference Include="MicroCom.CodeGenerator" />
<PackageReference Include="Numerge" />
<!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" />
@ -22,6 +22,8 @@
<PackageDownload Include="dotnet-ilrepack" Version="[2.0.44]" />
</ItemGroup>
<Import Project="..\build\MicroCOM.props" />
<ItemGroup>
<NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" />
<NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />

100
readme.md

@ -1,10 +1,8 @@
[![Star_Banner@3x](https://github.com/user-attachments/assets/d55eb468-fa5c-499f-858e-54618beb6f92)](https://github.com/sponsors/AvaloniaUI)
[![Hero](https://github.com/user-attachments/assets/7436f0e7-8aea-4cff-886a-e2faef29ca37)](https://avaloniaui.net?utm_source=github&utm_medium=referral&utm_content=readme_link)
[![Hero](https://github.com/user-attachments/assets/404db53f-f515-4a3a-bb18-f145dc34cedb)](https://avaloniaui.net?utm_source=github&utm_medium=referral&utm_content=readme_link)
[![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia)
[![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://img.shields.io/opencollective/backers/Avalonia?logo=opencollective)](#backers) [![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/Avalonia?logo=opencollective)](#sponsors) [![GitHub Sponsors](https://img.shields.io/github/sponsors/AvaloniaUI?logo=github)](https://github.com/sponsors/AvaloniaUI) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
<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) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg)
[![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
[![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)
## 📖 About
@ -14,26 +12,33 @@ Considered by many to be the spiritual successor to WPF, Avalonia UI provides a
For those seeking a cross-platform WPF, we have created [Avalonia XPF]([https://avaloniaui.net/xpf](https://avaloniaui.net/xpf?utm_source=github&utm_medium=referral&utm_content=readme_link)), enabling WPF applications to run on macOS and Linux with little to no code changes. Avalonia XPF is a commercial product and is licensed per-app, per-platform.
#### Blog
### Blog
To see the latest announcements and read about the state of Avalonia, check out the [Avalonia UI Blog](https://www.avaloniaui.net/blog?utm_source=github&utm_medium=referral&utm_content=readme_link).
#### Breaking Changes
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.
### Sponsorship
Avalonia development is supported by the generous sponsorship of [Devolutions](https://devolutions.net/?utm_source=pr&utm_medium=partnership&utm_campaign=avalonia&utm_id=C086&member_status=responded).
#### Awesome Avalonia
[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!
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/218a7077-6978-4c37-adc7-4a24bb0edcb9">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/597e3650-0b80-496e-84b2-db51fbe7e06e">
<img alt="Devolutions Logo" src="https://github.com/user-attachments/assets/597e3650-0b80-496e-84b2-db51fbe7e06e" width="200" >
</picture>
---
## 🚀 Getting Started
See our [Get Started](https://avaloniaui.net/gettingstarted?utm_source=github&utm_medium=referral&utm_content=readme_link) guide to begin developing apps with Avalonia UI.
See our [Get Started](https://docs.avaloniaui.net/docs/get-started?utm_source=github&utm_medium=referral&utm_content=readme_link) guide to begin developing apps with Avalonia UI.
### Visual Studio Code
The [Avalonia for Code](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.vscode-avalonia) extension gives you everything you need to build cross-platform .NET apps. XAML previewing, code completion, diagnostics, and code navigation, all inside the world's most popular editor. It's the fastest way to get started with Avalonia.
### Visual Studio
The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaVS) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started).
### Visual Studio 2022 & 2026
The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaVS) contains project and control templates, a live XAML previewer, code completion, and full diagnostics directly into Visual Studio.
### JetBrains Rider
[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) supports for Avalonia.
Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
Code completion, inspections and refactorings are supported out of the box. To enable previewing XAML, you will require a 3rd party, community-maintained extension: `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
### Avalonia Packages
Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
@ -43,79 +48,58 @@ Use these commands in the Package Manager console to install Avalonia manually:
Install-Package Avalonia
Install-Package Avalonia.Desktop
```
## Showcase
[![Showcase_Banner@3x](https://github.com/user-attachments/assets/42d21506-3d5a-4213-a4b4-7889a48acdc8)](https://avaloniaui.net/showcase?utm_source=github&utm_medium=referral&utm_content=readme_link)
See what others have built with Avalonia UI on our [Showcase](https://avaloniaui.net/showcase?utm_source=github&utm_medium=referral&utm_content=readme_link). We welcome submissions!
## Sponsors
Avalonia development is supported by the generous sponsorship of [Devolutions](https://devolutions.net/?utm_source=pr&utm_medium=partnership&utm_campaign=avalonia&utm_id=C086&member_status=responded).
<a href="https://devolutions.net/?utm_source=pr&utm_medium=partnership&utm_campaign=avalonia&utm_id=C086&member_status=responded"><img width="200" alt="devolutions-color-hr" src="https://github.com/user-attachments/assets/597e3650-0b80-496e-84b2-db51fbe7e06e"/></a>
## Community
Join our community hub to get early access to upcoming features, share your thoughts, and connect directly with the Avalonia team.
[![communityannouncement-banner 1](https://github.com/user-attachments/assets/21950b56-cd28-4574-9a0a-73bb17b89d31)](https://avaloniaui.community)
---
## Bleeding Edge Builds
We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) which tracks the current state of master. Although these packages are less stable than the release on NuGet.org, you'll get all the latest features and bugfixes right away and many of our users actually prefer this feed!
---
## Learning
### Documentation
Documentation can be found at https://docs.avaloniaui.net.
### Tutorials
We also have a [tutorial](https://docs.avaloniaui.net/docs/getting-started/programming-with-avalonia) over there for newcomers.
We also have a [tutorial](https://docs.avaloniaui.net/docs/get-started/starter-tutorial) over there for newcomers.
### Samples
We have a [range of samples](https://github.com/AvaloniaUI/Avalonia.Samples) to help you get started.
### Breaking Changes
You can also see what [breaking changes](https://docs.avaloniaui.net/docs/avalonia12-breaking-changes) between Avalonia 11 and Avalonia 12.
---
## Building and Using
See the [build instructions here](docs/build.md).
---
## Contributing
This project exists thanks to all the people who contribute.
<a href="https://github.com/AvaloniaUI/Avalonia/graphs/contributors"><img src="https://opencollective.com/Avalonia/contributors.svg?width=890&button=false" /></a>
Please read the [contribution guidelines](CONTRIBUTING.md) before submitting a pull request.
This project exists thanks to all the people who contribute. Please read the [contribution guidelines](CONTRIBUTING.md) before submitting a pull request.
## Code of Conduct
### Code of Conduct
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
For more information see the [Code of Conduct](CODE_OF_CONDUCT.md).
For more information, see the [Code of Conduct](CODE_OF_CONDUCT.md).
## Licence
Avalonia is licenced under the [MIT licence](licence.md).
## Donate
Donating to the project is a fantastic way to thank our valued contributors for their hard work. Your donations are shared among our community and awarded for significant contributions.
---
## Security
If you need support see Commercial Support section below.
If you discover a security vulnerability in any of our SDKs, tools, services, or repositories, please help us keep the community safe by reporting it responsibly.
Donate with BTC or use [Open Collective](https://opencollective.com/avalonia).
You can report security vulnerabilities by emailing **[security@avaloniaui.net](mailto:security@avaloniaui.net)**.
**BTC**: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx
Please avoid disclosing the issue publicly until we have had a reasonable amount of time to investigate and release a patch or mitigation. We review all legitimate reports and will work with you to quickly resolve the issue.
### Backers
Please note that Avalonia does not operate a bug bounty programme.
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)]
<a href="https://opencollective.com/Avalonia#backers" target="_blank"><img src="https://opencollective.com/Avalonia/backers.svg?width=890"></a>
## Commercial Support
We have a range of [support plans available](https://avaloniaui.net/support?utm_source=github&utm_medium=referral&utm_content=readme_link) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process.
---
## Licence
*Please note that donations are not considered payment for commercial support agreements. Please contact us to discuss your needs first. [team@avaloniaui.net](mailto://team@avaloniaui.net)*
Avalonia is licenced under the [MIT licence](licence.md).
## Avalonia XPF - Our cross-platform WPF
## XPF - cross-platform WPF
Unleash the full potential of your existing WPF apps with our cross-platform UI framework, enabling WPF apps to run on macOS and Linux without requiring expensive and risky rewrites.
[![GH_Banner](https://github.com/user-attachments/assets/a6176267-1187-45ff-b82b-fcc7048e54b7)](https://avaloniaui.net/xpf?utm_source=github&utm_medium=referral&utm_content=readme_ad)
[![GH_Banner](https://github.com/user-attachments/assets/d0a3cb13-f35d-41dd-aec9-632fe848acb0)](https://avaloniaui.net/xpf?utm_source=github&utm_medium=referral&utm_content=readme_ad)

2
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -5,6 +5,7 @@
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseMicroCom>true</UseMicroCom>
</PropertyGroup>
<ItemGroup>
@ -37,4 +38,5 @@
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\MicroCOM.props" />
</Project>

2
samples/ControlCatalog/MainView.xaml

@ -16,7 +16,7 @@
</Style>
</Grid.Styles>
<controls:HamburgerMenu Name="Sidebar">
<TabItem Header="Composition">
<TabItem Header="Composition" IsSelected="True">
<pages:CompositionPage />
</TabItem>
<TabItem Header="Accelerator">

4
samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs

@ -703,7 +703,7 @@ public partial class CareCompanionAppPage : UserControl
var home = BuildHomeTab();
home.Header = "Home";
home.Icon = Geometry.Parse("M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z");
home.Icon = new PathIcon { Data = Geometry.Parse("M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z") };
tp.Pages = new ObservableCollection<Page>
{
@ -729,7 +729,7 @@ public partial class CareCompanionAppPage : UserControl
=> new ContentPage
{
Header = header,
Icon = Geometry.Parse(iconData),
Icon = new PathIcon { Data = Geometry.Parse(iconData) },
Background = new SolidColorBrush(BgLight),
Content = new StackPanel
{

8
samples/ControlCatalog/Pages/CarouselPage/SanctuaryMainPage.xaml

@ -93,7 +93,7 @@
<ContentPage Header="Home"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z</StreamGeometry>
<PathIcon Data="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</ContentPage.Icon>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
@ -243,7 +243,7 @@
<ContentPage Header="Explore"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z</StreamGeometry>
<PathIcon Data="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z" />
</ContentPage.Icon>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="12" Margin="32">
@ -260,7 +260,7 @@
<ContentPage Header="Saved"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z</StreamGeometry>
<PathIcon Data="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
</ContentPage.Icon>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="12" Margin="32">
@ -277,7 +277,7 @@
<ContentPage Header="Profile"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z</StreamGeometry>
<PathIcon Data="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
</ContentPage.Icon>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="12" Margin="32">

9
samples/ControlCatalog/Pages/ClipboardPage.xaml.cs

@ -21,8 +21,6 @@ namespace ControlCatalog.Pages
DataFormat.CreateBytesApplicationFormat("controlcatalog-binary-data");
private INotificationManager? _notificationManager;
private INotificationManager NotificationManager => _notificationManager
??= new WindowNotificationManager(TopLevel.GetTopLevel(this)!);
private readonly DispatcherTimer _clipboardLastDataObjectChecker;
private DataTransfer? _storedDataTransfer;
@ -107,7 +105,7 @@ namespace ControlCatalog.Pages
if (invalidFile.Count > 0)
{
NotificationManager.Show(new Notification("Warning", "There is one o more invalid path.", NotificationType.Warning));
_notificationManager?.Show(new Notification("Warning", "There is one o more invalid path.", NotificationType.Warning));
}
if (files.Count > 0)
@ -116,11 +114,11 @@ namespace ControlCatalog.Pages
foreach (var file in files)
dataTransfer.Add(DataTransferItem.Create(DataFormat.File, file));
await clipboard.SetDataAsync(dataTransfer);
NotificationManager.Show(new Notification("Success", "Copy completed.", NotificationType.Success));
_notificationManager?.Show(new Notification("Success", "Copy completed.", NotificationType.Success));
}
else
{
NotificationManager.Show(new Notification("Warning", "Any files to copy in Clipboard.", NotificationType.Warning));
_notificationManager?.Show(new Notification("Warning", "Any files to copy in Clipboard.", NotificationType.Warning));
}
}
}
@ -179,6 +177,7 @@ namespace ControlCatalog.Pages
{
_clipboardLastDataObjectChecker.Start();
base.OnAttachedToVisualTree(e);
_notificationManager = new WindowNotificationManager(TopLevel.GetTopLevel(this)!);
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)

24
samples/ControlCatalog/Pages/CommandBar/CommandBarCustomizationPage.xaml

@ -15,9 +15,9 @@
<TextBlock Text="Live Preview" FontWeight="SemiBold" FontSize="13" />
<CommandBar x:Name="LiveBar">
<CommandBar.PrimaryCommands>
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Share"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.PrimaryCommands>
</CommandBar>
@ -74,7 +74,7 @@
<TextBlock Text="About" FontWeight="SemiBold" />
<TextBlock Text="CommandBar inherits from TemplatedControl, so Background, Foreground, BorderBrush, BorderThickness, and CornerRadius are available out of the box."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock Text="Foreground is an inherited property: setting it on the CommandBar cascades to all PathIcons inside AppBarButton/AppBarToggleButton."
<TextBlock Text="Foreground is an inherited property: setting it on the CommandBar cascades to all PathIcons inside CommandBarButton/CommandBarToggleButton."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" Margin="0,4,0,0" />
</StackPanel>
</ScrollViewer>
@ -89,20 +89,20 @@
<TextBlock Text="Default theme" FontSize="12" Opacity="0.7" />
<CommandBar OverflowButtonVisibility="Collapsed">
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
<TextBlock Text="Solid color" FontSize="12" Opacity="0.7" />
<CommandBar Background="#0078D4" Foreground="White" OverflowButtonVisibility="Collapsed">
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
<TextBlock Text="Dark" FontSize="12" Opacity="0.7" />
<CommandBar Background="#1C1C1E" Foreground="White" OverflowButtonVisibility="Collapsed">
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
<TextBlock Text="Pill shape (CornerRadius=20)" FontSize="12" Opacity="0.7" />
@ -111,8 +111,8 @@
BorderBrush="#CCCCCC"
BorderThickness="1"
OverflowButtonVisibility="Collapsed">
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
</StackPanel>
</ScrollViewer>

40
samples/ControlCatalog/Pages/CommandBar/CommandBarDynamicOverflowPage.xaml

@ -8,6 +8,7 @@
<StreamGeometry x:Key="BoldIcon">M15.6,10.79C17.04,10.07 18,8.64 18,7C18,4.79 16.21,3 14,3H7V21H14.73C16.78,21 18.5,19.37 18.5,17.32C18.5,15.82 17.72,14.53 16.5,13.77C16.2,13.59 15.9,13.44 15.6,13.32V10.79M10,6.5H13C13.83,6.5 14.5,7.17 14.5,8C14.5,8.83 13.83,9.5 13,9.5H10V6.5M13.5,17.5H10V14H13.5C14.33,14 15,14.67 15,15.5C15,16.33 14.33,17.5 13.5,17.5Z</StreamGeometry>
<StreamGeometry x:Key="ItalicIcon">M10,4V7H12.21L8.79,15H6V18H14V15H11.79L15.21,7H18V4H10Z</StreamGeometry>
<StreamGeometry x:Key="DeleteIcon">M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z</StreamGeometry>
<StreamGeometry x:Key="ExportIcon">M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M16,11V18.1L13.9,16L11.1,18.8L8.3,16L11.1,13.2L9,11.1L16,11Z</StreamGeometry>
</UserControl.Resources>
<DockPanel>
@ -33,6 +34,18 @@
IsChecked="True"
IsCheckedChanged="OnDynamicOverflowChanged" />
<CheckBox x:Name="SecondaryVisibleCheck"
Content="Include secondary command"
IsChecked="False"
IsCheckedChanged="OnSecondaryVisibilityChanged" />
<Separator />
<TextBlock Text="Resize to force grouped commands into overflow and verify that primary separators never become leading, trailing, or overflow items."
FontSize="12"
Opacity="0.7"
TextWrapping="Wrap" />
<Separator />
<TextBlock Text="Overflow Priority" FontWeight="SemiBold" />
@ -47,11 +60,11 @@
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<StackPanel Margin="12" Spacing="8">
<TextBlock x:Name="StatusText"
Text="Showing 6 of 6 commands, 0 in overflow"
FontSize="12"
Opacity="0.7" />
<StackPanel Margin="12" Spacing="8">
<TextBlock x:Name="StatusText"
Text="Visible primary: 6 commands, 2 separators&#x0a;Overflow items: 2 commands, 1 separator&#x0a;Synthetic overflow divider: present"
FontSize="12"
Opacity="0.7" />
<Border x:Name="BarContainer"
Width="400"
HorizontalAlignment="Left"
@ -61,13 +74,18 @@
ClipToBounds="True">
<CommandBar x:Name="DemoBar" IsDynamicOverflowEnabled="True">
<CommandBar.PrimaryCommands>
<AppBarButton Label="New" DynamicOverflowOrder="0"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save" DynamicOverflowOrder="0"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share" DynamicOverflowOrder="1"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Bold" DynamicOverflowOrder="2"><AppBarButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Italic" DynamicOverflowOrder="2"><AppBarButton.Icon><PathIcon Data="{StaticResource ItalicIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Delete" DynamicOverflowOrder="3"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New" DynamicOverflowOrder="0"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save" DynamicOverflowOrder="0"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarSeparator />
<CommandBarButton Label="Share" DynamicOverflowOrder="1"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Bold" DynamicOverflowOrder="2"><CommandBarButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarSeparator />
<CommandBarButton Label="Italic" DynamicOverflowOrder="2"><CommandBarButton.Icon><PathIcon Data="{StaticResource ItalicIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Delete" DynamicOverflowOrder="3"><CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<CommandBarButton x:Name="DemoSecondaryCommand" Label="Export"><CommandBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.SecondaryCommands>
</CommandBar>
</Border>
</StackPanel>

64
samples/ControlCatalog/Pages/CommandBar/CommandBarDynamicOverflowPage.xaml.cs

@ -9,7 +9,13 @@ namespace ControlCatalog.Pages
public CommandBarDynamicOverflowPage()
{
InitializeComponent();
if (SecondaryVisibleCheck.IsChecked != true)
{
DemoBar.SecondaryCommands?.Remove(DemoSecondaryCommand);
}
((INotifyCollectionChanged)DemoBar.OverflowItems).CollectionChanged += OnOverflowChanged;
((INotifyCollectionChanged)DemoBar.VisiblePrimaryCommands).CollectionChanged += OnOverflowChanged;
UpdateStatus();
}
@ -29,6 +35,26 @@ namespace ControlCatalog.Pages
DemoBar.IsDynamicOverflowEnabled = DynamicOverflowCheck.IsChecked == true;
}
private void OnSecondaryVisibilityChanged(object? sender, RoutedEventArgs e)
{
if (DemoBar?.SecondaryCommands == null || DemoSecondaryCommand == null)
return;
bool shouldInclude = SecondaryVisibleCheck.IsChecked == true;
bool isIncluded = DemoBar.SecondaryCommands.Contains(DemoSecondaryCommand);
if (shouldInclude && !isIncluded)
{
DemoBar.SecondaryCommands.Add(DemoSecondaryCommand);
}
else if (!shouldInclude && isIncluded)
{
DemoBar.SecondaryCommands.Remove(DemoSecondaryCommand);
}
UpdateStatus();
}
private void OnOverflowChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
UpdateStatus();
@ -36,10 +62,40 @@ namespace ControlCatalog.Pages
private void UpdateStatus()
{
var total = DemoBar.PrimaryCommands.Count;
var overflow = DemoBar.OverflowItems.Count;
var visible = total - overflow;
StatusText.Text = $"Showing {visible} of {total} commands, {overflow} in overflow";
int visiblePrimaryCommandCount = 0;
int visiblePrimarySeparatorCount = 0;
foreach (var item in DemoBar.VisiblePrimaryCommands)
{
if (item is CommandBarSeparator)
visiblePrimarySeparatorCount++;
else
visiblePrimaryCommandCount++;
}
int overflowCommandCount = 0;
int overflowSeparatorCount = 0;
bool hasSyntheticOverflowDivider = false;
foreach (var item in DemoBar.OverflowItems)
{
if (item is CommandBarSeparator separator)
{
overflowSeparatorCount++;
if (!DemoBar.PrimaryCommands.Contains(separator) &&
!DemoBar.SecondaryCommands.Contains(separator))
{
hasSyntheticOverflowDivider = true;
}
}
else
{
overflowCommandCount++;
}
}
StatusText.Text =
$"Visible primary: {visiblePrimaryCommandCount} commands, {visiblePrimarySeparatorCount} separators\n" +
$"Overflow items: {overflowCommandCount} commands, {overflowSeparatorCount} separators\n" +
$"Synthetic overflow divider: {(hasSyntheticOverflowDivider ? "present" : "absent")}";
}
}
}

10
samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml

@ -64,13 +64,13 @@
<CommandBar x:Name="DemoBar"
OverflowButtonVisibility="Auto">
<CommandBar.PrimaryCommands>
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Share"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<AppBarButton Label="Export"><AppBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="Export"><CommandBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Delete"><CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.SecondaryCommands>
</CommandBar>

18
samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml.cs

@ -141,13 +141,13 @@ namespace ControlCatalog.Pages
private void OnCommandItemClick(object? sender, RoutedEventArgs e)
{
if (sender is AppBarButton button)
if (sender is CommandBarButton button)
AppendLog($"Click, {button.Label}, {DescribePlacement(button)}");
}
private AppBarButton CreateButton(string label)
private CommandBarButton CreateButton(string label)
{
var button = new AppBarButton
var button = new CommandBarButton
{
Label = label,
Icon = new PathIcon
@ -170,14 +170,14 @@ namespace ControlCatalog.Pages
{
foreach (var item in items)
{
if (item is AppBarButton button)
if (item is CommandBarButton button)
button.Click -= OnCommandItemClick;
}
}
private void AttachItemHandler(ICommandBarElement item)
{
if (item is not AppBarButton button)
if (item is not CommandBarButton button)
return;
button.Click -= OnCommandItemClick;
@ -191,10 +191,10 @@ namespace ControlCatalog.Pages
return;
var item = items[^1];
var label = item is AppBarButton button ? button.Label ?? "(unnamed)" : item.GetType().Name;
var label = item is CommandBarButton button ? button.Label ?? "(unnamed)" : item.GetType().Name;
if (item is AppBarButton appBarButton)
appBarButton.Click -= OnCommandItemClick;
if (item is CommandBarButton commandBarButton)
commandBarButton.Click -= OnCommandItemClick;
items.RemoveAt(items.Count - 1);
@ -202,7 +202,7 @@ namespace ControlCatalog.Pages
RefreshState();
}
private static string DescribePlacement(AppBarButton button)
private static string DescribePlacement(CommandBarButton button)
{
return button.IsInOverflow ? "overflow" : "primary";
}

56
samples/ControlCatalog/Pages/CommandBar/CommandBarFirstLookPage.xaml

@ -36,7 +36,7 @@
<Separator />
<TextBlock Text="Separators" FontWeight="SemiBold" />
<TextBlock Text="AppBarSeparator creates visual dividers between command groups."
<TextBlock Text="CommandBarSeparator creates visual dividers between command groups."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
@ -52,35 +52,35 @@
<TextBlock Text="Document Editor" VerticalAlignment="Center" Margin="8,0" />
</CommandBar.Content>
<CommandBar.PrimaryCommands>
<AppBarButton Label="New" Click="OnButtonClick">
<AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon>
</AppBarButton>
<AppBarButton Label="Save" Click="OnButtonClick">
<AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon>
</AppBarButton>
<AppBarSeparator />
<AppBarToggleButton Label="Bold" IsCheckedChanged="OnToggleChanged">
<AppBarToggleButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></AppBarToggleButton.Icon>
</AppBarToggleButton>
<AppBarToggleButton Label="Italic" IsCheckedChanged="OnToggleChanged">
<AppBarToggleButton.Icon><PathIcon Data="{StaticResource ItalicIcon}" /></AppBarToggleButton.Icon>
</AppBarToggleButton>
<AppBarSeparator />
<AppBarButton Label="Share" Click="OnButtonClick">
<AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon>
</AppBarButton>
<CommandBarButton Label="New" Click="OnButtonClick">
<CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Save" Click="OnButtonClick">
<CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarSeparator />
<CommandBarToggleButton Label="Bold" IsCheckedChanged="OnToggleChanged">
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarToggleButton Label="Italic" IsCheckedChanged="OnToggleChanged">
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource ItalicIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarSeparator />
<CommandBarButton Label="Share" Click="OnButtonClick">
<CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<AppBarButton Label="Export" Click="OnButtonClick">
<AppBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></AppBarButton.Icon>
</AppBarButton>
<AppBarButton Label="Print" Click="OnButtonClick">
<AppBarButton.Icon><PathIcon Data="{StaticResource PrintIcon}" /></AppBarButton.Icon>
</AppBarButton>
<AppBarSeparator />
<AppBarButton Label="Delete" Click="OnButtonClick">
<AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon>
</AppBarButton>
<CommandBarButton Label="Export" Click="OnButtonClick">
<CommandBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Print" Click="OnButtonClick">
<CommandBarButton.Icon><PathIcon Data="{StaticResource PrintIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarSeparator />
<CommandBarButton Label="Delete" Click="OnButtonClick">
<CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
</CommandBar.SecondaryCommands>
</CommandBar>

4
samples/ControlCatalog/Pages/CommandBar/CommandBarFirstLookPage.xaml.cs

@ -12,13 +12,13 @@ namespace ControlCatalog.Pages
private void OnButtonClick(object? sender, RoutedEventArgs e)
{
if (sender is AppBarButton btn)
if (sender is CommandBarButton btn)
StatusText.Text = $"{btn.Label} clicked";
}
private void OnToggleChanged(object? sender, RoutedEventArgs e)
{
if (sender is AppBarToggleButton btn)
if (sender is CommandBarToggleButton btn)
StatusText.Text = btn.IsChecked == true
? $"{btn.Label} enabled"
: $"{btn.Label} disabled";

121
samples/ControlCatalog/Pages/CommandBar/CommandBarKeyboardPage.xaml

@ -0,0 +1,121 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CommandBarKeyboardPage">
<UserControl.Resources>
<StreamGeometry x:Key="AddIcon">M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z</StreamGeometry>
<StreamGeometry x:Key="SaveIcon">M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z</StreamGeometry>
<StreamGeometry x:Key="BoldIcon">M15.6,10.79C17.04,10.07 18,8.64 18,7C18,4.79 16.21,3 14,3H7V21H14.73C16.78,21 18.5,19.37 18.5,17.32C18.5,15.82 17.72,14.53 16.5,13.77C16.2,13.59 15.9,13.44 15.6,13.32V10.79M10,6.5H13C13.83,6.5 14.5,7.17 14.5,8C14.5,8.83 13.83,9.5 13,9.5H10V6.5M13.5,17.5H10V14H13.5C14.33,14 15,14.67 15,15.5C15,16.33 14.33,17.5 13.5,17.5Z</StreamGeometry>
<StreamGeometry x:Key="ShareIcon">M18,16.08C17.24,16.08 16.56,16.38 16.04,16.85L8.91,12.7C8.96,12.47 9,12.24 9,12C9,11.76 8.96,11.53 8.91,11.3L15.96,7.19C16.5,7.69 17.21,8 18,8A3,3 0 0,0 21,5A3,3 0 0,0 18,2A3,3 0 0,0 15,5C15,5.24 15.04,5.47 15.09,5.7L8.04,9.81C7.5,9.31 6.79,9 6,9A3,3 0 0,0 3,12A3,3 0 0,0 6,15C6.79,15 7.5,14.69 8.04,14.19L15.16,18.34C15.11,18.55 15.08,18.77 15.08,19C15.08,20.61 16.39,21.91 18,21.91C19.61,21.91 20.92,20.61 20.92,19C20.92,17.39 19.61,16.08 18,16.08Z</StreamGeometry>
<StreamGeometry x:Key="DeleteIcon">M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z</StreamGeometry>
</UserControl.Resources>
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="240">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="How to test" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="1. Click &quot;Open overflow&quot; below, or click the ··· button with the mouse." />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="2. Use Up/Down arrow keys to navigate. Focus wraps from last to first and back." />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="3. The separator and the disabled Delete item are skipped during navigation." />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="4. Press Escape to close. Focus returns to the ··· button." />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="5. You can also Tab into the CommandBar. Focus walks through primary items and the ··· button in order." />
<Separator />
<Button Content="Open overflow"
HorizontalAlignment="Stretch"
Click="OnOpenOverflow" />
<Button Content="Clear Log"
HorizontalAlignment="Stretch"
Click="OnClearLog" />
<Separator />
<TextBlock Text="About" FontWeight="SemiBold" />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="The focus log updates as keyboard navigation moves between overflow items. Separators and disabled items are excluded from the cycle." />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<ScrollViewer>
<StackPanel Spacing="16" Margin="12,12,12,0">
<TextBlock Classes="h2">Keyboard navigation in the overflow popup: Up/Down to move, Home/End to jump, Escape to close.</TextBlock>
<CommandBar x:Name="DemoBar">
<CommandBar.PrimaryCommands>
<CommandBarButton Label="New">
<CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Save">
<CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<CommandBarButton x:Name="BtnCopy" Label="Copy" />
<CommandBarButton x:Name="BtnPaste" Label="Paste" />
<CommandBarToggleButton x:Name="BtnBold" Label="Bold">
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarSeparator />
<CommandBarButton x:Name="BtnShare" Label="Share">
<CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton x:Name="BtnDelete" Label="Delete" IsEnabled="False">
<CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton x:Name="BtnExport" Label="Export" />
</CommandBar.SecondaryCommands>
</CommandBar>
<!-- Keyboard shortcuts reference -->
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
Padding="10">
<StackPanel Spacing="6">
<TextBlock Text="Keyboard shortcuts" FontWeight="SemiBold" />
<Grid ColumnDefinitions="80,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" FontFamily="Consolas,Menlo,monospace" FontSize="12" Text="Down" />
<TextBlock Grid.Row="0" Grid.Column="1" FontSize="12" Opacity="0.7" Text="Next item (wraps to first)" />
<TextBlock Grid.Row="1" Grid.Column="0" FontFamily="Consolas,Menlo,monospace" FontSize="12" Text="Up" />
<TextBlock Grid.Row="1" Grid.Column="1" FontSize="12" Opacity="0.7" Text="Previous item (wraps to last)" />
<TextBlock Grid.Row="2" Grid.Column="0" FontFamily="Consolas,Menlo,monospace" FontSize="12" Text="Home" />
<TextBlock Grid.Row="2" Grid.Column="1" FontSize="12" Opacity="0.7" Text="First item" />
<TextBlock Grid.Row="3" Grid.Column="0" FontFamily="Consolas,Menlo,monospace" FontSize="12" Text="End" />
<TextBlock Grid.Row="3" Grid.Column="1" FontSize="12" Opacity="0.7" Text="Last item" />
<TextBlock Grid.Row="4" Grid.Column="0" FontFamily="Consolas,Menlo,monospace" FontSize="12" Text="Escape" />
<TextBlock Grid.Row="4" Grid.Column="1" FontSize="12" Opacity="0.7" Text="Close menu, focus returns to ··· button" />
</Grid>
</StackPanel>
</Border>
<!-- Focus log -->
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
Padding="10">
<StackPanel Spacing="6">
<TextBlock Text="Focus log" FontWeight="SemiBold" />
<TextBlock x:Name="FocusLogText"
FontFamily="Consolas, Menlo, monospace"
FontSize="12"
TextWrapping="Wrap"
MinHeight="120"
Opacity="0.8"
Text="Open the overflow menu and use keyboard navigation." />
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</DockPanel>
</UserControl>

93
samples/ControlCatalog/Pages/CommandBar/CommandBarKeyboardPage.xaml.cs

@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CommandBarKeyboardPage : UserControl
{
private readonly List<string> _log = new();
public CommandBarKeyboardPage()
{
InitializeComponent();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e)
{
DemoBar.Opened += OnOpened;
DemoBar.Closed += OnClosed;
BtnCopy.GotFocus += OnItemFocused;
BtnPaste.GotFocus += OnItemFocused;
BtnBold.GotFocus += OnItemFocused;
BtnShare.GotFocus += OnItemFocused;
BtnDelete.GotFocus += OnItemFocused;
BtnExport.GotFocus += OnItemFocused;
}
private void OnUnloaded(object? sender, RoutedEventArgs e)
{
DemoBar.Opened -= OnOpened;
DemoBar.Closed -= OnClosed;
BtnCopy.GotFocus -= OnItemFocused;
BtnPaste.GotFocus -= OnItemFocused;
BtnBold.GotFocus -= OnItemFocused;
BtnShare.GotFocus -= OnItemFocused;
BtnDelete.GotFocus -= OnItemFocused;
BtnExport.GotFocus -= OnItemFocused;
}
private void OnOpened(object? sender, RoutedEventArgs e)
=> AppendLog("Opened. Use arrow keys to navigate.");
private void OnClosed(object? sender, RoutedEventArgs e)
=> AppendLog("Closed");
private void OnItemFocused(object? sender, FocusChangedEventArgs e)
{
var label = sender switch
{
CommandBarButton btn => btn.Label ?? "(unnamed)",
CommandBarToggleButton t => t.Label ?? "(unnamed)",
_ => sender?.GetType().Name ?? "?"
};
var method = e.NavigationMethod switch
{
NavigationMethod.Directional => "arrow key",
NavigationMethod.Tab => "Tab",
NavigationMethod.Pointer => "pointer",
_ => "unspecified"
};
AppendLog($"Focus: {label} ({method})");
}
private void OnOpenOverflow(object? sender, RoutedEventArgs e)
{
DemoBar.IsOpen = true;
}
private void OnClearLog(object? sender, RoutedEventArgs e)
{
_log.Clear();
FocusLogText.Text = "Log cleared.";
}
private void AppendLog(string message)
{
_log.Add(message);
if (_log.Count > 10)
_log.RemoveAt(0);
FocusLogText.Text = string.Join("\n", _log.Select((entry, i) => $"{i + 1,2}. {entry}"));
}
}
}

24
samples/ControlCatalog/Pages/CommandBar/CommandBarLabelPositionPage.xaml

@ -15,10 +15,10 @@
<TextBlock Text="Bottom (default)" FontWeight="SemiBold" />
<TextBlock Text="Label appears below the icon." FontSize="12" Opacity="0.7" />
<CommandBar DefaultLabelPosition="Bottom" OverflowButtonVisibility="Collapsed">
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Share"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Delete"><CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
<Separator />
@ -26,10 +26,10 @@
<TextBlock Text="Right" FontWeight="SemiBold" />
<TextBlock Text="Label appears to the right of the icon." FontSize="12" Opacity="0.7" />
<CommandBar DefaultLabelPosition="Right" OverflowButtonVisibility="Collapsed">
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Share"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Delete"><CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
<Separator />
@ -37,10 +37,10 @@
<TextBlock Text="Collapsed (icon only)" FontWeight="SemiBold" />
<TextBlock Text="No label shown. Use ToolTip.Tip to preserve accessibility." FontSize="12" Opacity="0.7" />
<CommandBar DefaultLabelPosition="Collapsed" OverflowButtonVisibility="Collapsed">
<AppBarButton ToolTip.Tip="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton ToolTip.Tip="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton ToolTip.Tip="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton ToolTip.Tip="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton ToolTip.Tip="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton ToolTip.Tip="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton ToolTip.Tip="Share"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton ToolTip.Tip="Delete"><CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar>
</StackPanel>
</ScrollViewer>

10
samples/ControlCatalog/Pages/CommandBar/CommandBarOverflowPage.xaml

@ -59,13 +59,13 @@
<CommandBar x:Name="DemoBar" IsDynamicOverflowEnabled="True">
<CommandBar.PrimaryCommands>
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="New"><CommandBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Save"><CommandBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Share"><CommandBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<AppBarButton Label="Export"><AppBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
<CommandBarButton Label="Export"><CommandBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></CommandBarButton.Icon></CommandBarButton>
<CommandBarButton Label="Delete"><CommandBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></CommandBarButton.Icon></CommandBarButton>
</CommandBar.SecondaryCommands>
</CommandBar>
</StackPanel>

4
samples/ControlCatalog/Pages/CommandBar/CommandBarOverflowPage.xaml.cs

@ -42,13 +42,13 @@ namespace ControlCatalog.Pages
private void OnAddPrimary(object? sender, RoutedEventArgs e)
{
_primaryCount++;
DemoBar.PrimaryCommands.Add(new AppBarButton { Label = $"Cmd {_primaryCount}" });
DemoBar.PrimaryCommands.Add(new CommandBarButton { Label = $"Cmd {_primaryCount}" });
}
private void OnAddSecondary(object? sender, RoutedEventArgs e)
{
_secondaryCount++;
DemoBar.SecondaryCommands.Add(new AppBarButton { Label = $"Sec {_secondaryCount}" });
DemoBar.SecondaryCommands.Add(new CommandBarButton { Label = $"Sec {_secondaryCount}" });
}
}
}

28
samples/ControlCatalog/Pages/CommandBar/CommandBarTogglePage.xaml

@ -28,7 +28,7 @@
<Separator />
<TextBlock Text="About" FontWeight="SemiBold" />
<TextBlock Text="AppBarToggleButton maintains checked/unchecked state. When checked, it shows a highlight background. Bind IsChecked to a boolean property."
<TextBlock Text="CommandBarToggleButton maintains checked/unchecked state. When checked, it shows a highlight background. Bind IsChecked to a boolean property."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
@ -37,25 +37,25 @@
<ScrollViewer>
<StackPanel Spacing="12" Margin="12,12,12,0">
<TextBlock Classes="h2">AppBarToggleButton supports on/off states for formatting and feature toggles.</TextBlock>
<TextBlock Classes="h2">CommandBarToggleButton supports on/off states for formatting and feature toggles.</TextBlock>
<TextBlock Text="Text Formatting" FontWeight="SemiBold" />
<CommandBar x:Name="FormatBar" OverflowButtonVisibility="Collapsed">
<AppBarToggleButton x:Name="BoldToggle"
<CommandBarToggleButton x:Name="BoldToggle"
Label="Bold"
IsCheckedChanged="OnFormatChanged">
<AppBarToggleButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></AppBarToggleButton.Icon>
</AppBarToggleButton>
<AppBarToggleButton x:Name="ItalicToggle"
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource BoldIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarToggleButton x:Name="ItalicToggle"
Label="Italic"
IsCheckedChanged="OnFormatChanged">
<AppBarToggleButton.Icon><PathIcon Data="{StaticResource ItalicIcon}" /></AppBarToggleButton.Icon>
</AppBarToggleButton>
<AppBarToggleButton x:Name="UnderlineToggle"
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource ItalicIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarToggleButton x:Name="UnderlineToggle"
Label="Underline"
IsCheckedChanged="OnFormatChanged">
<AppBarToggleButton.Icon><PathIcon Data="{StaticResource UnderlineIcon}" /></AppBarToggleButton.Icon>
</AppBarToggleButton>
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource UnderlineIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
</CommandBar>
<TextBlock x:Name="FormatStatus"
@ -67,9 +67,9 @@
<TextBlock Text="Favorite" FontWeight="SemiBold" />
<CommandBar OverflowButtonVisibility="Collapsed">
<AppBarToggleButton Label="Favorite">
<AppBarToggleButton.Icon><PathIcon Data="{StaticResource FavoriteIcon}" /></AppBarToggleButton.Icon>
</AppBarToggleButton>
<CommandBarToggleButton Label="Favorite">
<CommandBarToggleButton.Icon><PathIcon Data="{StaticResource FavoriteIcon}" /></CommandBarToggleButton.Icon>
</CommandBarToggleButton>
</CommandBar>
</StackPanel>
</ScrollViewer>

3
samples/ControlCatalog/Pages/CommandBarPage.xaml.cs

@ -13,7 +13,7 @@ namespace ControlCatalog.Pages
{
// Overview
("Overview", "First Look", "A CommandBar with primary commands, secondary overflow menu, and custom content area.", () => new CommandBarFirstLookPage()),
("Overview", "Toggle Buttons", "AppBarToggleButton for stateful actions like Bold, Italic, and Favorite.", () => new CommandBarTogglePage()),
("Overview", "Toggle Buttons", "CommandBarToggleButton for stateful actions like Bold, Italic, and Favorite.", () => new CommandBarTogglePage()),
// Appearance
("Appearance", "Label Positions", "Configure label position: Bottom (default), Right, or Collapsed (icon only).", () => new CommandBarLabelPositionPage()),
@ -23,6 +23,7 @@ namespace ControlCatalog.Pages
("Features", "Overflow Menu", "Secondary commands appear in an overflow popup. Configure visibility and sticky behavior.", () => new CommandBarOverflowPage()),
("Features", "Dynamic Overflow", "IsDynamicOverflowEnabled moves primary commands to overflow as space shrinks.", () => new CommandBarDynamicOverflowPage()),
("Features", "Events & State", "Observe Opening, Opened, Closing, and Closed while tracking IsOpen, HasSecondaryCommands, and IsOverflowButtonVisible.", () => new CommandBarEventsPage()),
("Features", "Keyboard Navigation", "Up/Down to move between overflow items, Home/End to jump to first/last, Escape to close and return focus.", () => new CommandBarKeyboardPage()),
};
public CommandBarPage()

20
samples/ControlCatalog/Pages/ContentPage/ContentPageCommandBarPage.xaml.cs

@ -78,7 +78,7 @@ namespace ControlCatalog.Pages
private void OnAddPrimary(object? sender, RoutedEventArgs e)
{
_itemCounter++;
var btn = new AppBarButton { Label = $"Action {_itemCounter}" };
var btn = new CommandBarButton { Label = $"Action {_itemCounter}" };
if (UseIconCheck.IsChecked == true)
{
var preset = IconPresets[(_itemCounter - 1) % IconPresets.Length];
@ -93,13 +93,13 @@ namespace ControlCatalog.Pages
private void OnAddSecondary(object? sender, RoutedEventArgs e)
{
_itemCounter++;
_secondaryItems.Add(new AppBarButton { Label = $"Item {_itemCounter}" });
_secondaryItems.Add(new CommandBarButton { Label = $"Item {_itemCounter}" });
RebuildCommandBar();
}
private void OnAddSeparator(object? sender, RoutedEventArgs e)
{
_primaryItems.Add(new AppBarSeparator());
_primaryItems.Add(new CommandBarSeparator());
RebuildCommandBar();
}
@ -177,26 +177,26 @@ namespace ControlCatalog.Pages
foreach (var item in _primaryItems)
{
if (item is AppBarButton btn)
if (item is CommandBarButton btn)
{
PathIcon? icon = null;
if (btn.Icon is PathIcon src)
icon = new PathIcon { Data = src.Data };
commandBar.PrimaryCommands.Add(new AppBarButton
commandBar.PrimaryCommands.Add(new CommandBarButton
{
Label = btn.Label,
Icon = icon,
IsCompact = btn.IsCompact,
});
}
else if (item is AppBarSeparator)
commandBar.PrimaryCommands.Add(new AppBarSeparator());
else if (item is CommandBarSeparator)
commandBar.PrimaryCommands.Add(new CommandBarSeparator());
}
foreach (var item in _secondaryItems)
{
if (item is AppBarButton btn)
commandBar.SecondaryCommands.Add(new AppBarButton { Label = btn.Label });
if (item is CommandBarButton btn)
commandBar.SecondaryCommands.Add(new CommandBarButton { Label = btn.Label });
}
if (_position == "Top")
@ -204,7 +204,7 @@ namespace ControlCatalog.Pages
else
NavigationPage.SetBottomCommandBar(activePage, commandBar);
var primaryCount = _primaryItems.Count(i => i is AppBarButton);
var primaryCount = _primaryItems.Count(i => i is CommandBarButton);
var secondaryCount = _secondaryItems.Count;
StatusText.Text = $"{primaryCount} primary, {secondaryCount} secondary ({_position})";
}

16
samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml

@ -72,6 +72,14 @@
<ComboBoxItem Content="Purple" />
</ComboBox>
<TextBlock Text="Header Template" FontSize="12" Opacity="0.7" />
<ComboBox x:Name="HeaderTemplateCombo" SelectedIndex="0"
SelectionChanged="OnHeaderTemplateChanged" HorizontalAlignment="Stretch">
<ComboBoxItem Content="None (direct control)" />
<ComboBoxItem Content="Banner" />
<ComboBoxItem Content="Avatar card" />
</ComboBox>
<TextBlock Text="Footer Background" FontSize="12" Opacity="0.7" />
<ComboBox x:Name="FooterBgCombo" SelectedIndex="0"
SelectionChanged="OnFooterBgChanged" HorizontalAlignment="Stretch">
@ -82,6 +90,14 @@
<ComboBoxItem Content="Maroon" />
</ComboBox>
<TextBlock Text="Footer Template" FontSize="12" Opacity="0.7" />
<ComboBox x:Name="FooterTemplateCombo" SelectedIndex="0"
SelectionChanged="OnFooterTemplateChanged" HorizontalAlignment="Stretch">
<ComboBoxItem Content="None (direct control)" />
<ComboBoxItem Content="Version badge" />
<ComboBoxItem Content="Icon + label" />
</ComboBox>
<TextBlock Text="Drawer Icon" FontSize="12" Opacity="0.7" />
<ComboBox x:Name="IconCombo" SelectedIndex="0"
SelectionChanged="OnIconChanged" HorizontalAlignment="Stretch">

127
samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml.cs

@ -1,8 +1,10 @@
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
namespace ControlCatalog.Pages
@ -143,7 +145,7 @@ namespace ControlCatalog.Pages
{
if (!_isLoaded)
return;
DemoDrawer.DrawerIcon = Geometry.Parse(_iconPaths[IconCombo.SelectedIndex]);
DemoDrawer.DrawerIcon = new PathIcon { Data = Geometry.Parse(_iconPaths[IconCombo.SelectedIndex]) };
}
private void OnBackdropChanged(object? sender, SelectionChangedEventArgs e)
@ -164,7 +166,7 @@ namespace ControlCatalog.Pages
if (!_isLoaded)
return;
if (ShowHeaderCheck.IsChecked == true)
DemoDrawer.DrawerHeader = DrawerHeaderBorder;
DemoDrawer.DrawerHeader = HeaderTemplateCombo.SelectedIndex == 0 ? DrawerHeaderBorder : (object)"My Application";
else
DemoDrawer.DrawerHeader = null;
}
@ -174,9 +176,128 @@ namespace ControlCatalog.Pages
if (!_isLoaded)
return;
if (ShowFooterCheck.IsChecked == true)
DemoDrawer.DrawerFooter = DrawerFooterBorder;
{
DemoDrawer.DrawerFooter = FooterTemplateCombo.SelectedIndex switch
{
1 => (object)"v12.0",
2 => (object)"Avalonia",
_ => DrawerFooterBorder
};
}
else
{
DemoDrawer.DrawerFooter = null;
}
}
private void OnHeaderTemplateChanged(object? sender, SelectionChangedEventArgs e)
{
if (!_isLoaded)
return;
switch (HeaderTemplateCombo.SelectedIndex)
{
case 1:
DemoDrawer.DrawerHeader = "My Application";
DemoDrawer.DrawerHeaderTemplate = new FuncDataTemplate<string>((data, _) =>
new Border
{
Padding = new Avalonia.Thickness(16),
Child = new StackPanel
{
Spacing = 2,
Children =
{
new TextBlock { Text = data, FontSize = 18, FontWeight = FontWeight.SemiBold, Foreground = Brushes.White },
new TextBlock { Text = "Navigation", FontSize = 12, Foreground = Brushes.White, Opacity = 0.7 }
}
}
});
break;
case 2:
DemoDrawer.DrawerHeader = "My Application";
DemoDrawer.DrawerHeaderTemplate = new FuncDataTemplate<string>((data, _) =>
{
var initial = data?.Length > 0 ? data[0].ToString().ToUpperInvariant() : "?";
var avatar = new Border
{
Width = 40,
Height = 40,
CornerRadius = new Avalonia.CornerRadius(20),
Background = new SolidColorBrush(Color.Parse("#1976D2")),
Child = new TextBlock
{
Text = initial,
FontSize = 18,
FontWeight = FontWeight.Bold,
Foreground = Brushes.White,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
}
};
var label = new TextBlock { Text = data, FontSize = 14, FontWeight = FontWeight.SemiBold, VerticalAlignment = VerticalAlignment.Center };
var row = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 10 };
row.Children.Add(avatar);
row.Children.Add(label);
return new Border { Padding = new Avalonia.Thickness(12), Child = row };
});
break;
default:
DemoDrawer.DrawerHeader = DrawerHeaderBorder;
DemoDrawer.DrawerHeaderTemplate = null;
break;
}
}
private void OnFooterTemplateChanged(object? sender, SelectionChangedEventArgs e)
{
if (!_isLoaded)
return;
switch (FooterTemplateCombo.SelectedIndex)
{
case 1:
DemoDrawer.DrawerFooter = "v12.0";
DemoDrawer.DrawerFooterTemplate = new FuncDataTemplate<string>((data, _) =>
new Border
{
Padding = new Avalonia.Thickness(12, 8),
Child = new Border
{
Padding = new Avalonia.Thickness(8, 4),
CornerRadius = new Avalonia.CornerRadius(4),
Background = new SolidColorBrush(Color.Parse("#1976D2")),
Child = new TextBlock { Text = data, FontSize = 11, Foreground = Brushes.White, FontWeight = FontWeight.SemiBold }
}
});
break;
case 2:
DemoDrawer.DrawerFooter = "Avalonia";
DemoDrawer.DrawerFooterTemplate = new FuncDataTemplate<string>((data, _) =>
{
var icon = new PathIcon
{
Width = 14,
Height = 14,
Data = Geometry.Parse("M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"),
Opacity = 0.5
};
var label = new TextBlock { Text = data, FontSize = 12, Opacity = 0.6, VerticalAlignment = VerticalAlignment.Center };
var row = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 6 };
row.Children.Add(icon);
row.Children.Add(label);
return new Border { Padding = new Avalonia.Thickness(14, 10), Child = row };
});
break;
default:
DemoDrawer.DrawerFooter = DrawerFooterBorder;
DemoDrawer.DrawerFooterTemplate = null;
break;
}
}
private void OnMenuItemClick(object? sender, RoutedEventArgs e)

8
samples/ControlCatalog/Pages/DrawerPage/EcoTrackerAppPage.xaml

@ -52,13 +52,9 @@
</DrawerPage.Resources>
<DrawerPage.DrawerIcon>
<StreamGeometry>M12 3C9 6 6 9 6 13C6 17.4 8.7 21 12 22C15.3 21 18 17.4 18 13C18 9 15 6 12 3Z</StreamGeometry>
<PathIcon Width="22" Height="22"
Data="M12 3C9 6 6 9 6 13C6 17.4 8.7 21 12 22C15.3 21 18 17.4 18 13C18 9 15 6 12 3Z" />
</DrawerPage.DrawerIcon>
<DrawerPage.DrawerIconTemplate>
<DataTemplate DataType="Geometry">
<PathIcon Width="22" Height="22" Data="{Binding}" />
</DataTemplate>
</DrawerPage.DrawerIconTemplate>
<DrawerPage.DrawerHeader>
<StackPanel Background="{StaticResource EcoDrawerBg}" Margin="0,0,0,8">

215
samples/ControlCatalog/Pages/GesturePage.cs

@ -1,214 +1,39 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Rendering.Composition;
using Avalonia.Utilities;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class GesturePage : UserControl
{
private bool _isInit;
private double _currentScale;
public GesturePage()
{
InitializeComponent();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
private static readonly (string Group, string Title, string Description, Func<UserControl> Factory)[] Demos =
{
base.OnAttachedToVisualTree(e);
if (_isInit)
{
return;
}
_isInit = true;
SetPullHandlers(TopPullZone, false);
SetPullHandlers(BottomPullZone, true);
SetPullHandlers(RightPullZone, true);
SetPullHandlers(LeftPullZone, false);
var image = PinchImage;
SetPinchHandlers(image);
var reset = ResetButton;
("Touch / Pen", "Pull Gesture",
"Press and drag from colored border zones. A green ball tracks the pull delta and springs back on release.",
() => new GesturePullPage()),
reset.Click += (_, _) =>
{
var compositionVisual = ElementComposition.GetElementVisual(image);
("Multi Touch", "Pinch / Zoom",
"Pinch to scale an image using composition visuals. Scroll to pan when zoomed in.",
() => new GesturePinchZoomPage()),
if (compositionVisual != null)
{
_currentScale = 1;
compositionVisual.Scale = new(1, 1, 1);
compositionVisual.Offset = default;
image.InvalidateMeasure();
}
};
("Multi Touch", "Pinch / Rotation",
"Pinch to rotate a rectangle. The Angle property from the pinch event drives a RotateTransform.",
() => new GesturePinchRotationPage()),
RotationGesture.AddHandler(InputElement.PinchEvent, (s, e) =>
{
AngleSlider.Value = e.Angle;
});
}
("Touch / Pen / Mouse", "Swipe Gesture",
"Swipe horizontally or vertically. Configure direction, threshold, and mouse support. Shows live delta, velocity, and direction.",
() => new GestureSwipePage()),
};
private void SetPinchHandlers(Control? control)
public GesturePage()
{
if (control == null)
{
return;
}
_currentScale = 1;
Vector3D currentOffset = default;
CompositionVisual? compositionVisual = null;
void InitComposition(Control visual)
{
if (compositionVisual != null)
{
return;
}
compositionVisual = ElementComposition.GetElementVisual(visual);
}
control.LayoutUpdated += (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null)
{
compositionVisual.Scale = new(_currentScale, _currentScale, 1);
if (currentOffset == default)
{
currentOffset = compositionVisual.Offset;
}
}
};
control.AddHandler(InputElement.PinchEvent, (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null)
{
var scale = _currentScale * (float)e.Scale;
if (scale <= 1)
{
scale = 1;
compositionVisual.Offset = default;
}
compositionVisual.Scale = new(scale, scale, 1);
e.Handled = true;
}
});
control.AddHandler(InputElement.PinchEndedEvent, (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null)
{
_currentScale = compositionVisual.Scale.X;
}
});
control.AddHandler(InputElement.ScrollGestureEvent, (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null && _currentScale != 1)
{
currentOffset += new Vector3D(e.Delta.X, e.Delta.Y, 0);
var currentSize = control.Bounds.Size * _currentScale;
currentOffset = new Vector3D(Math.Clamp(currentOffset.X, 0, currentSize.Width - control.Bounds.Width),
(float)Math.Clamp(currentOffset.Y, 0, currentSize.Height - control.Bounds.Height),
0);
compositionVisual.Offset = currentOffset * -1;
e.Handled = true;
}
});
InitializeComponent();
Loaded += OnLoaded;
}
private void SetPullHandlers(Control control, bool inverse)
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
var ball = control.FindLogicalDescendantOfType<Border>();
Vector3D defaultOffset = default;
CompositionVisual? ballCompositionVisual = null;
if (ball != null)
{
InitComposition(ball);
}
else
{
return;
}
control.LayoutUpdated += (s, e) =>
{
InitComposition(ball!);
if (ballCompositionVisual != null)
{
defaultOffset = ballCompositionVisual.Offset;
}
};
control.AddHandler(InputElement.PullGestureEvent, (s, e) =>
{
Vector3D center = new((float)control.Bounds.Center.X, (float)control.Bounds.Center.Y, 0);
InitComposition(ball!);
if (ballCompositionVisual != null)
{
ballCompositionVisual.Offset = defaultOffset + new Vector3D(e.Delta.X * 0.4f, e.Delta.Y * 0.4f, 0) * (inverse ? -1 : 1);
e.Handled = true;
}
});
control.AddHandler(InputElement.PullGestureEndedEvent, (s, e) =>
{
InitComposition(ball!);
if (ballCompositionVisual != null)
{
ballCompositionVisual.Offset = defaultOffset;
}
});
void InitComposition(Control control)
{
ballCompositionVisual = ElementComposition.GetElementVisual(ball);
if (ballCompositionVisual != null)
{
var offsetAnimation = ballCompositionVisual.Compositor.CreateVector3KeyFrameAnimation();
offsetAnimation.Target = "Offset";
offsetAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");
offsetAnimation.Duration = TimeSpan.FromMilliseconds(100);
var implicitAnimations = ballCompositionVisual.Compositor.CreateImplicitAnimationCollection();
implicitAnimations["Offset"] = offsetAnimation;
ballCompositionVisual.ImplicitAnimations = implicitAnimations;
}
}
await SampleNav.PushAsync(NavigationDemoHelper.CreateGalleryHomePage(SampleNav, Demos), null);
}
}
}

173
samples/ControlCatalog/Pages/GesturePage.xaml

@ -1,170 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DesignHeight="800"
d:DesignWidth="400"
x:Class="ControlCatalog.Pages.GesturePage">
<TabControl>
<TabItem>
<TabItem.Header>
<TextBlock FontWeight="Bold"
FontSize="18"
Margin="5">Pull Gexture (Touch / Pen)</TextBlock>
</TabItem.Header>
<StackPanel>
<TextBlock Margin="5">Pull from colored rectangles</TextBlock>
<Border>
<DockPanel HorizontalAlignment="Stretch"
ClipToBounds="True"
Margin="5"
Height="200">
<Border DockPanel.Dock="Top"
Margin="2"
Name="TopPullZone"
Background="Transparent"
BorderBrush="Red"
HorizontalAlignment="Stretch"
Height="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="TopToBottom"/>
</Border.GestureRecognizers>
<Border Width="10"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
Name="TopBall"
Background="Green"/>
</Border>
<Border DockPanel.Dock="Bottom"
BorderBrush="Green"
Margin="2"
Background="Transparent"
Name="BottomPullZone"
HorizontalAlignment="Stretch"
Height="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="BottomToTop"/>
</Border.GestureRecognizers>
<Border Width="10"
Name="BottomBall"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="10"
CornerRadius="5"
Background="Green"/>
</Border>
<Border DockPanel.Dock="Right"
Margin="2"
Background="Transparent"
Name="RightPullZone"
BorderBrush="Blue"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Width="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="RightToLeft"/>
</Border.GestureRecognizers>
<Border Width="10"
Height="10"
Name="RightBall"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
Background="Green"/>
</Border>
<Border DockPanel.Dock="Left"
Margin="2"
Background="Transparent"
Name="LeftPullZone"
BorderBrush="Orange"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Width="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="LeftToRight"/>
</Border.GestureRecognizers>
<Border Width="10"
Height="10"
Name="LeftBall"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
Background="Green"/>
</Border>
</DockPanel>
</Border>
</StackPanel>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock FontWeight="Bold"
FontSize="18"
Margin="5">Pinch/Zoom Gexture (Multi Touch)</TextBlock>
</TabItem.Header>
<StackPanel>
<Border ClipToBounds="True">
<Image Stretch="UniformToFill"
Margin="5"
Name="PinchImage"
Source="/Assets/delicate-arch-896885_640.jpg">
<Image.GestureRecognizers>
<PinchGestureRecognizer/>
<ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True"/>
</Image.GestureRecognizers>
</Image>
</Border>
<Button HorizontalAlignment="Center" Name="ResetButton">Reset</Button>
</StackPanel>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock FontWeight="Bold"
FontSize="18"
Margin="5">Pinch/Rotation Gexture (Multi Touch)</TextBlock>
</TabItem.Header>
<DockPanel>
<Slider Minimum="0"
Maximum="360"
DockPanel.Dock="Bottom"
x:Name="AngleSlider"
/>
<Panel x:Name="RotationGesture">
<Panel.GestureRecognizers>
<PinchGestureRecognizer/>
</Panel.GestureRecognizers>
<Border BorderThickness="1.5" BorderBrush="LawnGreen"/>
<Panel HorizontalAlignment="Center"
Width="100"
Height="100">
<Panel.RenderTransform>
<RotateTransform Angle="{Binding #AngleSlider.Value}"/>
</Panel.RenderTransform>
<Rectangle Fill="SkyBlue"/>
<Rectangle HorizontalAlignment="Center"
VerticalAlignment="Top"
Fill="Yellow"
Width="5"
Height="35"/>
</Panel>
<TextBlock Text="{Binding #AngleSlider.Value, StringFormat=0°}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontWeight="DemiBold"
FontSize="20"
/>
</Panel>
</DockPanel>
</TabItem>
</TabControl>
<NavigationPage x:Name="SampleNav">
<NavigationPage.Styles>
<Style Selector="NavigationPage#SampleNav /template/ Border#PART_NavigationBar">
<Setter Property="Background" Value="Transparent" />
</Style>
</NavigationPage.Styles>
</NavigationPage>
</UserControl>

59
samples/ControlCatalog/Pages/Gestures/GesturePinchRotationPage.xaml

@ -0,0 +1,59 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.GesturePinchRotationPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="How It Works" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="A PinchGestureRecognizer raises Pinch events that include an Angle property. The angle is applied to a RotateTransform on the inner panel." />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Use the slider below to manually adjust the rotation angle, or use a multi-touch pinch/twist gesture." />
<Separator />
<TextBlock Text="API" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="PinchEventArgs.Angle" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="The rotation angle in degrees from the pinch gesture." />
</StackPanel>
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<DockPanel Margin="12">
<Slider Minimum="0"
Maximum="360"
DockPanel.Dock="Bottom"
x:Name="AngleSlider" />
<Panel x:Name="RotationGesture">
<Panel.GestureRecognizers>
<PinchGestureRecognizer/>
</Panel.GestureRecognizers>
<Border BorderThickness="1.5" BorderBrush="LawnGreen"/>
<Panel HorizontalAlignment="Center"
Width="100"
Height="100">
<Panel.RenderTransform>
<RotateTransform Angle="{Binding #AngleSlider.Value}"/>
</Panel.RenderTransform>
<Rectangle Fill="SkyBlue"/>
<Rectangle HorizontalAlignment="Center"
VerticalAlignment="Top"
Fill="Yellow"
Width="5"
Height="35"/>
</Panel>
<TextBlock Text="{Binding #AngleSlider.Value, StringFormat={}{0:F0}\°}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontWeight="DemiBold"
FontSize="20" />
</Panel>
</DockPanel>
</DockPanel>
</UserControl>

33
samples/ControlCatalog/Pages/Gestures/GesturePinchRotationPage.xaml.cs

@ -0,0 +1,33 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
namespace ControlCatalog.Pages
{
public partial class GesturePinchRotationPage : UserControl
{
private bool _isInit;
public GesturePinchRotationPage()
{
InitializeComponent();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isInit)
{
return;
}
_isInit = true;
RotationGesture.AddHandler(InputElement.PinchEvent, (s, e) =>
{
AngleSlider.Value = e.Angle;
});
}
}
}

51
samples/ControlCatalog/Pages/Gestures/GesturePinchZoomPage.xaml

@ -0,0 +1,51 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.GesturePinchZoomPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="How It Works" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Attach a PinchGestureRecognizer and a ScrollGestureRecognizer to an image. Pinch to zoom in and out, then scroll to pan when zoomed." />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="The composition visual's Scale and Offset are updated directly for smooth performance." />
<Separator />
<TextBlock Text="API" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="PinchGestureRecognizer" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="Raises Pinch (with Scale) and PinchEnded events." />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="ScrollGestureRecognizer" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="CanHorizontallyScroll / CanVerticallyScroll enable panning." />
</StackPanel>
<Separator />
<Button x:Name="ResetButton"
Content="Reset"
HorizontalAlignment="Stretch" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12" ClipToBounds="True">
<Image Stretch="UniformToFill"
Name="PinchImage"
Source="/Assets/delicate-arch-896885_640.jpg">
<Image.GestureRecognizers>
<PinchGestureRecognizer/>
<ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True"/>
</Image.GestureRecognizers>
</Image>
</Border>
</DockPanel>
</UserControl>

134
samples/ControlCatalog/Pages/Gestures/GesturePinchZoomPage.xaml.cs

@ -0,0 +1,134 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Rendering.Composition;
namespace ControlCatalog.Pages
{
public partial class GesturePinchZoomPage : UserControl
{
private bool _isInit;
private double _currentScale;
public GesturePinchZoomPage()
{
InitializeComponent();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isInit)
{
return;
}
_isInit = true;
var image = PinchImage;
SetPinchHandlers(image);
ResetButton.Click += (_, _) =>
{
var compositionVisual = ElementComposition.GetElementVisual(image);
if (compositionVisual != null)
{
_currentScale = 1;
compositionVisual.Scale = new(1, 1, 1);
compositionVisual.Offset = default;
image.InvalidateMeasure();
}
};
}
private void SetPinchHandlers(Control? control)
{
if (control == null)
{
return;
}
_currentScale = 1;
Vector3D currentOffset = default;
CompositionVisual? compositionVisual = null;
void InitComposition(Control visual)
{
if (compositionVisual != null)
{
return;
}
compositionVisual = ElementComposition.GetElementVisual(visual);
}
control.LayoutUpdated += (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null)
{
compositionVisual.Scale = new(_currentScale, _currentScale, 1);
if (currentOffset == default)
{
currentOffset = compositionVisual.Offset;
}
}
};
control.AddHandler(InputElement.PinchEvent, (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null)
{
var scale = _currentScale * (float)e.Scale;
if (scale <= 1)
{
scale = 1;
compositionVisual.Offset = default;
}
compositionVisual.Scale = new(scale, scale, 1);
e.Handled = true;
}
});
control.AddHandler(InputElement.PinchEndedEvent, (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null)
{
_currentScale = compositionVisual.Scale.X;
}
});
control.AddHandler(InputElement.ScrollGestureEvent, (s, e) =>
{
InitComposition(control!);
if (compositionVisual != null && _currentScale != 1)
{
currentOffset += new Vector3D(e.Delta.X, e.Delta.Y, 0);
var currentSize = control.Bounds.Size * _currentScale;
currentOffset = new Vector3D(Math.Clamp(currentOffset.X, 0, currentSize.Width - control.Bounds.Width),
(float)Math.Clamp(currentOffset.Y, 0, currentSize.Height - control.Bounds.Height),
0);
compositionVisual.Offset = currentOffset * -1;
e.Handled = true;
}
});
}
}
}

113
samples/ControlCatalog/Pages/Gestures/GesturePullPage.xaml

@ -0,0 +1,113 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.GesturePullPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="How It Works" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Attach a PullGestureRecognizer to any control. Press and drag in the specified pull direction to fire PullGesture events with a delta vector." />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="When the pointer is released, PullGestureEnded fires so the control can spring back." />
<Separator />
<TextBlock Text="API" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="PullDirection" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="TopToBottom, BottomToTop, LeftToRight, or RightToLeft." />
</StackPanel>
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12">
<DockPanel HorizontalAlignment="Stretch"
ClipToBounds="True"
Height="200">
<Border DockPanel.Dock="Top"
Margin="2"
Name="TopPullZone"
Background="Transparent"
BorderBrush="Red"
HorizontalAlignment="Stretch"
Height="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="TopToBottom"/>
</Border.GestureRecognizers>
<Border Width="10"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
Name="TopBall"
Background="Green"/>
</Border>
<Border DockPanel.Dock="Bottom"
BorderBrush="Green"
Margin="2"
Background="Transparent"
Name="BottomPullZone"
HorizontalAlignment="Stretch"
Height="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="BottomToTop"/>
</Border.GestureRecognizers>
<Border Width="10"
Name="BottomBall"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="10"
CornerRadius="5"
Background="Green"/>
</Border>
<Border DockPanel.Dock="Right"
Margin="2"
Background="Transparent"
Name="RightPullZone"
BorderBrush="Blue"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Width="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="RightToLeft"/>
</Border.GestureRecognizers>
<Border Width="10"
Height="10"
Name="RightBall"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
Background="Green"/>
</Border>
<Border DockPanel.Dock="Left"
Margin="2"
Background="Transparent"
Name="LeftPullZone"
BorderBrush="Orange"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Width="50"
BorderThickness="1">
<Border.GestureRecognizers>
<PullGestureRecognizer PullDirection="LeftToRight"/>
</Border.GestureRecognizers>
<Border Width="10"
Height="10"
Name="LeftBall"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
Background="Green"/>
</Border>
</DockPanel>
</Border>
</DockPanel>
</UserControl>

100
samples/ControlCatalog/Pages/Gestures/GesturePullPage.xaml.cs

@ -0,0 +1,100 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Rendering.Composition;
namespace ControlCatalog.Pages
{
public partial class GesturePullPage : UserControl
{
private bool _isInit;
public GesturePullPage()
{
InitializeComponent();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isInit)
{
return;
}
_isInit = true;
SetPullHandlers(TopPullZone, false);
SetPullHandlers(BottomPullZone, true);
SetPullHandlers(RightPullZone, true);
SetPullHandlers(LeftPullZone, false);
}
private void SetPullHandlers(Control control, bool inverse)
{
var ball = control.FindLogicalDescendantOfType<Border>();
Vector3D defaultOffset = default;
CompositionVisual? ballCompositionVisual = null;
if (ball != null)
{
InitComposition(ball);
}
else
{
return;
}
control.LayoutUpdated += (s, e) =>
{
InitComposition(ball!);
if (ballCompositionVisual != null)
{
defaultOffset = ballCompositionVisual.Offset;
}
};
control.AddHandler(InputElement.PullGestureEvent, (s, e) =>
{
InitComposition(ball!);
if (ballCompositionVisual != null)
{
ballCompositionVisual.Offset = defaultOffset + new Vector3D(e.Delta.X * 0.4f, e.Delta.Y * 0.4f, 0) * (inverse ? -1 : 1);
e.Handled = true;
}
});
control.AddHandler(InputElement.PullGestureEndedEvent, (s, e) =>
{
InitComposition(ball!);
if (ballCompositionVisual != null)
{
ballCompositionVisual.Offset = defaultOffset;
}
});
void InitComposition(Control control)
{
ballCompositionVisual = ElementComposition.GetElementVisual(ball);
if (ballCompositionVisual != null)
{
var offsetAnimation = ballCompositionVisual.Compositor.CreateVector3KeyFrameAnimation();
offsetAnimation.Target = "Offset";
offsetAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");
offsetAnimation.Duration = TimeSpan.FromMilliseconds(100);
var implicitAnimations = ballCompositionVisual.Compositor.CreateImplicitAnimationCollection();
implicitAnimations["Offset"] = offsetAnimation;
ballCompositionVisual.ImplicitAnimations = implicitAnimations;
}
}
}
}
}

123
samples/ControlCatalog/Pages/Gestures/GestureSwipePage.xaml

@ -0,0 +1,123 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.GestureSwipePage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="How It Works" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Attach a SwipeGestureRecognizer to any control. Drag horizontally or vertically to fire SwipeGesture events with a delta vector and velocity." />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="When the pointer is released, SwipeGestureEnded fires with the final velocity so you can apply fling logic." />
<Separator />
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="14" />
<CheckBox x:Name="HorizontalCheck"
Content="CanHorizontallySwipe"
IsChecked="True"
IsCheckedChanged="OnDirectionChanged" />
<CheckBox x:Name="VerticalCheck"
Content="CanVerticallySwipe"
IsChecked="True"
IsCheckedChanged="OnDirectionChanged" />
<CheckBox x:Name="MouseCheck"
Content="IsMouseEnabled"
IsChecked="True"
IsCheckedChanged="OnMouseEnabledChanged" />
<Separator />
<TextBlock Text="Threshold" FontWeight="SemiBold" FontSize="13" />
<DockPanel>
<TextBlock x:Name="ThresholdText"
DockPanel.Dock="Right"
Text="0"
Width="30"
VerticalAlignment="Center" />
<Slider x:Name="ThresholdSlider"
Minimum="0"
Maximum="50"
Value="0"
ValueChanged="OnThresholdChanged" />
</DockPanel>
<TextBlock FontSize="11" TextWrapping="Wrap" Opacity="0.5"
Text="0 = platform default. Higher values require more movement before a swipe starts." />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="DirectionText"
Text="Direction: (none)"
Opacity="0.7" />
<TextBlock x:Name="DeltaText"
Text="Delta: 0, 0"
Opacity="0.7" />
<TextBlock x:Name="VelocityText"
Text="Velocity: 0, 0"
Opacity="0.7" />
<Separator />
<TextBlock Text="API" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="CanHorizontallySwipe" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="Enable horizontal swipe tracking." />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="CanVerticallySwipe" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="Enable vertical swipe tracking." />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="Threshold" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="Minimum pixel distance before a swipe is recognized. 0 uses platform default." />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock FontSize="13" FontFamily="Cascadia Code, Consolas, Monospace"
Text="IsMouseEnabled" />
<TextBlock FontSize="12" TextWrapping="Wrap" Opacity="0.7"
Text="Allow mouse pointer to trigger swipes (touch/pen always enabled)." />
</StackPanel>
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Panel x:Name="SwipePanel" Background="Transparent">
<Panel.GestureRecognizers>
<SwipeGestureRecognizer x:Name="SwipeRecognizer"
CanHorizontallySwipe="True"
CanVerticallySwipe="True"
IsMouseEnabled="True" />
</Panel.GestureRecognizers>
<Border x:Name="SwipeIndicator"
Width="80" Height="80"
CornerRadius="40"
Background="{DynamicResource SystemControlHighlightAccentBrush}"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock x:Name="SwipeDirectionLabel"
Text="Swipe here"
FontSize="11"
FontWeight="SemiBold"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</Panel>
</Border>
</DockPanel>
</UserControl>

125
samples/ControlCatalog/Pages/Gestures/GestureSwipePage.xaml.cs

@ -0,0 +1,125 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Controls.Primitives;
using Avalonia.Rendering.Composition;
namespace ControlCatalog.Pages
{
public partial class GestureSwipePage : UserControl
{
private bool _isInit;
private CompositionVisual? _indicatorVisual;
private Vector3D _swipeDelta;
public GestureSwipePage()
{
InitializeComponent();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isInit)
{
return;
}
_isInit = true;
SwipePanel.AddHandler(InputElement.SwipeGestureEvent, OnSwipeGesture);
SwipePanel.AddHandler(InputElement.SwipeGestureEndedEvent, OnSwipeGestureEnded);
}
private void EnsureVisual()
{
if (_indicatorVisual != null)
{
return;
}
_indicatorVisual = ElementComposition.GetElementVisual(SwipeIndicator);
if (_indicatorVisual != null)
{
var offsetAnimation = _indicatorVisual.Compositor.CreateVector3KeyFrameAnimation();
offsetAnimation.Target = "Offset";
offsetAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");
offsetAnimation.Duration = TimeSpan.FromMilliseconds(150);
var implicitAnimations = _indicatorVisual.Compositor.CreateImplicitAnimationCollection();
implicitAnimations["Offset"] = offsetAnimation;
_indicatorVisual.ImplicitAnimations = implicitAnimations;
}
}
private void OnSwipeGesture(object? sender, SwipeGestureEventArgs e)
{
EnsureVisual();
if (_indicatorVisual != null)
{
_swipeDelta += new Vector3D(-e.Delta.X, -e.Delta.Y, 0);
_indicatorVisual.Offset += new Vector3D(-e.Delta.X, -e.Delta.Y, 0);
}
DirectionText.Text = $"Direction: {e.SwipeDirection}";
DeltaText.Text = $"Delta: {e.Delta.X:F1}, {e.Delta.Y:F1}";
VelocityText.Text = $"Velocity: {e.Velocity.X:F0}, {e.Velocity.Y:F0}";
SwipeDirectionLabel.Text = e.SwipeDirection.ToString();
SwipeDirectionLabel.Opacity = 1;
e.Handled = true;
}
private void OnSwipeGestureEnded(object? sender, SwipeGestureEndedEventArgs e)
{
if (_indicatorVisual != null)
{
_indicatorVisual.Offset -= _swipeDelta;
}
_swipeDelta = default;
VelocityText.Text = $"Velocity: {e.Velocity.X:F0}, {e.Velocity.Y:F0} (ended)";
SwipeDirectionLabel.Text = "Swipe here";
SwipeDirectionLabel.Opacity = 0.5;
}
private void OnDirectionChanged(object? sender, RoutedEventArgs e)
{
if (SwipeRecognizer == null)
{
return;
}
SwipeRecognizer.CanHorizontallySwipe = HorizontalCheck.IsChecked == true;
SwipeRecognizer.CanVerticallySwipe = VerticalCheck.IsChecked == true;
}
private void OnMouseEnabledChanged(object? sender, RoutedEventArgs e)
{
if (SwipeRecognizer == null)
{
return;
}
SwipeRecognizer.IsMouseEnabled = MouseCheck.IsChecked == true;
}
private void OnThresholdChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
if (SwipeRecognizer == null || ThresholdText == null)
{
return;
}
SwipeRecognizer.Threshold = e.NewValue;
ThresholdText.Text = $"{e.NewValue:F0}";
}
}
}

51
samples/ControlCatalog/Pages/NavigationPage/LAvenirAppPage.xaml.cs

@ -59,26 +59,6 @@ public partial class LAvenirAppPage : UserControl
_infoPanel.IsVisible = Bounds.Width >= 650;
}
void ApplyRootNavigationBarAppearance()
{
if (_navPage == null)
return;
_navPage.Background = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarForeground"] = new SolidColorBrush(TextDark);
}
void ApplyDetailNavigationBarAppearance()
{
if (_navPage == null)
return;
_navPage.Background = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarForeground"] = Brushes.White;
}
TabbedPage BuildMenuTabbedPage()
{
var tp = new TabbedPage
@ -112,7 +92,6 @@ public partial class LAvenirAppPage : UserControl
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Center,
};
ApplyRootNavigationBarAppearance();
NavigationPage.SetTopCommandBar(tp, new Button
{
@ -140,7 +119,7 @@ public partial class LAvenirAppPage : UserControl
Content = menuView,
Background = new SolidColorBrush(BgLight),
Header = "Menu",
Icon = Geometry.Parse("M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z"),
Icon = new PathIcon { Data = Geometry.Parse("M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z") },
};
var reservationsPage = new ContentPage
@ -148,7 +127,7 @@ public partial class LAvenirAppPage : UserControl
Content = new LAvenirReservationsView(),
Background = new SolidColorBrush(BgLight),
Header = "Reservations",
Icon = Geometry.Parse("M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM9 10H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z"),
Icon = new PathIcon { Data = Geometry.Parse("M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM9 10H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z") },
};
var profilePage = new ContentPage
@ -156,7 +135,7 @@ public partial class LAvenirAppPage : UserControl
Content = new LAvenirProfileView(),
Background = new SolidColorBrush(BgLight),
Header = "Profile",
Icon = Geometry.Parse("M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"),
Icon = new PathIcon { Data = Geometry.Parse("M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z") },
};
tp.Pages = new ObservableCollection<Page> { menuPage, reservationsPage, profilePage };
@ -165,8 +144,7 @@ public partial class LAvenirAppPage : UserControl
async void PushDishDetail(string name, string price, string description, string imageFile)
{
if (_navPage == null)
return;
if (_navPage == null) return;
var detail = new ContentPage
{
@ -175,19 +153,22 @@ public partial class LAvenirAppPage : UserControl
Header = name,
};
NavigationPage.SetBottomCommandBar(detail, BuildFloatingBar(price));
detail.Navigating += args =>
{
if (args.NavigationType == NavigationType.Pop)
ApplyRootNavigationBarAppearance();
return Task.CompletedTask;
_navPage.Background = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarForeground"] = Brushes.White;
detail.NavigatedFrom += (_, _) =>
{
if (_navPage != null)
{
_navPage.Background = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarForeground"] = new SolidColorBrush(TextDark);
}
};
ApplyDetailNavigationBarAppearance();
await _navPage.PushAsync(detail);
if (!ReferenceEquals(_navPage.CurrentPage, detail))
ApplyRootNavigationBarAppearance();
}
Border BuildFloatingBar(string price)

16
samples/ControlCatalog/Pages/NavigationPage/NavigationPageToolbarPage.xaml.cs

@ -49,7 +49,7 @@ namespace ControlCatalog.Pages
private void OnAddPrimary(object? sender, RoutedEventArgs e)
{
_itemCount++;
_rootCommandBar.PrimaryCommands.Add(new AppBarButton
_rootCommandBar.PrimaryCommands.Add(new CommandBarButton
{
Label = $"Item {_itemCount}",
Icon = new PathIcon { Data = (Geometry)this.FindResource("AddIcon")! }
@ -60,7 +60,7 @@ namespace ControlCatalog.Pages
private void OnAddSecondary(object? sender, RoutedEventArgs e)
{
_itemCount++;
_rootCommandBar.SecondaryCommands.Add(new AppBarButton
_rootCommandBar.SecondaryCommands.Add(new CommandBarButton
{
Label = $"Secondary {_itemCount}"
});
@ -69,13 +69,13 @@ namespace ControlCatalog.Pages
private void OnAddPrimarySeparator(object? sender, RoutedEventArgs e)
{
_rootCommandBar.PrimaryCommands.Add(new AppBarSeparator());
_rootCommandBar.PrimaryCommands.Add(new CommandBarSeparator());
UpdateStatus();
}
private void OnAddSecondarySeparator(object? sender, RoutedEventArgs e)
{
_rootCommandBar.SecondaryCommands.Add(new AppBarSeparator());
_rootCommandBar.SecondaryCommands.Add(new CommandBarSeparator());
UpdateStatus();
}
@ -125,13 +125,13 @@ namespace ControlCatalog.Pages
{
PrimaryCommands =
{
new AppBarButton { Label = "Search", Icon = new PathIcon { Data = (Geometry)this.FindResource("SearchIcon")! } },
new AppBarButton { Label = "Share", Icon = new PathIcon { Data = (Geometry)this.FindResource("ShareIcon")! } },
new AppBarButton { Label = "Edit", Icon = new PathIcon { Data = (Geometry)this.FindResource("EditIcon")! } },
new CommandBarButton { Label = "Search", Icon = new PathIcon { Data = (Geometry)this.FindResource("SearchIcon")! } },
new CommandBarButton { Label = "Share", Icon = new PathIcon { Data = (Geometry)this.FindResource("ShareIcon")! } },
new CommandBarButton { Label = "Edit", Icon = new PathIcon { Data = (Geometry)this.FindResource("EditIcon")! } },
},
SecondaryCommands =
{
new AppBarButton { Label = "Delete", Icon = new PathIcon { Data = (Geometry)this.FindResource("DeleteIcon")! } }
new CommandBarButton { Label = "Delete", Icon = new PathIcon { Data = (Geometry)this.FindResource("DeleteIcon")! } }
}
};
}

6
samples/ControlCatalog/Pages/NavigationPage/PulseAppPage.xaml.cs

@ -99,7 +99,7 @@ public partial class PulseAppPage : UserControl
Content = homeView,
Background = new SolidColorBrush(BgDashboard),
Header = "Home",
Icon = Geometry.Parse("M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"),
Icon = new PathIcon { Data = Geometry.Parse("M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z") },
};
var workoutsPage = new ContentPage
@ -107,7 +107,7 @@ public partial class PulseAppPage : UserControl
Content = new PulseWorkoutsView(),
Background = new SolidColorBrush(BgDashboard),
Header = "Workouts",
Icon = Geometry.Parse("M20.57 14.86L22 13.43 20.57 12 17 15.57 8.43 7 12 3.43 10.57 2 9.14 3.43 7.71 2 5.57 4.14 4.14 2.71 2.71 4.14l1.43 1.43L2 7.71l1.43 1.43L2 10.57 3.43 12 7 8.43 15.57 17 12 20.57 13.43 22l1.43-1.43L16.29 22l2.14-2.14 1.43 1.43 1.43-1.43-1.43-1.43L22 16.29z"),
Icon = new PathIcon { Data = Geometry.Parse("M20.57 14.86L22 13.43 20.57 12 17 15.57 8.43 7 12 3.43 10.57 2 9.14 3.43 7.71 2 5.57 4.14 4.14 2.71 2.71 4.14l1.43 1.43L2 7.71l1.43 1.43L2 10.57 3.43 12 7 8.43 15.57 17 12 20.57 13.43 22l1.43-1.43L16.29 22l2.14-2.14 1.43 1.43 1.43-1.43-1.43-1.43L22 16.29z") },
};
var profilePage = new ContentPage
@ -115,7 +115,7 @@ public partial class PulseAppPage : UserControl
Content = new PulseProfileView(),
Background = new SolidColorBrush(BgDashboard),
Header = "Profile",
Icon = Geometry.Parse("M12 2C9.243 2 7 4.243 7 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5zM12 14c-5.523 0-10 3.582-10 8a1 1 0 001 1h18a1 1 0 001-1c0-4.418-4.477-8-10-8z"),
Icon = new PathIcon { Data = Geometry.Parse("M12 2C9.243 2 7 4.243 7 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5zM12 14c-5.523 0-10 3.582-10 8a1 1 0 001 1h18a1 1 0 001-1c0-4.418-4.477-8-10-8z") },
};
tp.Pages = new ObservableCollection<Page> { homePage, workoutsPage, profilePage };

43
samples/ControlCatalog/Pages/NavigationPage/RetroGamingAppPage.xaml.cs

@ -51,30 +51,11 @@ public partial class RetroGamingAppPage : UserControl
_infoPanel.IsVisible = Bounds.Width >= 650;
}
void ApplyHomeNavigationBarAppearance()
{
if (_nav == null)
return;
_nav.Resources["NavigationBarBackground"] = new SolidColorBrush(SurfaceColor);
_nav.Resources["NavigationBarForeground"] = new SolidColorBrush(CyanColor);
}
void ApplyDetailNavigationBarAppearance()
{
if (_nav == null)
return;
_nav.Resources["NavigationBarBackground"] = Brushes.Transparent;
_nav.Resources["NavigationBarForeground"] = new SolidColorBrush(CyanColor);
}
ContentPage BuildHomePage()
{
var page = new ContentPage { Background = new SolidColorBrush(BgColor) };
page.Header = BuildPixelArcadeLogo();
NavigationPage.SetTopCommandBar(page, BuildNavBarRight());
ApplyHomeNavigationBarAppearance();
var panel = new Panel();
panel.Children.Add(BuildHomeTabbedPage());
@ -193,7 +174,7 @@ public partial class RetroGamingAppPage : UserControl
var homeTab = new ContentPage
{
Header = "Home",
Icon = Geometry.Parse("M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z"),
Icon = new PathIcon { Data = Geometry.Parse("M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z") },
Background = new SolidColorBrush(BgColor),
Content = homeView,
};
@ -204,7 +185,7 @@ public partial class RetroGamingAppPage : UserControl
var gamesTab = new ContentPage
{
Header = "Games",
Icon = Geometry.Parse("M7.97,16L5,19C4.67,19.3 4.23,19.5 3.75,19.5A1.75,1.75 0 0,1 2,17.75V17.5L3,10.12C3.21,7.81 5.14,6 7.5,6H16.5C18.86,6 20.79,7.81 21,10.12L22,17.5V17.75A1.75,1.75 0 0,1 20.25,19.5C19.77,19.5 19.33,19.3 19,19L16.03,16H7.97M7,9V11H5V13H7V15H9V13H11V11H9V9H7M14.5,12A1.5,1.5 0 0,0 13,13.5A1.5,1.5 0 0,0 14.5,15A1.5,1.5 0 0,0 16,13.5A1.5,1.5 0 0,0 14.5,12M17.5,9A1.5,1.5 0 0,0 16,10.5A1.5,1.5 0 0,0 17.5,12A1.5,1.5 0 0,0 19,10.5A1.5,1.5 0 0,0 17.5,9Z"),
Icon = new PathIcon { Data = Geometry.Parse("M7.97,16L5,19C4.67,19.3 4.23,19.5 3.75,19.5A1.75,1.75 0 0,1 2,17.75V17.5L3,10.12C3.21,7.81 5.14,6 7.5,6H16.5C18.86,6 20.79,7.81 21,10.12L22,17.5V17.75A1.75,1.75 0 0,1 20.25,19.5C19.77,19.5 19.33,19.3 19,19L16.03,16H7.97M7,9V11H5V13H7V15H9V13H11V11H9V9H7M14.5,12A1.5,1.5 0 0,0 13,13.5A1.5,1.5 0 0,0 14.5,15A1.5,1.5 0 0,0 16,13.5A1.5,1.5 0 0,0 14.5,12M17.5,9A1.5,1.5 0 0,0 16,10.5A1.5,1.5 0 0,0 17.5,12A1.5,1.5 0 0,0 19,10.5A1.5,1.5 0 0,0 17.5,9Z") },
Background = new SolidColorBrush(BgColor),
Content = gamesView,
};
@ -212,7 +193,7 @@ public partial class RetroGamingAppPage : UserControl
var favTab = new ContentPage
{
Header = "Favorites",
Icon = Geometry.Parse("M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"),
Icon = new PathIcon { Data = Geometry.Parse("M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z") },
Background = new SolidColorBrush(BgColor),
Content = new RetroGamingFavoritesView(),
};
@ -220,7 +201,7 @@ public partial class RetroGamingAppPage : UserControl
var profileTab = new ContentPage
{
Header = "Profile",
Icon = Geometry.Parse("M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"),
Icon = new PathIcon { Data = Geometry.Parse("M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z") },
Background = new SolidColorBrush(BgColor),
Content = new RetroGamingProfileView(),
};
@ -279,8 +260,7 @@ public partial class RetroGamingAppPage : UserControl
async void PushDetailPage(string gameTitle)
{
if (_nav == null)
return;
if (_nav == null) return;
var detailView = new RetroGamingDetailView(gameTitle);
@ -291,13 +271,8 @@ public partial class RetroGamingAppPage : UserControl
};
NavigationPage.SetBarLayoutBehavior(page, BarLayoutBehavior.Overlay);
page.Navigating += args =>
{
if (args.NavigationType == NavigationType.Pop)
ApplyHomeNavigationBarAppearance();
return Task.CompletedTask;
};
page.NavigatedTo += (_, _) => { if (_nav != null) _nav.Resources["NavigationBarBackground"] = Brushes.Transparent; };
page.NavigatedFrom += (_, _) => { if (_nav != null) _nav.Resources["NavigationBarBackground"] = new SolidColorBrush(SurfaceColor); };
var cmdBar = new StackPanel
{
@ -326,10 +301,6 @@ public partial class RetroGamingAppPage : UserControl
cmdBar.Children.Add(shareBtn);
NavigationPage.SetTopCommandBar(page, cmdBar);
ApplyDetailNavigationBarAppearance();
await _nav.PushAsync(page);
if (!ReferenceEquals(_nav.CurrentPage, page))
ApplyHomeNavigationBarAppearance();
}
}

26
samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonsPage.xaml → samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml

@ -1,17 +1,17 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.PipsPagerCustomButtonsPage">
x:Class="ControlCatalog.Pages.PipsPagerCustomButtonThemesPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Custom Buttons" FontSize="16" FontWeight="SemiBold"
<TextBlock Text="Custom Button Themes" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Replace the default chevron navigation buttons with custom styled buttons using PreviousButtonStyle and NextButtonStyle." />
Text="Replace the default chevron navigation buttons with custom button themes using PreviousButtonTheme and NextButtonTheme." />
<Separator />
<TextBlock Text="Properties" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="PreviousButtonStyle" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="NextButtonStyle" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="PreviousButtonTheme" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="NextButtonTheme" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="IsPreviousButtonVisible" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="IsNextButtonVisible" />
</StackPanel>
@ -27,7 +27,7 @@
<PipsPager NumberOfPages="5" MaxVisiblePips="5"
IsPreviousButtonVisible="True" IsNextButtonVisible="True">
<PipsPager.Resources>
<ControlTheme x:Key="CustomPreviousButtonStyle" TargetType="Button">
<ControlTheme x:Key="CustomPreviousButtonTheme" TargetType="Button">
<Setter Property="Content" Value="Prev" />
<Setter Property="Background" Value="LightGray" />
<Setter Property="Foreground" Value="Black" />
@ -41,7 +41,7 @@
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="CustomNextButtonStyle" TargetType="Button">
<ControlTheme x:Key="CustomNextButtonTheme" TargetType="Button">
<Setter Property="Content" Value="Next" />
<Setter Property="Background" Value="LightGray" />
<Setter Property="Foreground" Value="Black" />
@ -56,12 +56,12 @@
</Setter>
</ControlTheme>
</PipsPager.Resources>
<PipsPager.PreviousButtonStyle>
<StaticResource ResourceKey="CustomPreviousButtonStyle" />
</PipsPager.PreviousButtonStyle>
<PipsPager.NextButtonStyle>
<StaticResource ResourceKey="CustomNextButtonStyle" />
</PipsPager.NextButtonStyle>
<PipsPager.PreviousButtonTheme>
<StaticResource ResourceKey="CustomPreviousButtonTheme" />
</PipsPager.PreviousButtonTheme>
<PipsPager.NextButtonTheme>
<StaticResource ResourceKey="CustomNextButtonTheme" />
</PipsPager.NextButtonTheme>
</PipsPager>
</StackPanel>

11
samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml.cs

@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace ControlCatalog.Pages;
public partial class PipsPagerCustomButtonThemesPage : UserControl
{
public PipsPagerCustomButtonThemesPage()
{
InitializeComponent();
}
}

11
samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonsPage.xaml.cs

@ -1,11 +0,0 @@
using Avalonia.Controls;
namespace ControlCatalog.Pages;
public partial class PipsPagerCustomButtonsPage : UserControl
{
public PipsPagerCustomButtonsPage()
{
InitializeComponent();
}
}

6
samples/ControlCatalog/Pages/PipsPagerPage.xaml.cs

@ -25,9 +25,9 @@ namespace ControlCatalog.Pages
("Appearance", "Custom Colors",
"Override pip indicator colors using resource keys for normal, selected, and hover states.",
() => new PipsPagerCustomColorsPage()),
("Appearance", "Custom Buttons",
"Replace the default chevron navigation buttons with custom styled buttons.",
() => new PipsPagerCustomButtonsPage()),
("Appearance", "Custom Button Themes",
"Replace the default chevron navigation buttons with custom button themes.",
() => new PipsPagerCustomButtonThemesPage()),
("Appearance", "Custom Templates",
"Override pip item templates to create squares, pills, numbers, or any custom shape.",
() => new PipsPagerCustomTemplatesPage()),

68
samples/SampleControls/HamburgerMenu/HamburgerMenu.cs

@ -1,4 +1,6 @@
using Avalonia;
using System;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
@ -8,6 +10,8 @@ namespace ControlSamples
public class HamburgerMenu : TabControl
{
private SplitView? _splitView;
private TextBox? _searchBox;
private bool _initialized;
public static readonly StyledProperty<IBrush?> PaneBackgroundProperty =
SplitView.PaneBackgroundProperty.AddOwner<HamburgerMenu>();
@ -41,6 +45,68 @@ namespace ControlSamples
base.OnApplyTemplate(e);
_splitView = e.NameScope.Find<SplitView>("PART_NavigationPane");
_searchBox = e.NameScope.Find<TextBox>("PART_SearchBox");
if (_searchBox is not null)
{
_searchBox.TextChanged += OnSearchTextChanged;
}
}
protected override void OnLoaded(Avalonia.Interactivity.RoutedEventArgs e)
{
base.OnLoaded(e);
if (!_initialized)
{
_initialized = true;
SortItems();
}
}
private void SortItems()
{
var items = Items.OfType<TabItem>().ToList();
var sorted = items.OrderBy(t => t.Header?.ToString() ?? "", StringComparer.OrdinalIgnoreCase).ToList();
// Only reorder if needed
bool needsSort = false;
for (int i = 0; i < items.Count; i++)
{
if (!ReferenceEquals(items[i], sorted[i]))
{
needsSort = true;
break;
}
}
if (needsSort)
{
Items.Clear();
foreach (var item in sorted)
{
Items.Add(item);
}
}
}
private void OnSearchTextChanged(object? sender, TextChangedEventArgs e)
{
var searchText = _searchBox?.Text;
var hasFilter = !string.IsNullOrWhiteSpace(searchText);
foreach (var item in Items.OfType<TabItem>())
{
if (hasFilter)
{
var header = item.Header?.ToString() ?? "";
item.IsVisible = header.Contains(searchText!, StringComparison.OrdinalIgnoreCase);
}
else
{
item.IsVisible = true;
}
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)

17
samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml

@ -175,10 +175,21 @@
OpenPaneLength="{StaticResource PaneExpandWidth}"
PaneBackground="Transparent">
<SplitView.Pane>
<Grid Margin="0,0,1,5" RowDefinitions="Auto, *, Auto">
<Grid Margin="0,0,1,5" RowDefinitions="Auto, Auto, *, Auto">
<Panel Height="{StaticResource HeaderHeight}" />
<TextBox x:Name="PART_SearchBox"
Grid.Row="1"
PlaceholderText="Search…"
Margin="4,0,8,4"
VerticalContentAlignment="Center">
<TextBox.InnerLeftContent>
<PathIcon Width="14" Height="14" Margin="6,0,0,0"
VerticalAlignment="Center"
Data="M10 2.5a7.5 7.5 0 0 1 5.964 12.048l4.743 4.745a1 1 0 0 1-1.32 1.497l-.094-.083-4.745-4.743A7.5 7.5 0 1 1 10 2.5Zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z" />
</TextBox.InnerLeftContent>
</TextBox>
<ScrollViewer x:Name="PART_ScrollViewer"
Grid.Row="1"
Grid.Row="2"
HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
@ -195,7 +206,7 @@
</ItemsPresenter>
</ScrollViewer>
<Button x:Name="SettingsButton"
Grid.Row="2"
Grid.Row="3"
Theme="{StaticResource NavigationButton}"
Content="Settings"
Flyout="{TemplateBinding (FlyoutBase.AttachedFlyout)}"

21
src/Android/Avalonia.Android/AndroidDispatcherImpl.cs

@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Threading;
using Android.OS;
using Avalonia.Controls.Documents;
using Avalonia.Threading;
@ -19,8 +20,7 @@ namespace Avalonia.Android
private readonly Runnable _timerSignaler;
private readonly Runnable _wakeupSignaler;
private readonly MessageQueue _queue;
private readonly object _lock = new();
private bool _signaled;
private int _signaled;
private bool _backgroundProcessingRequested;
@ -46,8 +46,7 @@ namespace Avalonia.Android
public event Action? Signaled;
private void OnSignaled()
{
lock (_lock)
_signaled = false;
Interlocked.Exchange(ref _signaled, 0);
Signaled?.Invoke();
}
@ -68,13 +67,11 @@ namespace Avalonia.Android
public void Signal()
{
lock (_lock)
if (Interlocked.CompareExchange(ref _signaled, 1, 0) != 0)
{
if(_signaled)
return;
_signaled = true;
_handler.Post(_signaler);
return;
}
_handler.Post(_signaler);
}
readonly Stopwatch _clock = Stopwatch.StartNew();
@ -133,11 +130,9 @@ namespace Avalonia.Android
// "background" jobs not being processed
// So we need to examine the queue state to prevent that scenario
lock (_lock)
if (Volatile.Read(ref _signaled) != 0)
{
// There are higher priority jobs enqueued, we'll be called again
if (_signaled)
return;
return;
}
if (CanQueryPendingInput)

17
src/Android/Avalonia.Android/AvaloniaAccessHelper.cs

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Android.OS;
using AndroidX.Core.View.Accessibility;
using AndroidX.CustomView.Widget;
@ -134,9 +134,18 @@ namespace Avalonia.Android
protected override bool OnPerformActionForVirtualView(int virtualViewId, int action, Bundle? arguments)
{
return (GetNodeInfoProvidersFromVirtualViewId(virtualViewId) ?? [])
.Select(x => TryPerformNodeAction(x, action, arguments))
.Aggregate(false, (a, b) => a | b);
var providers = GetNodeInfoProvidersFromVirtualViewId(virtualViewId);
if (providers == null)
{
return false;
}
var result = false;
foreach (var provider in providers)
{
result |= TryPerformNodeAction(provider, action, arguments);
}
return result;
}
private static bool TryPerformNodeAction(INodeInfoProvider nodeInfoProvider, int action, Bundle? arguments)

16
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -4,6 +4,7 @@ using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
@ -144,6 +145,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
private readonly TopLevelImpl _tl;
private Size _oldSize;
private double _oldScaling;
private Paint? _clearPaint;
public SurfaceViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context)
{
@ -159,11 +161,13 @@ namespace Avalonia.Android.Platform.SkiaPlatform
// can be seen below, but it does not.
if (OperatingSystem.IsAndroidVersionAtLeast(29))
{
// Android 10+ does this (BlendMode was new)
var paint = new Paint();
paint.SetColor(0);
paint.BlendMode = BlendMode.Clear;
canvas.DrawRect(0, 0, Width, Height, paint);
if (_clearPaint == null)
{
_clearPaint = new Paint();
_clearPaint.SetColor(0);
_clearPaint.BlendMode = BlendMode.Clear;
}
canvas.DrawRect(0, 0, Width, Height, _clearPaint);
}
else
{
@ -384,7 +388,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
if(Input != null)
{
var args = new RawTextInputEventArgs(AndroidKeyboardDevice.Instance!, (ulong)DateTime.Now.Ticks, InputRoot!, text);
var args = new RawTextInputEventArgs(AndroidKeyboardDevice.Instance!, (ulong)SystemClock.UptimeMillis(), InputRoot!, text);
Input(args);
}

25
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -10,6 +10,18 @@ namespace Avalonia.Android.Platform.Specific.Helpers
{
internal class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : TopLevelImpl
{
private static readonly string[] s_asciiStringCache = InitAsciiStringCache();
private static string[] InitAsciiStringCache()
{
var cache = new string[128];
for (int i = 0; i < 128; i++)
{
cache[i] = ((char)i).ToString();
}
return cache;
}
private readonly TView _view;
public bool HandleEvents { get; set; }
@ -79,7 +91,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
AndroidKeyboardDevice.Instance!,
Convert.ToUInt64(e.EventTime),
inputRoot,
unicodeTextInput ?? Convert.ToChar(e.UnicodeChar).ToString()
unicodeTextInput ?? CharToString(e.UnicodeChar)
);
_view.Input?.Invoke(rawTextEvent);
@ -107,6 +119,15 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return rv;
}
private static string CharToString(int unicodeChar)
{
if (unicodeChar >= 0 && unicodeChar < s_asciiStringCache.Length)
{
return s_asciiStringCache[unicodeChar];
}
return char.ConvertFromUtf32(unicodeChar);
}
private static string? GetKeySymbol(int unicodeChar, PhysicalKey physicalKey)
{
// Handle a very limited set of control characters so that we're consistent with other platforms
@ -126,7 +147,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
if (unicodeChar <= 0x7F)
{
var asciiChar = (char)unicodeChar;
return KeySymbolHelper.IsAllowedAsciiKeySymbol(asciiChar) ? asciiChar.ToString() : null;
return KeySymbolHelper.IsAllowedAsciiKeySymbol(asciiChar) ? s_asciiStringCache[asciiChar] : null;
}
return char.ConvertFromUtf32(unicodeChar);
}

60
src/Avalonia.Base/Animation/Animation.cs

@ -42,6 +42,15 @@ namespace Avalonia.Animation
o => o._playbackDirection,
(o, v) => o._playbackDirection = v);
/// <summary>
/// Defines the <see cref="PlaybackBehavior"/> property.
/// </summary>
public static readonly DirectProperty<Animation, PlaybackBehavior> PlaybackBehaviorProperty =
AvaloniaProperty.RegisterDirect<Animation, PlaybackBehavior>(
nameof(PlaybackBehavior),
o => o._playbackBehavior,
(o, v) => o._playbackBehavior = v);
/// <summary>
/// Defines the <see cref="FillMode"/> property.
/// </summary>
@ -91,6 +100,7 @@ namespace Avalonia.Animation
private TimeSpan _duration;
private IterationCount _iterationCount = new IterationCount(1);
private PlaybackDirection _playbackDirection;
private PlaybackBehavior _playbackBehavior;
private FillMode _fillMode;
private Easing _easing = new LinearEasing();
private TimeSpan _delay = TimeSpan.Zero;
@ -124,6 +134,19 @@ namespace Avalonia.Animation
set { SetAndRaise(PlaybackDirectionProperty, ref _playbackDirection, value); }
}
/// <summary>
/// Gets or sets the playback behavior for this animation.
/// When set to <see cref="PlaybackBehavior.Auto"/>, manually started animations and
/// animations targeting <see cref="Visual.IsVisibleProperty"/> always play,
/// while style-applied animations pause when the control is not effectively visible
/// (see <see cref="Visual.IsEffectivelyVisible"/>).
/// </summary>
public PlaybackBehavior PlaybackBehavior
{
get { return _playbackBehavior; }
set { SetAndRaise(PlaybackBehaviorProperty, ref _playbackBehavior, value); }
}
/// <summary>
/// Gets or sets the value fill mode for this animation.
/// </summary>
@ -192,11 +215,12 @@ namespace Avalonia.Animation
return null;
}
private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control)
private (IList<IAnimator> Animators, IList<IDisposable> subscriptions, bool animatesVisibility) InterpretKeyframes(Animatable control)
{
var handlerList = new Dictionary<(Type type, AvaloniaProperty Property), Func<IAnimator>>();
var animatorKeyFrames = new List<AnimatorKeyFrame>();
var subscriptions = new List<IDisposable>();
var animatesVisibility = false;
foreach (var keyframe in Children)
{
@ -207,6 +231,9 @@ namespace Avalonia.Animation
throw new InvalidOperationException("No Setter property assigned.");
}
if (setter.Property == Visual.IsVisibleProperty)
animatesVisibility = true;
var handler = Animation.GetAnimator(setter) ?? GetAnimatorType(setter.Property);
if (handler == null)
@ -265,19 +292,31 @@ namespace Avalonia.Animation
}
}
return (newAnimatorInstances, subscriptions);
return (newAnimatorInstances, subscriptions, animatesVisibility);
}
IDisposable IAnimation.Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
=> Apply(control, clock, match, onComplete);
IDisposable IAnimation.Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete,
bool isManuallyStarted)
=> Apply(control, clock, match, onComplete, isManuallyStarted);
/// <inheritdoc cref="IAnimation.Apply"/>
internal IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
internal IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete,
bool isManuallyStarted = false)
{
var (animators, subscriptions) = InterpretKeyframes(control);
var (animators, subscriptions, animatesVisibility) = InterpretKeyframes(control);
var shouldPauseOnInvisible = _playbackBehavior switch
{
PlaybackBehavior.Auto => !(animatesVisibility || isManuallyStarted),
PlaybackBehavior.Always => false,
PlaybackBehavior.OnlyIfVisible => true,
_ => throw new InvalidOperationException($"Unknown PlaybackBehavior value: {_playbackBehavior}"),
};
if (animators.Count == 1)
{
var subscription = animators[0].Apply(this, control, clock, match, onComplete);
var subscription = animators[0].Apply(this, control, clock, match,
onComplete, shouldPauseOnInvisible);
if (subscription is not null)
{
@ -297,7 +336,8 @@ namespace Avalonia.Animation
completionTasks!.Add(tcs.Task);
}
var subscription = animator.Apply(this, control, clock, match, animatorOnComplete);
var subscription = animator.Apply(this, control, clock, match,
animatorOnComplete, shouldPauseOnInvisible);
if (subscription is not null)
{
@ -348,7 +388,7 @@ namespace Avalonia.Animation
run.TrySetResult(null);
subscriptions?.Dispose();
cancellation?.Dispose();
});
}, isManuallyStarted: true);
cancellation = cancellationToken.Register(() =>
{

59
src/Avalonia.Base/Animation/AnimationInstance`1.cs

@ -38,7 +38,9 @@ namespace Avalonia.Animation
private EventHandler? _visibilityChangedHandler;
private EventHandler<VisualTreeAttachmentEventArgs>? _detachedHandler;
public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, IClock baseClock, Action? OnComplete, Func<double, T, T> Interpolator)
private readonly bool _shouldPauseOnInvisible;
public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, IClock baseClock, Action? OnComplete, Func<double, T, T> Interpolator, bool shouldPauseOnInvisible)
{
_animator = animator;
_animation = animation;
@ -49,6 +51,7 @@ namespace Avalonia.Animation
_lastInterpValue = default!;
_firstKFValue = default!;
_neutralValue = default!;
_shouldPauseOnInvisible = shouldPauseOnInvisible;
FetchProperties();
}
@ -120,29 +123,36 @@ namespace Avalonia.Animation
if (_targetControl is Visual visual)
{
_visibilityChangedHandler = (_, _) =>
if (_shouldPauseOnInvisible)
{
if (_clock is null || _clock.PlayState == PlayState.Stop)
return;
if (visual.IsEffectivelyVisible)
{
if (_clock.PlayState == PlayState.Pause)
_clock.PlayState = PlayState.Run;
}
else
_visibilityChangedHandler = (_, _) =>
{
if (_clock.PlayState == PlayState.Run)
_clock.PlayState = PlayState.Pause;
}
};
visual.IsEffectivelyVisibleChanged += _visibilityChangedHandler;
// If already invisible when animation starts, pause immediately.
if (!visual.IsEffectivelyVisible)
_clock.PlayState = PlayState.Pause;
if (_clock is null || _clock.PlayState == PlayState.Stop)
return;
if (visual.IsEffectivelyVisible)
{
if (_clock.PlayState == PlayState.Pause)
_clock.PlayState = PlayState.Run;
}
else
{
if (_clock.PlayState == PlayState.Run)
_clock.PlayState = PlayState.Pause;
}
};
visual.IsEffectivelyVisibleChanged += _visibilityChangedHandler;
// If already invisible when animation starts, pause immediately.
if (!visual.IsEffectivelyVisible)
_clock.PlayState = PlayState.Pause;
}
// Stop and dispose the animation when detached from the visual tree.
_detachedHandler = (_, _) => DoComplete();
_detachedHandler = (_, _) =>
{
SetFinalValue();
DoComplete();
};
visual.DetachedFromVisualTree += _detachedHandler;
}
@ -166,6 +176,12 @@ namespace Avalonia.Animation
}
}
private void SetFinalValue()
{
var easedTime = _easeFunc!.Ease(_playbackReversed ? 0.0 : 1.0);
_lastInterpValue = _interpolator(easedTime, _neutralValue);
}
private void ApplyFinalFill()
{
if (_animator.Property is null)
@ -231,8 +247,7 @@ namespace Avalonia.Animation
// when the duration is set to zero while animating and snap to the last iterated value.
if (_currentIteration + 1 > _iterationCount || _duration == TimeSpan.Zero)
{
var easedTime = _easeFunc!.Ease(_playbackReversed ? 0.0 : 1.0);
_lastInterpValue = _interpolator(easedTime, _neutralValue);
SetFinalValue();
DoComplete();
return;
}

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

@ -17,9 +17,9 @@ namespace Avalonia.Animation.Animators
public AvaloniaProperty? Property { get; set; }
/// <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, bool shouldPauseOnInvisible)
{
var subject = new DisposeAnimationInstanceSubject<T>(this, animation, control, clock, onComplete);
var subject = new DisposeAnimationInstanceSubject<T>(this, animation, control, clock, onComplete, shouldPauseOnInvisible);
return new CompositeDisposable(match.Subscribe(subject), subject);
}
@ -103,7 +103,7 @@ namespace Avalonia.Animation.Animators
/// <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, bool shouldPauseOnInvisible)
{
var instance = new AnimationInstance<T>(
animation,
@ -111,7 +111,8 @@ namespace Avalonia.Animation.Animators
this,
clock ?? control.Clock ?? Clock.GlobalClock,
onComplete,
InterpolationHandler);
InterpolationHandler,
shouldPauseOnInvisible);
return BindAnimation(control, instance);
}

6
src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs

@ -38,20 +38,20 @@ namespace Avalonia.Animation.Animators
/// <inheritdoc/>
public override IDisposable? Apply(Animation animation, Animatable control, IClock? clock,
IObservable<bool> match, Action? onComplete)
IObservable<bool> match, Action? onComplete, bool shouldPauseOnInvisible)
{
if (TryCreateCustomRegisteredAnimator(out var animator)
|| TryCreateGradientAnimator(out animator)
|| TryCreateSolidColorBrushAnimator(out animator))
{
return animator.Apply(animation, control, clock, match, onComplete);
return animator.Apply(animation, control, clock, match, onComplete, shouldPauseOnInvisible);
}
Logger.TryGet(LogEventLevel.Error, LogArea.Animations)?.Log(
this,
"The animation's keyframe value types set is not supported.");
return base.Apply(animation, control, clock, match, onComplete);
return base.Apply(animation, control, clock, match, onComplete, shouldPauseOnInvisible);
}
/// <summary>

9
src/Avalonia.Base/Animation/Animators/TransformAnimator.cs

@ -14,7 +14,8 @@ namespace Avalonia.Animation.Animators
DoubleAnimator? _doubleAnimator;
/// <inheritdoc/>
public override IDisposable? Apply(Animation animation, Animatable control, IClock? clock, IObservable<bool> obsMatch, Action? onComplete)
public override IDisposable? Apply(Animation animation, Animatable control, IClock? clock,
IObservable<bool> obsMatch, Action? onComplete, bool shouldPauseOnInvisible)
{
var ctrl = (Visual)control;
@ -65,7 +66,8 @@ namespace Avalonia.Animation.Animators
// It's a transform object so let's target that.
if (renderTransformType == Property.OwnerType)
{
return _doubleAnimator.Apply(animation, (Transform) ctrl.RenderTransform, clock ?? control.Clock, obsMatch, onComplete);
return _doubleAnimator.Apply(animation, (Transform) ctrl.RenderTransform, clock ?? control.Clock,
obsMatch, onComplete, shouldPauseOnInvisible);
}
// It's a TransformGroup and try finding the target there.
else if (renderTransformType == typeof(TransformGroup))
@ -74,7 +76,8 @@ namespace Avalonia.Animation.Animators
{
if (transform.GetType() == Property.OwnerType)
{
return _doubleAnimator.Apply(animation, transform, clock ?? control.Clock, obsMatch, onComplete);
return _doubleAnimator.Apply(animation, transform, clock ?? control.Clock,
obsMatch, onComplete, shouldPauseOnInvisible);
}
}
}

24
src/Avalonia.Base/Animation/DisposeAnimationInstanceSubject.cs

@ -6,24 +6,18 @@ namespace Avalonia.Animation
/// <summary>
/// Manages the lifetime of animation instances as determined by its selector state.
/// </summary>
internal class DisposeAnimationInstanceSubject<T> : IObserver<bool>, IDisposable
internal class DisposeAnimationInstanceSubject<T>(
Animator<T> animator,
Animation animation,
Animatable control,
IClock? clock,
Action? onComplete,
bool shouldPauseOnInvisible)
: IObserver<bool>, IDisposable
{
private IDisposable? _lastInstance;
private bool _lastMatch;
private readonly Animator<T> _animator;
private readonly Animation _animation;
private readonly Animatable _control;
private readonly Action? _onComplete;
private readonly IClock? _clock;
public DisposeAnimationInstanceSubject(Animator<T> animator, Animation animation, Animatable control, IClock? clock, Action? onComplete)
{
this._animator = animator;
this._animation = animation;
this._control = control;
this._onComplete = onComplete;
this._clock = clock;
}
public void Dispose()
{
_lastInstance?.Dispose();
@ -47,7 +41,7 @@ namespace Avalonia.Animation
if (matchVal)
{
_lastInstance = _animator.Run(_animation, _control, _clock, _onComplete);
_lastInstance = animator.Run(animation, control, clock, onComplete, shouldPauseOnInvisible);
}
else
{

3
src/Avalonia.Base/Animation/IAnimation.cs

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

5
src/Avalonia.Base/Animation/IAnimator.cs

@ -12,11 +12,12 @@ 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, bool shouldPauseOnInvisible);
}
}

29
src/Avalonia.Base/Animation/PlaybackBehavior.cs

@ -0,0 +1,29 @@
namespace Avalonia.Animation
{
/// <summary>
/// Determines whether an animation pauses when its target control is not effectively visible
/// (see <see cref="Visual.IsEffectivelyVisible"/>).
/// </summary>
public enum PlaybackBehavior
{
/// <summary>
/// The system decides based on context. Manually started animations
/// (via <see cref="Animation.RunAsync(Animatable, System.Threading.CancellationToken)"/>)
/// and animations that target <see cref="Visual.IsVisibleProperty"/> always play.
/// Style-applied animations pause when the control is not effectively visible
/// (see <see cref="Visual.IsEffectivelyVisible"/>).
/// </summary>
Auto,
/// <summary>
/// The animation always plays regardless of the control's effective visibility state.
/// </summary>
Always,
/// <summary>
/// The animation pauses when the control is not effectively visible
/// (see <see cref="Visual.IsEffectivelyVisible"/>).
/// </summary>
OnlyIfVisible,
}
}

21
src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs

@ -303,29 +303,14 @@ internal class BindingExpressionVisitor<TIn>(LambdaExpression expression) : Expr
}
}
private static Func<object, object>? CreateGetter(PropertyInfo info)
private static Func<object, object?>? CreateGetter(PropertyInfo info)
{
if (info.GetMethod == null)
return null;
var target = Expression.Parameter(typeof(object), "target");
return Expression.Lambda<Func<object, object>>(
Expression.Convert(Expression.Call(Expression.Convert(target, info.DeclaringType!), info.GetMethod),
typeof(object)),
target)
.Compile();
return info.CanRead ? info.GetValue : null;
}
private static Action<object, object?>? CreateSetter(PropertyInfo info)
{
if (info.SetMethod == null)
return null;
var target = Expression.Parameter(typeof(object), "target");
var value = Expression.Parameter(typeof(object), "value");
return Expression.Lambda<Action<object, object?>>(
Expression.Call(Expression.Convert(target, info.DeclaringType!), info.SetMethod,
Expression.Convert(value, info.SetMethod.GetParameters()[0].ParameterType)),
target, value)
.Compile();
return info.CanWrite ? info.SetValue : null;
}
private static T GetValue<T>(Expression expr)

2
src/Avalonia.Base/Input/DragDrop.cs

@ -127,7 +127,7 @@ namespace Avalonia.Input
/// <seealso cref="DataTransfer"/>
/// </summary>
public static Task<DragDropEffects> DoDragDropAsync(
PointerEventArgs triggerEvent,
PointerPressedEventArgs triggerEvent,
IDataTransfer dataTransfer,
DragDropEffects allowedEffects)
{

4
src/Avalonia.Base/Input/DragEventArgs.cs

@ -1,6 +1,5 @@
using System;
using Avalonia.Interactivity;
using Avalonia.Metadata;
namespace Avalonia.Input
{
@ -25,9 +24,8 @@ namespace Avalonia.Input
return _target.TranslatePoint(_targetLocation, relativeTo) ?? new Point(0, 0);
}
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using DragDrop.DoDragDrop or IHeadlessWindow.DragDrop.")]
public DragEventArgs(
RoutedEvent<DragEventArgs> routedEvent,
RoutedEvent<DragEventArgs>? routedEvent,
IDataTransfer dataTransfer,
Interactive target,
Point targetLocation,

2
src/Avalonia.Base/Input/FocusChangedEventArgs.cs

@ -11,7 +11,7 @@ namespace Avalonia.Input
/// Initializes a new instance of <see cref="FocusChangedEventArgs"/>.
/// </summary>
/// <param name="routedEvent">The routed event associated with these event args.</param>
public FocusChangedEventArgs(RoutedEvent routedEvent)
public FocusChangedEventArgs(RoutedEvent? routedEvent)
: base(routedEvent)
{
}

2
src/Avalonia.Base/Input/FocusChangingEventArgs.cs

@ -12,7 +12,7 @@ namespace Avalonia.Input
/// <summary>
/// Provides data for focus changing.
/// </summary>
internal FocusChangingEventArgs(RoutedEvent routedEvent) : base(routedEvent)
public FocusChangingEventArgs(RoutedEvent? routedEvent) : base(routedEvent)
{
}

64
src/Avalonia.Base/Input/FocusManager.cs

@ -75,30 +75,44 @@ namespace Avalonia.Input
if (element is not null)
{
if (!CanFocus(element))
return false;
return FocusCore(keyboardDevice, element, method, keyModifiers);
}
if (_focusRoot?.GetValue(FocusedElementProperty) is { } restore && restore != Current)
{
return FocusCore(keyboardDevice, restore, method, keyModifiers);
}
_focusRoot = null;
keyboardDevice.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None, false);
return false;
}
private bool FocusCore(
KeyboardDevice keyboardDevice,
IInputElement element,
NavigationMethod method,
KeyModifiers keyModifiers)
{
if (!CanFocus(element))
return false;
keyboardDevice.SetFocusedElement(element, method, keyModifiers);
if (GetFocusScope(element) is StyledElement scope)
if (keyboardDevice.FocusedElement is { } effectivelyFocusedElement)
{
if (GetFocusScope(effectivelyFocusedElement) is { } scope)
{
scope.SetValue(FocusedElementProperty, element);
scope.SetValue(FocusedElementProperty, effectivelyFocusedElement);
_focusRoot = GetFocusRoot(scope);
}
keyboardDevice.SetFocusedElement(element, method, keyModifiers);
return true;
}
else if (_focusRoot?.GetValue(FocusedElementProperty) is { } restore &&
restore != Current &&
Focus(restore))
{
return true;
}
else
{
_focusRoot = null;
keyboardDevice.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None, false);
return false;
return effectivelyFocusedElement == element;
}
_focusRoot = null;
keyboardDevice.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None, false);
return false;
}
internal void ClearFocusOnElementRemoved(IInputElement removedElement, Visual oldParent)
@ -111,7 +125,7 @@ namespace Avalonia.Input
scope.ClearValue(FocusedElementProperty);
}
if (Current == removedElement)
if (Current == removedElement)
Focus(null);
}
@ -158,7 +172,7 @@ namespace Avalonia.Input
/// </summary>
internal static FocusManager? GetFocusManager(IInputElement? element)
{
// Element might not be a visual, and not attached to the root.
// But IFocusManager is always expected to be a FocusManager.
return (FocusManager?)(element as Visual)?.GetInputRoot()?.FocusManager
@ -188,8 +202,12 @@ namespace Avalonia.Input
{
if (CanFocus(e))
{
if (ev.Pointer.Type == PointerType.Mouse || ev is PointerReleasedEventArgs)
return true;
return ev switch
{
PointerReleasedEventArgs releasedEventArgs when releasedEventArgs.Pointer.Type != PointerType.Mouse => true,
PointerPressedEventArgs pressedEventArgs when pressedEventArgs.Pointer.Type == PointerType.Mouse => true,
_ => false,
};
}
return false;
@ -229,7 +247,7 @@ namespace Avalonia.Input
var root = v.PresentationSource?.InputRoot.FocusRoot as Visual;
while (root is IHostedVisualTreeRoot hosted &&
hosted.Host?.PresentationSource?.InputRoot.FocusRoot is {} parentRoot)
hosted.Host?.PresentationSource?.InputRoot.FocusRoot is { } parentRoot)
{
root = parentRoot;
}

22
src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs

@ -33,6 +33,7 @@ namespace Avalonia.Input.GestureRecognizers
private TimeSpan _lastTime;
private TimeSpan _inertiaStartTime;
private int _currentInertiaGestureId;
private Point _delta;
/// <summary>
/// Defines the <see cref="CanHorizontallyScroll"/> property.
@ -133,8 +134,6 @@ namespace Avalonia.Input.GestureRecognizers
_trackedRootPoint = new Point(
_trackedRootPoint.X - (_trackedRootPoint.X >= rootPoint.X ? ScrollStartDistance : -ScrollStartDistance),
_trackedRootPoint.Y - (_trackedRootPoint.Y >= rootPoint.Y ? ScrollStartDistance : -ScrollStartDistance));
Capture(e.Pointer);
}
}
@ -142,12 +141,23 @@ namespace Avalonia.Input.GestureRecognizers
{
var vector = _trackedRootPoint - rootPoint;
_velocityTracker?.AddPosition(TimeSpan.FromMilliseconds(e.Timestamp), _pointerPressedPoint - rootPoint);
var oldDelta = _delta;
_delta = _pointerPressedPoint - rootPoint;
if (oldDelta == _delta)
return;
_velocityTracker?.AddPosition(TimeSpan.FromMilliseconds(e.Timestamp), _delta);
_lastMoveTimestamp = e.Timestamp;
Target!.RaiseEvent(new ScrollGestureEventArgs(_gestureId, vector));
var scrollEventArgs = new ScrollGestureEventArgs(_gestureId, vector);
Target!.RaiseEvent(scrollEventArgs);
_trackedRootPoint = rootPoint;
e.Handled = true;
e.Handled = scrollEventArgs.Handled;
if(e.Handled)
{
Capture(e.Pointer);
}
}
}
}
@ -166,7 +176,9 @@ namespace Avalonia.Input.GestureRecognizers
_stopWatch?.Stop();
_stopWatch = null;
_inertia = default;
_delta = default;
_scrolling = false;
_velocityTracker = null;
Target!.RaiseEvent(new ScrollGestureEndedEventArgs(_gestureId));
_gestureId = 0;
_lastMoveTimestamp = null;

24
src/Avalonia.Base/Input/GestureRecognizers/VelocityTracker.cs

@ -3,7 +3,6 @@
using System;
using System.Diagnostics;
using Avalonia.Utilities;
namespace Avalonia.Input.GestureRecognizers
{
@ -71,6 +70,8 @@ namespace Avalonia.Input.GestureRecognizers
private readonly PointAtTime[] _samples = new PointAtTime[HistorySize];
private int _index = 0;
private Stopwatch _sinceLastSample = new Stopwatch();
/// <summary>
/// Adds a position as the given time to the tracker.
/// </summary>
@ -78,6 +79,7 @@ namespace Avalonia.Input.GestureRecognizers
/// <param name="position"></param>
public void AddPosition(TimeSpan time, Vector position)
{
_sinceLastSample.Restart();
_index++;
if (_index == HistorySize)
{
@ -94,6 +96,11 @@ namespace Avalonia.Input.GestureRecognizers
/// Returns null if there is no data on which to base an estimate.
protected virtual VelocityEstimate? GetVelocityEstimate()
{
if (_sinceLastSample.ElapsedMilliseconds > AssumePointerMoveStoppedMilliseconds)
{
return new VelocityEstimate(default, 1.0, default, default);
}
Span<double> x = stackalloc double[HistorySize];
Span<double> y = stackalloc double[HistorySize];
Span<double> w = stackalloc double[HistorySize];
@ -159,17 +166,6 @@ namespace Avalonia.Input.GestureRecognizers
}
}
}
else if(sampleCount > 1)
{
// Return linear velocity if we don't have enough samples
var distance = newestSample.Point - oldestSample.Point;
return new VelocityEstimate(
PixelsPerSecond: new Vector(distance.X / duration.Milliseconds * 1000, distance.Y / duration.Milliseconds * 1000),
Confidence: 1,
Duration: duration,
Offset: offset
);
}
// We're unable to make a velocity estimate but we did have at least one
// valid pointer position.
@ -302,7 +298,7 @@ namespace Avalonia.Input.GestureRecognizers
// Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
// We just work from bottom-right to top-left calculating B's coefficients.
// "m" isn't expected to be bigger than HistorySize=20, so allocation on stack is safe.
Span<double> wy = stackalloc double[m];
Span<double> wy = stackalloc double[m];
for (int h = 0; h < m; h += 1)
{
wy[h] = y[h] * w[h];
@ -360,7 +356,7 @@ namespace Avalonia.Input.GestureRecognizers
}
return result;
}
private static double Norm(Span<double> v)
{
return Math.Sqrt(Multiply(v, v));

4
src/Avalonia.Base/Input/IFocusManager.cs

@ -24,8 +24,8 @@ namespace Avalonia.Input
/// If <paramref name="element"/> is null, this method tries to clear the focus. However, it is not advised.
/// For a better user experience, focus should be moved to another element when possible.
///
/// When this method return <c>true</c>, it is not guaranteed that the focus has been moved
/// to <paramref name="element"/>. The focus might have been redirected to another element.
/// When this method returns <c>true</c>, the focus has been moved to <paramref name="element"/>.
/// When this method returns <c>false</c>, the focus may have been canceled or redirected to another element.
/// </remarks>
bool Focus(
IInputElement? element,

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

Loading…
Cancel
Save