浏览代码

Merge branch 'master' into combobox-scroll-browser

Max Katz 2 年之前
父节点
当前提交
e9d101ede1
共有 100 个文件被更改,包括 805 次插入414 次删除
  1. 20 1
      .editorconfig
  2. 5 0
      .ncrunch/AppWithoutLifetime.v3.ncrunchproject
  3. 5 0
      .ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject
  4. 5 0
      .ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject
  5. 0 4
      .nuke/build.schema.json
  6. 7 7
      Avalonia.Desktop.slnf
  7. 42 15
      Avalonia.sln
  8. 1 1
      build/DevAnalyzers.props
  9. 32 0
      build/ExternalConsumers.props
  10. 3 2
      dirs.proj
  11. 3 3
      native/Avalonia.Native/src/OSX/AvnView.mm
  12. 1 1
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  13. 7 6
      nukebuild/Build.cs
  14. 50 43
      nukebuild/RefAssemblyGenerator.cs
  15. 1 1
      nukebuild/_build.csproj
  16. 5 0
      nukebuild/numerge.config
  17. 21 0
      packages/Avalonia/Avalonia.csproj
  18. 2 0
      packages/Avalonia/Avalonia.props
  19. 42 23
      readme.md
  20. 7 0
      samples/AppWithoutLifetime/App.axaml
  21. 12 0
      samples/AppWithoutLifetime/App.axaml.cs
  22. 21 0
      samples/AppWithoutLifetime/AppWithoutLifetime.csproj
  23. 13 0
      samples/AppWithoutLifetime/MainWindow.axaml
  24. 30 0
      samples/AppWithoutLifetime/MainWindow.axaml.cs
  25. 28 0
      samples/AppWithoutLifetime/Program.cs
  26. 9 0
      samples/AppWithoutLifetime/Sub.axaml
  27. 24 0
      samples/AppWithoutLifetime/Sub.axaml.cs
  28. 18 0
      samples/AppWithoutLifetime/app.manifest
  29. 0 2
      samples/ControlCatalog/App.xaml
  30. 0 48
      samples/ControlCatalog/MainView.xaml.cs
  31. 2 1
      samples/ControlCatalog/Pages/ColorPickerPage.xaml
  32. 15 0
      samples/ControlCatalog/Pages/ComboBoxPage.xaml
  33. 5 6
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  34. 1 1
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  35. 2 3
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  36. 25 4
      samples/ControlCatalog/Pages/TabControlPage.xaml
  37. 1 1
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  38. 1 1
      samples/ControlCatalog/Pages/TextBlockPage.xaml
  39. 15 0
      samples/ControlCatalog/ViewModels/ComboBoxPageViewModel.cs
  40. 1 1
      samples/ControlCatalog/ViewModels/TabControlPageViewModel.cs
  41. 0 2
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  42. 1 1
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  43. 1 0
      samples/IntegrationTestApp/IntegrationTestApp.csproj
  44. 3 0
      samples/IntegrationTestApp/MainWindow.axaml
  45. 2 2
      samples/IntegrationTestApp/MainWindow.axaml.cs
  46. 5 5
      samples/RenderDemo/Pages/CustomSkiaPage.cs
  47. 4 4
      samples/RenderDemo/Pages/PathMeasurementPage.cs
  48. 1 1
      samples/RenderDemo/Pages/WriteableBitmapPage.cs
  49. 1 1
      samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
  50. 3 8
      samples/Sandbox/MainWindow.axaml.cs
  51. 2 0
      samples/Sandbox/Sandbox.csproj
  52. 3 3
      samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs
  53. 58 54
      src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs
  54. 2 2
      src/Avalonia.Base/Animation/Animatable.cs
  55. 7 5
      src/Avalonia.Base/Animation/Animation.cs
  56. 1 1
      src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
  57. 4 2
      src/Avalonia.Base/AttachedProperty.cs
  58. 2 0
      src/Avalonia.Base/Avalonia.Base.csproj
  59. 14 10
      src/Avalonia.Base/AvaloniaProperty.cs
  60. 1 1
      src/Avalonia.Base/AvaloniaPropertyExtensions.cs
  61. 8 6
      src/Avalonia.Base/AvaloniaProperty`1.cs
  62. 2 0
      src/Avalonia.Base/ClassBindingManager.cs
  63. 1 1
      src/Avalonia.Base/Collections/AvaloniaDictionaryExtensions.cs
  64. 1 1
      src/Avalonia.Base/Collections/AvaloniaListConverter.cs
  65. 1 1
      src/Avalonia.Base/Collections/Pooled/ClearMode.cs
  66. 1 1
      src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs
  67. 2 2
      src/Avalonia.Base/Collections/Pooled/PooledList.cs
  68. 2 2
      src/Avalonia.Base/Collections/Pooled/PooledStack.cs
  69. 1 1
      src/Avalonia.Base/Controls/ChildNameScope.cs
  70. 1 1
      src/Avalonia.Base/Controls/IResourceDictionary.cs
  71. 21 0
      src/Avalonia.Base/Controls/IThemeVariantProvider.cs
  72. 7 5
      src/Avalonia.Base/Controls/ResourceDictionary.cs
  73. 46 18
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  74. 2 1
      src/Avalonia.Base/Data/BindingPriority.cs
  75. 2 2
      src/Avalonia.Base/Data/BindingValue.cs
  76. 1 1
      src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
  77. 6 1
      src/Avalonia.Base/Data/Converters/StringFormatValueConverter.cs
  78. 1 1
      src/Avalonia.Base/Data/Core/BindingExpression.cs
  79. 1 1
      src/Avalonia.Base/Data/Core/CommonPropertyNames.cs
  80. 1 1
      src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
  81. 1 1
      src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
  82. 1 1
      src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
  83. 1 1
      src/Avalonia.Base/Data/IndexerBinding.cs
  84. 2 1
      src/Avalonia.Base/Data/InstancedBinding.cs
  85. 1 1
      src/Avalonia.Base/Data/TemplateBinding.cs
  86. 18 0
      src/Avalonia.Base/Diagnostics/AppliedStyle.cs
  87. 1 1
      src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
  88. 1 1
      src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs
  89. 2 2
      src/Avalonia.Base/Diagnostics/StyleDiagnostics.cs
  90. 4 4
      src/Avalonia.Base/Diagnostics/TrimmingMessages.cs
  91. 1 40
      src/Avalonia.Base/DirectProperty.cs
  92. 3 3
      src/Avalonia.Base/DirectPropertyBase.cs
  93. 1 1
      src/Avalonia.Base/EnumExtensions.cs
  94. 4 2
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  95. 12 5
      src/Avalonia.Base/Input/Cursor.cs
  96. 2 1
      src/Avalonia.Base/Input/DataFormats.cs
  97. 2 1
      src/Avalonia.Base/Input/DataObjectExtensions.cs
  98. 1 2
      src/Avalonia.Base/Input/DragEventArgs.cs
  99. 41 20
      src/Avalonia.Base/Input/FocusManager.cs
  100. 1 2
      src/Avalonia.Base/Input/IAccessKeyHandler.cs

+ 20 - 1
.editorconfig

@@ -177,7 +177,9 @@ dotnet_diagnostic.CA1828.severity = warning
 dotnet_diagnostic.CA1829.severity = warning
 dotnet_diagnostic.CA1829.severity = warning
 #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
 #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
 dotnet_diagnostic.CA1847.severity = warning
 dotnet_diagnostic.CA1847.severity = warning
-#CACA2211:Non-constant fields should not be visible
+#CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
+dotnet_diagnostic.CA1854.severity = warning
+#CA2211:Non-constant fields should not be visible
 dotnet_diagnostic.CA2211.severity = error
 dotnet_diagnostic.CA2211.severity = error
 
 
 # Wrapping preferences
 # Wrapping preferences
@@ -186,6 +188,23 @@ csharp_wrap_before_ternary_opsigns = false
 # Avalonia DevAnalyzer preferences
 # Avalonia DevAnalyzer preferences
 dotnet_diagnostic.AVADEV2001.severity = error
 dotnet_diagnostic.AVADEV2001.severity = error
 
 
+# Avalonia PublicAnalyzer preferences
+dotnet_diagnostic.AVP1000.severity = error
+dotnet_diagnostic.AVP1001.severity = error
+dotnet_diagnostic.AVP1002.severity = error
+dotnet_diagnostic.AVP1010.severity = error
+dotnet_diagnostic.AVP1011.severity = error
+dotnet_diagnostic.AVP1012.severity = warning
+dotnet_diagnostic.AVP1013.severity = error
+dotnet_diagnostic.AVP1020.severity = error
+dotnet_diagnostic.AVP1021.severity = error
+dotnet_diagnostic.AVP1022.severity = error
+dotnet_diagnostic.AVP1030.severity = error
+dotnet_diagnostic.AVP1031.severity = error
+dotnet_diagnostic.AVP1032.severity = error
+dotnet_diagnostic.AVP1040.severity = error
+dotnet_diagnostic.AVA2001.severity = error
+
 # Xaml files
 # Xaml files
 [*.{xaml,axaml}]
 [*.{xaml,axaml}]
 indent_size = 2
 indent_size = 2

+ 5 - 0
.ncrunch/AppWithoutLifetime.v3.ncrunchproject

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

+ 5 - 0
.ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject

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

+ 5 - 0
.ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject

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

+ 0 - 4
.nuke/build.schema.json

@@ -101,10 +101,6 @@
           "type": "boolean",
           "type": "boolean",
           "description": "skip-tests"
           "description": "skip-tests"
         },
         },
-        "Solution": {
-          "type": "string",
-          "description": "Path to a solution file that is automatically loaded. Default is Avalonia.sln"
-        },
         "Target": {
         "Target": {
           "type": "array",
           "type": "array",
           "description": "List of targets to be invoked. Default is '{default_target}'",
           "description": "List of targets to be invoked. Default is '{default_target}'",

+ 7 - 7
Avalonia.Desktop.slnf

@@ -3,6 +3,7 @@
     "path": "Avalonia.sln",
     "path": "Avalonia.sln",
     "projects": [
     "projects": [
       "packages\\Avalonia\\Avalonia.csproj",
       "packages\\Avalonia\\Avalonia.csproj",
+      "samples\\AppWithoutLifetime\\AppWithoutLifetime.csproj",
       "samples\\ControlCatalog.NetCore\\ControlCatalog.NetCore.csproj",
       "samples\\ControlCatalog.NetCore\\ControlCatalog.NetCore.csproj",
       "samples\\ControlCatalog\\ControlCatalog.csproj",
       "samples\\ControlCatalog\\ControlCatalog.csproj",
       "samples\\GpuInterop\\GpuInterop.csproj",
       "samples\\GpuInterop\\GpuInterop.csproj",
@@ -23,8 +24,6 @@
       "src\\Avalonia.Dialogs\\Avalonia.Dialogs.csproj",
       "src\\Avalonia.Dialogs\\Avalonia.Dialogs.csproj",
       "src\\Avalonia.Fonts.Inter\\Avalonia.Fonts.Inter.csproj",
       "src\\Avalonia.Fonts.Inter\\Avalonia.Fonts.Inter.csproj",
       "src\\Avalonia.FreeDesktop\\Avalonia.FreeDesktop.csproj",
       "src\\Avalonia.FreeDesktop\\Avalonia.FreeDesktop.csproj",
-      "src\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
-      "src\\Avalonia.Headless\\Avalonia.Headless.csproj",
       "src\\Avalonia.MicroCom\\Avalonia.MicroCom.csproj",
       "src\\Avalonia.MicroCom\\Avalonia.MicroCom.csproj",
       "src\\Avalonia.Native\\Avalonia.Native.csproj",
       "src\\Avalonia.Native\\Avalonia.Native.csproj",
       "src\\Avalonia.OpenGL\\Avalonia.OpenGL.csproj",
       "src\\Avalonia.OpenGL\\Avalonia.OpenGL.csproj",
@@ -33,19 +32,20 @@
       "src\\Avalonia.Themes.Fluent\\Avalonia.Themes.Fluent.csproj",
       "src\\Avalonia.Themes.Fluent\\Avalonia.Themes.Fluent.csproj",
       "src\\Avalonia.Themes.Simple\\Avalonia.Themes.Simple.csproj",
       "src\\Avalonia.Themes.Simple\\Avalonia.Themes.Simple.csproj",
       "src\\Avalonia.X11\\Avalonia.X11.csproj",
       "src\\Avalonia.X11\\Avalonia.X11.csproj",
+      "src\\Headless\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
+      "src\\Headless\\Avalonia.Headless\\Avalonia.Headless.csproj",
       "src\\Linux\\Avalonia.LinuxFramebuffer\\Avalonia.LinuxFramebuffer.csproj",
       "src\\Linux\\Avalonia.LinuxFramebuffer\\Avalonia.LinuxFramebuffer.csproj",
       "src\\Markup\\Avalonia.Markup.Xaml.Loader\\Avalonia.Markup.Xaml.Loader.csproj",
       "src\\Markup\\Avalonia.Markup.Xaml.Loader\\Avalonia.Markup.Xaml.Loader.csproj",
       "src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
       "src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
       "src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj",
       "src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj",
       "src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj",
       "src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj",
-      "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
-      "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
-      "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
-      "src\\tools\\DevGenerators\\DevGenerators.csproj",
-      "src\\tools\\PublicAnalyzers\\Avalonia.Analyzers.csproj",
       "src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj",
       "src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj",
       "src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj",
       "src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj",
       "src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
       "src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
+      "src\\tools\\Avalonia.Analyzers\\Avalonia.Analyzers.csproj",
+      "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
+      "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
+      "src\\tools\\DevGenerators\\DevGenerators.csproj",
       "tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
       "tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
       "tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
       "tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
       "tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",
       "tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",

+ 42 - 15
Avalonia.sln

@@ -233,7 +233,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\R
 EndProject
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
 EndProject
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
 EndProject
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
 	ProjectSection(SolutionItems) = preProject
 	ProjectSection(SolutionItems) = preProject
@@ -246,12 +246,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepe
 EndProject
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
 EndProject
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
 EndProject
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
 EndProject
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppWithoutLifetime", "samples\AppWithoutLifetime\AppWithoutLifetime.csproj", "{F8928267-688E-4A51-989C-612A72446D33}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
 EndProject
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"
@@ -262,9 +261,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples
 EndProject
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
 EndProject
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
+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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit", "src\Headless\Avalonia.Headless.NUnit\Avalonia.Headless.NUnit.csproj", "{ED976634-B118-43F8-8B26-0279C7A7044F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}"
 EndProject
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.UnitTests", "tests\Avalonia.Headless.UnitTests\Avalonia.Headless.UnitTests.csproj", "{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit.UnitTests", "tests\Avalonia.Headless.NUnit.UnitTests\Avalonia.Headless.NUnit.UnitTests.csproj", "{2999D79E-3C20-4A90-B651-CA7E0AC92D35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit.UnitTests", "tests\Avalonia.Headless.XUnit.UnitTests\Avalonia.Headless.XUnit.UnitTests.csproj", "{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}"
 EndProject
 EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -597,10 +602,6 @@ Global
 		{DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
 		{DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.Build.0 = Release|Any CPU
 		{DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.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.ActiveCfg = Debug|Any CPU
 		{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
@@ -609,14 +610,14 @@ Global
 		{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
 		{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
 		{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.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.ActiveCfg = Debug|Any CPU
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
 		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
@@ -637,6 +638,26 @@ Global
 		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.ActiveCfg = Release|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.Build.0 = Release|Any CPU
 		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.0 = Release|Any CPU
 		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.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
+		{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
+		{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
+		{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE
@@ -681,6 +702,8 @@ Global
 		{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
 		{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
 		{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+		{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}
 		{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
 		{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
@@ -707,14 +730,18 @@ Global
 		{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
 		{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
 		{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
 		{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
 		{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
 		{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
-		{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
 		{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
-		{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{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}
 		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D} = {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}
 		{4CDAD037-34A2-4CCF-A03A-C6C7B988A572} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+		{ED976634-B118-43F8-8B26-0279C7A7044F} = {FF237916-7150-496B-89ED-6CA3292896E7}
+		{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
+		{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+		{2999D79E-3C20-4A90-B651-CA7E0AC92D35} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+		{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

+ 1 - 1
build/DevAnalyzers.props

@@ -5,7 +5,7 @@
                       ReferenceOutputAssembly="false"
                       ReferenceOutputAssembly="false"
                       OutputItemType="Analyzer"
                       OutputItemType="Analyzer"
                       SetTargetFramework="TargetFramework=netstandard2.0"/>
                       SetTargetFramework="TargetFramework=netstandard2.0"/>
-    <ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj"
+    <ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj"
                       PrivateAssets="all"
                       PrivateAssets="all"
                       ReferenceOutputAssembly="false"
                       ReferenceOutputAssembly="false"
                       OutputItemType="Analyzer"
                       OutputItemType="Analyzer"

+ 32 - 0
build/ExternalConsumers.props

@@ -0,0 +1,32 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <InternalsVisibleTo Include="AvaloniaUI.Xpf.WinApiShim, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a7f4b8b7db0bfb8d74992dc94ecafae031019197ff4263d87ac0a5835fab101c973ccab6fa6e7d90e8f987374f7c6de18dd0b5cd7d6c41e574a8bc66b64836b7c7e707e1aa393d27e33a08f372c1c9965be81658937c85698f4a1c0f73be68a61ffce06d49d1366bf18464c20a29859ccf105fc2d5e35c7ae68919eab668bf8e" />
+    <InternalsVisibleTo Include="System.Windows.Forms, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="System.Windows.Forms.Primitives, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="PresentationFramework-SystemData, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="PresentationFramework.Aero, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="System.Xaml, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="PresentationFramework, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework-SystemDrawing, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="PresentationFramework-SystemCore, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="WindowsFormsIntegration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework.AeroLite, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework.Aero2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="UIAutomationClient, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework.Luna, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="UIAutomationTypes, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework.Royale, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="System.Windows.Input.Manipulations, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="System.Windows.Controls.Ribbon, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="PresentationFramework-SystemXml, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="ReachFramework, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="System.Printing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework-SystemXmlLinq, PublicKey=00000000000000000400000000000000" />
+    <InternalsVisibleTo Include="PresentationUI, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="Atlantis, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a7f4b8b7db0bfb8d74992dc94ecafae031019197ff4263d87ac0a5835fab101c973ccab6fa6e7d90e8f987374f7c6de18dd0b5cd7d6c41e574a8bc66b64836b7c7e707e1aa393d27e33a08f372c1c9965be81658937c85698f4a1c0f73be68a61ffce06d49d1366bf18464c20a29859ccf105fc2d5e35c7ae68919eab668bf8e" />
+    <InternalsVisibleTo Include="WindowsBase, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationFramework.Classic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="UIAutomationProvider, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+    <InternalsVisibleTo Include="PresentationCore, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
+  </ItemGroup>
+</Project>

+ 3 - 2
dirs.proj

@@ -9,10 +9,11 @@
     <ProjectReference Remove="**/*.shproj" />
     <ProjectReference Remove="**/*.shproj" />
     <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
     <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
     <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/**/*.*proj" />
     <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/**/*.*proj" />
-    <!-- Exclude iOS, Android and Web samples from build -->
+    <!-- Exclude iOS, Android and Browser samples from build -->
     <ProjectReference Remove="samples/*.iOS/*.csproj" />
     <ProjectReference Remove="samples/*.iOS/*.csproj" />
     <ProjectReference Remove="samples/*.Android/*.csproj" />
     <ProjectReference Remove="samples/*.Android/*.csproj" />
-    <ProjectReference Remove="samples/*.Web/*.csproj" />
+    <ProjectReference Remove="samples/*.Browser/*.csproj" />
+    <ProjectReference Remove="samples/*.Blazor/*.csproj" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
   <ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
     <ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />
     <ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />

+ 3 - 3
native/Avalonia.Native/src/OSX/AvnView.mm

@@ -275,7 +275,7 @@
         delta.Y = [event deltaY];
         delta.Y = [event deltaY];
     }
     }
 
 
-    uint32 timestamp = static_cast<uint32>([event timestamp] * 1000);
+    uint64_t timestamp = static_cast<uint64_t>([event timestamp] * 1000);
     auto modifiers = [self getModifiers:[event modifierFlags]];
     auto modifiers = [self getModifiers:[event modifierFlags]];
 
 
     if(type != Move ||
     if(type != Move ||
@@ -444,7 +444,7 @@
 
 
     auto key = s_KeyMap[[event keyCode]];
     auto key = s_KeyMap[[event keyCode]];
 
 
-    uint32_t timestamp = static_cast<uint32_t>([event timestamp] * 1000);
+    uint64_t timestamp = static_cast<uint64_t>([event timestamp] * 1000);
     auto modifiers = [self getModifiers:[event modifierFlags]];
     auto modifiers = [self getModifiers:[event modifierFlags]];
 
 
     if(_parent != nullptr)
     if(_parent != nullptr)
@@ -657,7 +657,7 @@
     
     
     [self unmarkText];
     [self unmarkText];
         
         
-    uint32_t timestamp = static_cast<uint32_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
+    uint64_t timestamp = static_cast<uint64_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
         
         
     _lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]);
     _lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]);
     
     

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

@@ -460,7 +460,7 @@
                     auto point = [self translateLocalPoint:avnPoint];
                     auto point = [self translateLocalPoint:avnPoint];
                     AvnVector delta = { 0, 0 };
                     AvnVector delta = { 0, 0 };
 
 
-                    _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint32>([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
+                    _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint64>([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
                 }
                 }
                 
                 
                 if(!_isTransitioningToFullScreen)
                 if(!_isTransitioningToFullScreen)

+ 7 - 6
nukebuild/Build.cs

@@ -35,8 +35,6 @@ using MicroCom.CodeGenerator;
 
 
 partial class Build : NukeBuild
 partial class Build : NukeBuild
 {
 {
-    [Solution("Avalonia.sln")] readonly Solution Solution;
-
     BuildParameters Parameters { get; set; }
     BuildParameters Parameters { get; set; }
     protected override void OnBuildInitialized()
     protected override void OnBuildInitialized()
     {
     {
@@ -143,10 +141,12 @@ partial class Build : NukeBuild
     void RunCoreTest(string projectName)
     void RunCoreTest(string projectName)
     {
     {
         Information($"Running tests from {projectName}");
         Information($"Running tests from {projectName}");
-        var project = Solution.GetProject(projectName).NotNull("project != null");
+        var project = RootDirectory.GlobFiles(@$"**\{projectName}.csproj").FirstOrDefault()
+            ?? throw new InvalidOperationException($"Project {projectName} doesn't exist");
+
         // Nuke and MSBuild tools have build-in helpers to get target frameworks from the project.
         // Nuke and MSBuild tools have build-in helpers to get target frameworks from the project.
         // Unfortunately, it gets broken with every second SDK update, so we had to do it manually.
         // Unfortunately, it gets broken with every second SDK update, so we had to do it manually.
-        var fileXml = XDocument.Parse(File.ReadAllText(project.Path));
+        var fileXml = XDocument.Parse(File.ReadAllText(project));
         var targetFrameworks = fileXml.Descendants("TargetFrameworks")
         var targetFrameworks = fileXml.Descendants("TargetFrameworks")
             .FirstOrDefault()?.Value.Split(';').Select(f => f.Trim());
             .FirstOrDefault()?.Value.Split(';').Select(f => f.Trim());
         if (targetFrameworks is null)
         if (targetFrameworks is null)
@@ -212,7 +212,8 @@ partial class Build : NukeBuild
             RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
             RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
             RunCoreTest("Avalonia.Skia.UnitTests");
             RunCoreTest("Avalonia.Skia.UnitTests");
             RunCoreTest("Avalonia.ReactiveUI.UnitTests");
             RunCoreTest("Avalonia.ReactiveUI.UnitTests");
-            RunCoreTest("Avalonia.Headless.UnitTests");
+            RunCoreTest("Avalonia.Headless.NUnit.UnitTests");
+            RunCoreTest("Avalonia.Headless.XUnit.UnitTests");
         });
         });
 
 
     Target RunRenderTests => _ => _
     Target RunRenderTests => _ => _
@@ -311,7 +312,7 @@ partial class Build : NukeBuild
 
 
     public static int Main() =>
     public static int Main() =>
         RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
         RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
-            ? Execute<Build>(x => x.Package)
+            ? Execute<Build>(x => x.RunToolsTests)
             : Execute<Build>(x => x.RunTests);
             : Execute<Build>(x => x.RunTests);
 
 
 }
 }

+ 50 - 43
nukebuild/RefAssemblyGenerator.cs

@@ -63,68 +63,75 @@ public class RefAssemblyGenerator
         });
         });
     }
     }
 
 
+    static bool HasPrivateApi(IEnumerable<CustomAttribute> attrs) => attrs.Any(a =>
+        a.AttributeType.FullName == "Avalonia.Metadata.PrivateApiAttribute");
+    
     static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor)
     static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor)
     {
     {
         foreach (var nested in type.NestedTypes)
         foreach (var nested in type.NestedTypes)
             ProcessType(nested, obsoleteCtor);
             ProcessType(nested, obsoleteCtor);
-        if (type.IsInterface)
+
+        var hideMethods = (type.IsInterface && type.Name.EndsWith("Impl"))
+                          || HasPrivateApi(type.CustomAttributes);
+
+        var injectMethod = hideMethods
+                           || type.CustomAttributes.Any(a =>
+                               a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute");
+
+
+        
+        if (injectMethod)
         {
         {
-            var hideMethods = type.Name.EndsWith("Impl")
-                              || (type.HasCustomAttributes && type.CustomAttributes.Any(a =>
-                                  a.AttributeType.FullName == "Avalonia.Metadata.PrivateApiAttribute"));
+            type.Methods.Add(new MethodDefinition(
+                "(This interface or abstract class is -not- implementable by user code !)",
+                MethodAttributes.Assembly
+                | MethodAttributes.Abstract
+                | MethodAttributes.NewSlot
+                | MethodAttributes.HideBySig, type.Module.TypeSystem.Void));
+        }
 
 
-            var injectMethod = hideMethods
-                               || type.CustomAttributes.Any(a =>
-                                   a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute");
-            
-            if (hideMethods)
-            {
-                foreach (var m in type.Methods)
-                {
-                    var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
-                                 MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
-                    m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
-                }
-            }
-            
-            if(injectMethod)
+        var forceUnstable = type.CustomAttributes.FirstOrDefault(a =>
+            a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute");
+
+        foreach (var m in type.Methods)
+        {
+            if (hideMethods || HasPrivateApi(m.CustomAttributes))
             {
             {
-                type.Methods.Add(new MethodDefinition("NotClientImplementable",
-                    MethodAttributes.Assembly
-                    | MethodAttributes.Abstract
-                    | MethodAttributes.NewSlot
-                    | MethodAttributes.HideBySig, type.Module.TypeSystem.Void));
+                var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
+                             MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
+                m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
             }
             }
-
-            var forceUnstable = type.CustomAttributes.Any(a =>
-                a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute");
-            
-            foreach (var m in type.Methods)
-                MarkAsUnstable(m, obsoleteCtor, forceUnstable);
-            foreach (var m in type.Properties)
-                MarkAsUnstable(m, obsoleteCtor, forceUnstable);
-            foreach (var m in type.Events)
-                MarkAsUnstable(m, obsoleteCtor, forceUnstable);
-            
+            MarkAsUnstable(m, obsoleteCtor, forceUnstable);
         }
         }
+
+        foreach (var m in type.Properties)
+            MarkAsUnstable(m, obsoleteCtor, forceUnstable);
+        foreach (var m in type.Events)
+            MarkAsUnstable(m, obsoleteCtor, forceUnstable);
     }
     }
 
 
-    static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, bool force)
+    static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute)
     {
     {
-        if (!force && (
-            def.HasCustomAttributes == false
-            || def.CustomAttributes.All(a => a.AttributeType.FullName != "Avalonia.Metadata.UnstableAttribute")))
+        if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
             return;
             return;
 
 
-        if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
+        unstableAttribute = def.CustomAttributes.FirstOrDefault(a =>
+            a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute") ?? unstableAttribute;
+
+        if (unstableAttribute is null)
             return;
             return;
 
 
+        var message = unstableAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString();
+        if (string.IsNullOrEmpty(message))
+        {
+            message = "This is a part of unstable API and can be changed in minor releases. Consider replacing it with alternatives or reach out developers on GitHub.";
+        }
+        
         def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
         def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
         {
         {
             ConstructorArguments =
             ConstructorArguments =
             {
             {
-                new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String,
-                    "This is a part of unstable API and can be changed in minor releases. You have been warned")
+                new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String, message)
             }
             }
         });
         });
     }
     }
@@ -168,4 +175,4 @@ public class RefAssemblyGenerator
                 }
                 }
         }
         }
     }
     }
-}
+}

+ 1 - 1
nukebuild/_build.csproj

@@ -15,7 +15,7 @@
     <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
     <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
     <PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" />
     <PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" />
     <!-- Keep in sync with Avalonia.Build.Tasks -->
     <!-- Keep in sync with Avalonia.Build.Tasks -->
-    <PackageReference Include="Mono.Cecil" Version="0.11.4" />
+    <PackageReference Include="Mono.Cecil" Version="0.11.5" />
     <PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
     <PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
     <PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
     <PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
     <PackageReference Include="xunit.runner.console" Version="2.4.2">
     <PackageReference Include="xunit.runner.console" Version="2.4.2">

+ 5 - 0
nukebuild/numerge.config

@@ -16,6 +16,11 @@
           "Id": "Avalonia.Generators",
           "Id": "Avalonia.Generators",
           "IgnoreMissingFrameworkBinaries": true,
           "IgnoreMissingFrameworkBinaries": true,
           "DoNotMergeDependencies": true
           "DoNotMergeDependencies": true
+        },
+        {
+          "Id": "Avalonia.Analyzers",
+          "IgnoreMissingFrameworkBinaries": true,
+          "DoNotMergeDependencies": true
         }
         }
       ]
       ]
     }
     }

+ 21 - 0
packages/Avalonia/Avalonia.csproj

@@ -5,6 +5,7 @@
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
+      <PackageReference Include="Avalonia.BuildServices" Version="0.0.16" />
       <ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
       <ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
       <ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj">
       <ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj">
         <PrivateAssets>all</PrivateAssets>
         <PrivateAssets>all</PrivateAssets>
@@ -15,6 +16,10 @@
                         ReferenceOutputAssembly="false"
                         ReferenceOutputAssembly="false"
                         PrivateAssets="all"
                         PrivateAssets="all"
                         OutputItemType="Analyzer" />
                         OutputItemType="Analyzer" />
+      <ProjectReference Include="..\..\src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj"
+                        ReferenceOutputAssembly="false"
+                        PrivateAssets="all"
+                        OutputItemType="Analyzer" />
   </ItemGroup>
   </ItemGroup>
 
 
   <PropertyGroup>
   <PropertyGroup>
@@ -60,4 +65,20 @@
   <Import Project="..\..\build\NetFX.props" />
   <Import Project="..\..\build\NetFX.props" />
   <Import Project="..\..\build\CoreLibraries.props" />
   <Import Project="..\..\build\CoreLibraries.props" />
   <Import Project="..\..\build\SourceLink.props" Condition="'$(DisableSourceLink)' == ''" />
   <Import Project="..\..\build\SourceLink.props" Condition="'$(DisableSourceLink)' == ''" />
+
+  <Target Name="WriteCurrentPackageVersionProps" BeforeTargets="_GetPackageFiles">
+    <PropertyGroup>
+      <PackageVersionPropsPath>$(IntermediateOutputPath)/AvaloniaVersion.props</PackageVersionPropsPath>
+    </PropertyGroup>
+    <WriteLinesToFile
+      File="$(PackageVersionPropsPath)"
+      Overwrite="true"
+      Lines="&lt;Project&gt;&lt;PropertyGroup&gt;&lt;AvaloniaMainPackageVersion&gt;$(PackageVersion)&lt;/AvaloniaMainPackageVersion&gt;&lt;/PropertyGroup&gt;&lt;/Project&gt;" />
+    <ItemGroup>
+      <Content Include="$(PackageVersionPropsPath)">
+        <Pack>true</Pack>
+        <PackagePath>build</PackagePath>
+      </Content>
+    </ItemGroup>
+  </Target>
 </Project>
 </Project>

+ 2 - 0
packages/Avalonia/Avalonia.props

@@ -4,9 +4,11 @@
     <AvaloniaPreviewerNetFullToolPath>$(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe</AvaloniaPreviewerNetFullToolPath>
     <AvaloniaPreviewerNetFullToolPath>$(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe</AvaloniaPreviewerNetFullToolPath>
     <AvaloniaBuildTasksLocation>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll</AvaloniaBuildTasksLocation>
     <AvaloniaBuildTasksLocation>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll</AvaloniaBuildTasksLocation>
     <AvaloniaUseExternalMSBuild>false</AvaloniaUseExternalMSBuild>
     <AvaloniaUseExternalMSBuild>false</AvaloniaUseExternalMSBuild>
+    <UsedAvaloniaProducts>$(UsedAvaloniaProducts);AvaloniaUI</UsedAvaloniaProducts>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.props"/>
   <Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.props"/>
   <Import Project="$(MSBuildThisFileDirectory)\Avalonia.Generators.props"/>
   <Import Project="$(MSBuildThisFileDirectory)\Avalonia.Generators.props"/>
+  <Import Project="$(MSBuildThisFileDirectory)..\build\AvaloniaVersion.props" />
 
 
   <!-- Allow loading the AvaloniaVS extension when referencing the Avalonia nuget package -->
   <!-- Allow loading the AvaloniaVS extension when referencing the Avalonia nuget package -->
   <ItemGroup>
   <ItemGroup>

+ 42 - 23
readme.md

@@ -1,26 +1,43 @@
-[![GH_Banner](https://user-images.githubusercontent.com/552074/218457976-92e76834-9e22-4e35-acfa-aa50281bc0f9.png)](https://avaloniaui.net/xpf)
+![Star our repo to show support](https://user-images.githubusercontent.com/552074/235945895-1b896994-a0b6-4e7c-a522-c5688c4ec1b9.png)
+![Header](https://user-images.githubusercontent.com/552074/235865745-2a8e7274-4f66-4f77-8f05-feeb76e7d478.png)
 
 
 [![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia)
 [![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia)
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![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://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![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://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
 <br />
 <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) 
 [![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) 
 
 
-# ⚠️ **v11 Update - Pausing community contributions**
-
-for more information see [this](https://github.com/AvaloniaUI/Avalonia/discussions/10599) discussion.
+⚠️ **v11 Update - [Pausing community contributions](https://github.com/AvaloniaUI/Avalonia/discussions/10599)**
 
 
 ## 📖 About 
 ## 📖 About 
 
 
-Avalonia is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS. Avalonia is mature and production ready. We also have in beta release support for iOS, Android and in early stages support for browser via WASM.
+[Avalonia](https://avaloniaui.net) is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of platforms such as Windows, macOS, Linux, iOS, Android and WebAssembly. Avalonia is mature and production ready and is used by companies, including [Schneider Electric](https://avaloniaui.net/showcase#se), [Unity](https://avaloniaui.net/showcase#unity), [JetBrains](https://avaloniaui.net/showcase#rider) and [Github](https://avaloniaui.net/showcase#github).
+
+Considered by many to be the spiritual successor to WPF, Avalonia UI provides a familiar, modern development experience for XAML developers creating cross-platform applications. While Avalonia UI is [similar to WPF](https://docs.avaloniaui.net/misc/wpf), it isn't a 1:1 copy, and you'll find plenty of improvements. 
 
 
-![image](https://user-images.githubusercontent.com/4672627/152126443-932966cf-57e7-4e77-9be6-62463a66b9f8.png)
+For those seeking a cross-platform WPF, we have created [Avalonia XPF](https://avaloniaui.net/xpf), 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. 
 
 
-To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
+#### Roadmap
+To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). 
+
+#### 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. 
+
+#### 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!
 
 
 ## 🚀 Getting Started
 ## 🚀 Getting Started
 
 
+See our [Get Started](https://avaloniaui.net/GettingStarted) guide to begin developing apps with Avalonia UI. 
+
+### Visual Studio 
 The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started).
 The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started).
 
 
+### JetBrains Rider
+[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
+
+Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
+
+### Avalonia Packages
 Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
 Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
 
 
 Use these commands in the Package Manager console to install Avalonia manually:
 Use these commands in the Package Manager console to install Avalonia manually:
@@ -30,31 +47,26 @@ Install-Package Avalonia.Desktop
 ```
 ```
 
 
 ## Showcase
 ## Showcase
+[![Showcase_Banner](https://user-images.githubusercontent.com/552074/235946124-bf6fda52-0c9f-4730-868b-0de957e5b97b.png)](https://avaloniaui.net/showcase)
 
 
-Examples of UIs built with Avalonia
-<video src="https://user-images.githubusercontent.com/4672627/152325602-28df36ec-6444-44a6-aebe-90ad52c8f27a.mp4"></video>
-([Lunacy](https://icons8.com/lunacy))
-
-![image](https://user-images.githubusercontent.com/4672627/152325740-261c27a3-e6f0-4662-bff7-4796d4940e04.png)
-([PlasticSCM](https://www.plasticscm.com/))
 
 
-![image](https://user-images.githubusercontent.com/4672627/152326453-14944c4d-33da-4d50-a268-b87f80927adb.png)
-([WasabiWallet](https://www.wasabiwallet.io/))
 
 
-
-## JetBrains Rider
-
-[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
-
-Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
+See what others have built with Avalonia UI on our [Showcase](https://avaloniaui.net/Showcase). We welcome submissions! 
 
 
 ## Bleeding Edge Builds
 ## 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!
 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!
 
 
-## Documentation
+## Learning
+
+### Documentation 
+Documentation can be found at https://docs.avaloniaui.net. 
 
 
-Documentation can be found at https://docs.avaloniaui.net. We also have a [tutorial](https://docs.avaloniaui.net/docs/getting-started/programming-with-avalonia) over there for newcomers.
+### Tutorials 
+We also have a [tutorial](https://docs.avaloniaui.net/docs/getting-started/programming-with-avalonia) over there for newcomers.
+
+### Samples
+We have a [range of samples](https://github.com/AvaloniaUI/Avalonia.Samples) to help you get started.
 
 
 ## Building and Using
 ## Building and Using
 
 
@@ -108,6 +120,8 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
 <a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
 <a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
 <a href="https://baseheadinc.com/" target="_blank"><img height="50" src="https://baseheadinc.com/wp-content/uploads/2020/09/BH-Logo-for-Site-Header-New.png"></a>
 <a href="https://baseheadinc.com/" target="_blank"><img height="50" src="https://baseheadinc.com/wp-content/uploads/2020/09/BH-Logo-for-Site-Header-New.png"></a>
 
 
+<a href="https://aws.amazon.com/developer/language/net/" target="_blank"><img src="https://github.com/AvaloniaUI/Avalonia/assets/552074/7771d8b9-ef84-4503-9889-033a87d2c852"></a>
+
 ## Commercial Support 
 ## Commercial Support 
 
 
 We have a range of [support plans available](https://avaloniaui.net/support) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process.
 We have a range of [support plans available](https://avaloniaui.net/support) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process.
@@ -116,3 +130,8 @@ We have a range of [support plans available](https://avaloniaui.net/support) for
 ## .NET Foundation
 ## .NET Foundation
 
 
 This project is supported by the [.NET Foundation](https://dotnetfoundation.org).
 This project is supported by the [.NET Foundation](https://dotnetfoundation.org).
+
+## Avalonia XPF
+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://user-images.githubusercontent.com/552074/218457976-92e76834-9e22-4e35-acfa-aa50281bc0f9.png)](https://avaloniaui.net/xpf)

+ 7 - 0
samples/AppWithoutLifetime/App.axaml

@@ -0,0 +1,7 @@
+<Application xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             x:Class="AppWithoutLifetime.App">
+    <Application.Styles>
+        <FluentTheme />
+    </Application.Styles>
+</Application>

+ 12 - 0
samples/AppWithoutLifetime/App.axaml.cs

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

+ 21 - 0
samples/AppWithoutLifetime/AppWithoutLifetime.csproj

@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>net6.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ApplicationManifest>app.manifest</ApplicationManifest>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
+  </ItemGroup>
+  
+  <Import Project="..\..\build\SampleApp.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
+  <Import Project="..\..\build\BuildTargets.targets" />
+
+</Project>

+ 13 - 0
samples/AppWithoutLifetime/MainWindow.axaml

@@ -0,0 +1,13 @@
+<Window xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+        x:Class="AppWithoutLifetime.MainWindow"
+        Title="AppWithoutLifetime">
+  <StackPanel>
+    <TextBlock Text="Welcome to Avalonia!"/>
+    <CheckBox Content="Welcome to Avalonia!"/>
+    <Button Click="Open" Content="Open"/>
+  </StackPanel>
+</Window>

+ 30 - 0
samples/AppWithoutLifetime/MainWindow.axaml.cs

@@ -0,0 +1,30 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace AppWithoutLifetime;
+
+public partial class MainWindow : Window
+{
+    public MainWindow()
+    {
+       InitializeComponent();
+    }
+
+    private void InitializeComponent()
+    {
+        AvaloniaXamlLoader.Load(this);
+    }
+
+    protected override void OnLoaded()
+    {
+        this.AttachDevTools();
+        base.OnLoaded();
+    }
+
+    public void Open(object sender, RoutedEventArgs e)
+    {
+        new Sub().Show(this);
+    }
+}

+ 28 - 0
samples/AppWithoutLifetime/Program.cs

@@ -0,0 +1,28 @@
+using Avalonia;
+using Avalonia.Controls;
+using System;
+
+namespace AppWithoutLifetime;
+
+class Program
+{
+    // Initialization code. Don't use any Avalonia, third-party APIs or any
+    // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+    // yet and stuff might break.
+    [STAThread]
+    public static void Main(string[] args)
+    {
+        BuildAvaloniaApp().Start(AppMain, args);
+    }
+
+    private static void AppMain(Application app, string[] args)
+    {
+        app.Run(new MainWindow());
+    }
+
+    // Avalonia configuration, don't remove; also used by visual designer.
+    public static AppBuilder BuildAvaloniaApp()
+        => AppBuilder.Configure<App>()
+            .UsePlatformDetect()
+            .LogToTrace();
+}

+ 9 - 0
samples/AppWithoutLifetime/Sub.axaml

@@ -0,0 +1,9 @@
+<Window xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+        x:Class="AppWithoutLifetime.Sub"
+        Title="Window1">
+  Welcome to Avalonia Sub!
+</Window>

+ 24 - 0
samples/AppWithoutLifetime/Sub.axaml.cs

@@ -0,0 +1,24 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace AppWithoutLifetime;
+
+public partial class Sub : Window
+{
+    public Sub()
+    {
+        InitializeComponent();
+    }
+
+    private void InitializeComponent()
+    {
+        AvaloniaXamlLoader.Load(this);
+    }
+
+    protected override void OnLoaded()
+    {
+        this.AttachDevTools();
+        base.OnLoaded();
+    }
+}

+ 18 - 0
samples/AppWithoutLifetime/app.manifest

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <!-- This manifest is used on Windows only.
+       Don't remove it as it might cause problems with window transparency and embeded controls.
+       For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
+  <assemblyIdentity version="1.0.0.0" name="AppWithoutLifetime"/>
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- A list of the Windows versions that this application has been tested on
+           and is designed to work with. Uncomment the appropriate elements
+           and Windows will automatically select the most compatible environment. -->
+
+      <!-- Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
+    </application>
+  </compatibility>
+</assembly>

+ 0 - 2
samples/ControlCatalog/App.xaml

@@ -26,8 +26,6 @@
           <Color x:Key="CatalogBaseHighColor">#FFFFFFFF</Color>
           <Color x:Key="CatalogBaseHighColor">#FFFFFFFF</Color>
         </ResourceDictionary>
         </ResourceDictionary>
       </ResourceDictionary.ThemeDictionaries>
       </ResourceDictionary.ThemeDictionaries>
-      <Color x:Key="SystemAccentColor">#FF0078D7</Color>
-      <Color x:Key="SystemAccentColorDark1">#FF005A9E</Color>
 
 
       <!-- Styles attached dynamically depending on current theme (simple or fluent) -->
       <!-- Styles attached dynamically depending on current theme (simple or fluent) -->
       <StyleInclude x:Key="DataGridFluent" Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />
       <StyleInclude x:Key="DataGridFluent" Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />

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

@@ -19,13 +19,9 @@ namespace ControlCatalog
 {
 {
     public class MainView : UserControl
     public class MainView : UserControl
     {
     {
-        private readonly IPlatformSettings _platformSettings;
-
         public MainView()
         public MainView()
         {
         {
             AvaloniaXamlLoader.Load(this);
             AvaloniaXamlLoader.Load(this);
-            _platformSettings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>();
-            PlatformSettingsOnColorValuesChanged(_platformSettings, _platformSettings.GetColorValues());
             
             
             var sideBar = this.Get<TabControl>("Sidebar");
             var sideBar = this.Get<TabControl>("Sidebar");
 
 
@@ -141,50 +137,6 @@ namespace ControlCatalog
                     ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
                     ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
                 };
                 };
             }
             }
-
-            _platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged;
-            PlatformSettingsOnColorValuesChanged(_platformSettings, _platformSettings.GetColorValues());
-        }
-
-        protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
-        {
-            base.OnDetachedFromLogicalTree(e);
-            
-            _platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged;
-        }
-
-        private void PlatformSettingsOnColorValuesChanged(object? sender, PlatformColorValues e)
-        {
-            Application.Current!.Resources["SystemAccentColor"] = e.AccentColor1;
-            Application.Current.Resources["SystemAccentColorDark1"] = ChangeColorLuminosity(e.AccentColor1, -0.3);
-            Application.Current.Resources["SystemAccentColorDark2"] = ChangeColorLuminosity(e.AccentColor1, -0.5);
-            Application.Current.Resources["SystemAccentColorDark3"] = ChangeColorLuminosity(e.AccentColor1, -0.7);
-            Application.Current.Resources["SystemAccentColorLight1"] = ChangeColorLuminosity(e.AccentColor1, 0.3);
-            Application.Current.Resources["SystemAccentColorLight2"] = ChangeColorLuminosity(e.AccentColor1, 0.5);
-            Application.Current.Resources["SystemAccentColorLight3"] = ChangeColorLuminosity(e.AccentColor1, 0.7);
-
-            static Color ChangeColorLuminosity(Color color, double luminosityFactor)
-            {
-                var red = (double)color.R;
-                var green = (double)color.G;
-                var blue = (double)color.B;
-
-                if (luminosityFactor < 0)
-                {
-                    luminosityFactor = 1 + luminosityFactor;
-                    red *= luminosityFactor;
-                    green *= luminosityFactor;
-                    blue *= luminosityFactor;
-                }
-                else if (luminosityFactor >= 0)
-                {
-                    red = (255 - red) * luminosityFactor + red;
-                    green = (255 - green) * luminosityFactor + green;
-                    blue = (255 - blue) * luminosityFactor + blue;
-                }
-
-                return new Color(color.A, (byte)red, (byte)green, (byte)blue);
-            }
         }
         }
     }
     }
 }
 }

+ 2 - 1
samples/ControlCatalog/Pages/ColorPickerPage.xaml

@@ -103,7 +103,8 @@
                    HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />-->
                    HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />-->
       <ColorPreviewer Grid.Row="8"
       <ColorPreviewer Grid.Row="8"
                       IsAccentColorsVisible="False"
                       IsAccentColorsVisible="False"
-                      HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />
+                      HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}"
+                      Margin="0,2,0,0" />
     </Grid>
     </Grid>
   </Grid>
   </Grid>
 </UserControl>
 </UserControl>

+ 15 - 0
samples/ControlCatalog/Pages/ComboBoxPage.xaml

@@ -98,6 +98,21 @@
                     <ComboBoxItem>Inline Item 3</ComboBoxItem>
                     <ComboBoxItem>Inline Item 3</ComboBoxItem>
                     <ComboBoxItem>Inline Item 4</ComboBoxItem>
                     <ComboBoxItem>Inline Item 4</ComboBoxItem>
                 </ComboBox>
                 </ComboBox>
+
+                <ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" DisplayMemberBinding="{Binding Name}">
+                
+                </ComboBox>
+
+                <ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" >
+                    <ComboBox.ItemTemplate>
+                        <DataTemplate>
+                            <StackPanel Orientation="Horizontal">
+                                <TextBlock Text="{Binding Name}"></TextBlock>
+                                <TextBlock Text="{Binding Id}"></TextBlock>
+                            </StackPanel>
+                        </DataTemplate>
+                    </ComboBox.ItemTemplate>
+                </ComboBox>
             </WrapPanel>
             </WrapPanel>
 
 
             <CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>
             <CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>

+ 5 - 6
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

@@ -19,18 +19,16 @@ namespace ControlCatalog.Pages
         public static readonly StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
         public static readonly StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
         public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
         public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
 
 
-        public static readonly StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation));
+        public static readonly StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation),
+            coerce: (_, val) => val % (Math.PI * 2));
+
         /// <summary>
         /// <summary>
         /// Rotation, measured in Radians!
         /// Rotation, measured in Radians!
         /// </summary>
         /// </summary>
         public double Rotation
         public double Rotation
         {
         {
             get => GetValue(RotationProperty);
             get => GetValue(RotationProperty);
-            set
-            {
-                double valueToUse = value % (Math.PI * 2);
-                SetValue(RotationProperty, valueToUse);
-            }
+            set => SetValue(RotationProperty, value);
         }
         }
 
 
         public static readonly StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
         public static readonly StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
@@ -213,5 +211,6 @@ namespace ControlCatalog.Pages
 
 
             return workingPoint;
             return workingPoint;
         }
         }
+
     }
     }
 }
 }

+ 1 - 1
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -307,7 +307,7 @@ namespace ControlCatalog.Pages
             Content:
             Content:
             ";
             ";
 
 
-                        resultText += await ReadTextFromFile(file, 10000);
+                        resultText += await ReadTextFromFile(file, 500);
                     }
                     }
 
 
                     openedFileContent.Text = resultText;
                     openedFileContent.Text = resultText;

+ 2 - 3
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@@ -1,5 +1,4 @@
 using System;
 using System;
-using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Reflection;
 using System.Reflection;
 using Avalonia.Controls;
 using Avalonia.Controls;
@@ -23,7 +22,7 @@ namespace ControlCatalog.Pages
                 $"Text was dragged {++textCount} times"), DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
                 $"Text was dragged {++textCount} times"), DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
 
 
             SetupDnd("Custom", d => d.Set(CustomFormat, "Test123"), DragDropEffects.Move);
             SetupDnd("Custom", d => d.Set(CustomFormat, "Test123"), DragDropEffects.Move);
-            SetupDnd("Files", d => d.Set(DataFormats.Files, new[] { Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName }), DragDropEffects.Copy);
+            SetupDnd("Files", async d => d.Set(DataFormats.Files, new[] { await (VisualRoot as TopLevel)!.StorageProvider.TryGetFileFromPathAsync(Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName) }), DragDropEffects.Copy);
         }
         }
 
 
         void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
         void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
@@ -99,7 +98,7 @@ namespace ControlCatalog.Pages
                     {
                     {
                         if (item is IStorageFile file)
                         if (item is IStorageFile file)
                         {
                         {
-                            var content = await DialogsPage.ReadTextFromFile(file, 1000);
+                            var content = await DialogsPage.ReadTextFromFile(file, 500);
                             contentStr += $"File {item.Name}:{Environment.NewLine}{content}{Environment.NewLine}{Environment.NewLine}";
                             contentStr += $"File {item.Name}:{Environment.NewLine}{content}{Environment.NewLine}{Environment.NewLine}";
                         }
                         }
                         else if (item is IStorageFolder folder)
                         else if (item is IStorageFolder folder)

+ 25 - 4
samples/ControlCatalog/Pages/TabControlPage.xaml

@@ -4,7 +4,27 @@
     xmlns="https://github.com/avaloniaui"
     xmlns="https://github.com/avaloniaui"
     xmlns:viewModels="using:ControlCatalog.ViewModels"
     xmlns:viewModels="using:ControlCatalog.ViewModels"
     x:DataType="viewModels:TabControlPageViewModel">
     x:DataType="viewModels:TabControlPageViewModel">
-    <DockPanel>
+    <DockPanel Classes.WithContentTemplates="{Binding IsChecked, ElementName=UseContentTemplates}">
+        <DockPanel.Styles>
+            <Style Selector="DockPanel.WithContentTemplates">
+                <Style Selector="^ TabItem">
+                    <Setter Property="ContentTemplate">
+                        <DataTemplate x:CompileBindings="False">
+                            <Border BorderBrush="Red" BorderThickness="10">
+                                <ContentPresenter Content="{Binding}"/>
+                            </Border>
+                        </DataTemplate>
+                    </Setter>
+                </Style>
+                <Style Selector="^ TabControl">
+                    <Setter Property="ContentTemplate">
+                        <DataTemplate>
+                            <TextBlock Text="This template should be overriden by each TabItem's template."/>
+                        </DataTemplate>
+                    </Setter>
+                </Style>
+            </Style>
+        </DockPanel.Styles>
         <TextBlock 
         <TextBlock 
             DockPanel.Dock="Top" 
             DockPanel.Dock="Top" 
             Classes="h2"
             Classes="h2"
@@ -55,14 +75,14 @@
                     Margin="0 16"
                     Margin="0 16"
                     DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
                     DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
                     TabStripPlacement="{Binding TabPlacement}">
                     TabStripPlacement="{Binding TabPlacement}">
-                    <TabControl.ContentTemplate>
+                    <TabControl.DataTemplates>
                         <DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
                         <DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
                             <StackPanel Orientation="Vertical" Spacing="8">
                             <StackPanel Orientation="Vertical" Spacing="8">
                                 <TextBlock Text="{Binding Text}"/>
                                 <TextBlock Text="{Binding Text}"/>
                                 <Image Source="{Binding Image}" Width="300"/>
                                 <Image Source="{Binding Image}" Width="300"/>
                             </StackPanel>
                             </StackPanel>
                         </DataTemplate>
                         </DataTemplate>
-                    </TabControl.ContentTemplate>
+                    </TabControl.DataTemplates>
                     <TabControl.Styles>
                     <TabControl.Styles>
                         <Style Selector="TabItem" x:DataType="viewModels:TabControlPageViewModelItem">
                         <Style Selector="TabItem" x:DataType="viewModels:TabControlPageViewModelItem">
                             <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
                             <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
@@ -78,12 +98,13 @@
                 HorizontalAlignment="Center"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center">
                 VerticalAlignment="Center">
                 <TextBlock VerticalAlignment="Center">Tab Placement:</TextBlock>
                 <TextBlock VerticalAlignment="Center">Tab Placement:</TextBlock>
-                <ComboBox SelectedIndex="{Binding TabPlacement, Mode=TwoWay}">
+                <ComboBox SelectedIndex="{Binding TabPlacement, Mode=TwoWay}" Width="100">
                     <ComboBoxItem>Left</ComboBoxItem>
                     <ComboBoxItem>Left</ComboBoxItem>
                     <ComboBoxItem>Bottom</ComboBoxItem>
                     <ComboBoxItem>Bottom</ComboBoxItem>
                     <ComboBoxItem>Right</ComboBoxItem>
                     <ComboBoxItem>Right</ComboBoxItem>
                     <ComboBoxItem>Top</ComboBoxItem>
                     <ComboBoxItem>Top</ComboBoxItem>
                 </ComboBox>
                 </ComboBox>
+                <CheckBox Name="UseContentTemplates">Set TabItem.ContentTemplate</CheckBox>
             </StackPanel>
             </StackPanel>
         </Grid>
         </Grid>
     </DockPanel>
     </DockPanel>

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

@@ -49,7 +49,7 @@ namespace ControlCatalog.Pages
             AvaloniaXamlLoader.Load(this);
             AvaloniaXamlLoader.Load(this);
         }
         }
 
 
-        private static IBitmap LoadBitmap(string uri)
+        private static Bitmap LoadBitmap(string uri)
         {
         {
             var assets = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
             var assets = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
             return new Bitmap(assets.Open(new Uri(uri)));
             return new Bitmap(assets.Open(new Uri(uri)));

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

@@ -118,7 +118,7 @@
         </StackPanel>
         </StackPanel>
       </Border>
       </Border>
       <Border>
       <Border>
-        <SelectableTextBlock SelectionBrush="LightBlue" Margin="10" TextWrapping="Wrap">
+        <SelectableTextBlock Margin="10" TextWrapping="Wrap">
           This <Span FontWeight="Bold">is</Span> a
           This <Span FontWeight="Bold">is</Span> a
           <Span Background="Silver" Foreground="Maroon">TextBlock</Span>
           <Span Background="Silver" Foreground="Maroon">TextBlock</Span>
           with <Span TextDecorations="Underline">several</Span>
           with <Span TextDecorations="Underline">several</Span>

+ 15 - 0
samples/ControlCatalog/ViewModels/ComboBoxPageViewModel.cs

@@ -16,5 +16,20 @@ namespace ControlCatalog.ViewModels
             get => _wrapSelection;
             get => _wrapSelection;
             set => this.RaiseAndSetIfChanged(ref _wrapSelection, value);
             set => this.RaiseAndSetIfChanged(ref _wrapSelection, value);
         }
         }
+
+        public ObservableCollection<IdAndName> Values { get; set; } = new ObservableCollection<IdAndName>
+        {
+            new IdAndName(){ Id = "Id 1", Name = "Name 1" },
+            new IdAndName(){ Id = "Id 2", Name = "Name 2" },
+            new IdAndName(){ Id = "Id 3", Name = "Name 3" },
+            new IdAndName(){ Id = "Id 4", Name = "Name 4" },
+            new IdAndName(){ Id = "Id 5", Name = "Name 5" },
+        };
+    }
+
+    public class IdAndName
+    {
+        public string Id { get; set; }
+        public string Name { get; set; }
     }
     }
 }
 }

+ 1 - 1
samples/ControlCatalog/ViewModels/TabControlPageViewModel.cs

@@ -21,6 +21,6 @@ public class TabControlPageViewModelItem
 {
 {
     public string? Header { get; set; }
     public string? Header { get; set; }
     public string? Text { get; set; }
     public string? Text { get; set; }
-    public IBitmap? Image { get; set; }
+    public Bitmap? Image { get; set; }
     public bool IsEnabled { get; set; } = true;
     public bool IsEnabled { get; set; } = true;
 }
 }

+ 0 - 2
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@@ -216,7 +216,6 @@ namespace ControlCatalog.ViewModels
             {
             {
                 var animation = new Animation
                 var animation = new Animation
                 {
                 {
-                    FillMode = FillMode.Forward,
                     Children =
                     Children =
                     {
                     {
                         new KeyFrame
                         new KeyFrame
@@ -247,7 +246,6 @@ namespace ControlCatalog.ViewModels
                 to.IsVisible = true;
                 to.IsVisible = true;
                 var animation = new Animation
                 var animation = new Animation
                 {
                 {
-                    FillMode = FillMode.Forward,
                     Children =
                     Children =
                     {
                     {
                         new KeyFrame
                         new KeyFrame

+ 1 - 1
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@@ -174,7 +174,7 @@ public unsafe class VulkanContext : IDisposable
                 for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
                 for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
                 {
                 {
                     var family = familyProperties[queueFamilyIndex];
                     var family = familyProperties[queueFamilyIndex];
-                    if (!family.QueueFlags.HasAllFlags(QueueFlags.GraphicsBit))
+                    if (!family.QueueFlags.HasFlag(QueueFlags.GraphicsBit))
                         continue;
                         continue;
 
 
 
 

+ 1 - 0
samples/IntegrationTestApp/IntegrationTestApp.csproj

@@ -3,6 +3,7 @@
     <OutputType>WinExe</OutputType>
     <OutputType>WinExe</OutputType>
     <TargetFramework>net7.0</TargetFramework>
     <TargetFramework>net7.0</TargetFramework>
     <Nullable>enable</Nullable>
     <Nullable>enable</Nullable>
+    <NoWarn>$(NoWarn);AVP1012</NoWarn>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <PropertyGroup>
   <PropertyGroup>

+ 3 - 0
samples/IntegrationTestApp/MainWindow.axaml

@@ -47,6 +47,9 @@
           <Button Name="DisabledButton" IsEnabled="False">
           <Button Name="DisabledButton" IsEnabled="False">
             Disabled Button
             Disabled Button
           </Button>
           </Button>
+          <Button Name="EffectivelyDisabledButton" Command="{ReflectionBinding DoesntExist}">
+            Effectively Disabled Button
+          </Button>
           <Button Name="BasicButton">
           <Button Name="BasicButton">
             Basic Button
             Basic Button
           </Button>
           </Button>

+ 2 - 2
samples/IntegrationTestApp/MainWindow.axaml.cs

@@ -202,7 +202,7 @@ namespace IntegrationTestApp
         {
         {
             var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
             var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
 
 
-            foreach (var window in lifetime.Windows)
+            foreach (var window in lifetime.Windows.ToArray())
             {
             {
                 window.Activate();
                 window.Activate();
             }
             }
@@ -212,7 +212,7 @@ namespace IntegrationTestApp
         {
         {
             var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
             var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
 
 
-            foreach (var window in lifetime.Windows)
+            foreach (var window in lifetime.Windows.ToArray())
             {
             {
                 window.Show();
                 window.Show();
                 if (window.WindowState == WindowState.Minimized)
                 if (window.WindowState == WindowState.Minimized)

+ 5 - 5
samples/RenderDemo/Pages/CustomSkiaPage.cs

@@ -27,11 +27,11 @@ namespace RenderDemo.Pages
         
         
         class CustomDrawOp : ICustomDrawOperation
         class CustomDrawOp : ICustomDrawOperation
         {
         {
-            private readonly GlyphRun _noSkia;
+            private readonly IImmutableGlyphRunReference _noSkia;
 
 
             public CustomDrawOp(Rect bounds, GlyphRun noSkia)
             public CustomDrawOp(Rect bounds, GlyphRun noSkia)
             {
             {
-                _noSkia = noSkia;
+                _noSkia = noSkia.TryCreateImmutableGlyphRunReference();
                 Bounds = bounds;
                 Bounds = bounds;
             }
             }
             
             
@@ -44,11 +44,11 @@ namespace RenderDemo.Pages
             public bool HitTest(Point p) => false;
             public bool HitTest(Point p) => false;
             public bool Equals(ICustomDrawOperation other) => false;
             public bool Equals(ICustomDrawOperation other) => false;
             static Stopwatch St = Stopwatch.StartNew();
             static Stopwatch St = Stopwatch.StartNew();
-            public void Render(IDrawingContextImpl context)
+            public void Render(ImmediateDrawingContext context)
             {
             {
-                var leaseFeature = context.GetFeature<ISkiaSharpApiLeaseFeature>();
+                var leaseFeature = context.TryGetFeature<ISkiaSharpApiLeaseFeature>();
                 if (leaseFeature == null)
                 if (leaseFeature == null)
-                    context.DrawGlyphRun(Brushes.Black, _noSkia.PlatformImpl);
+                    context.DrawGlyphRun(Brushes.Black, _noSkia);
                 else
                 else
                 {
                 {
                     using var lease = leaseFeature.Lease();
                     using var lease = leaseFeature.Lease();

+ 4 - 4
samples/RenderDemo/Pages/PathMeasurementPage.cs

@@ -53,15 +53,15 @@ namespace RenderDemo.Pages
                 bitmapCtx.DrawGeometry(null, strokePen, basePath);
                 bitmapCtx.DrawGeometry(null, strokePen, basePath);
 
 
 
 
-                var length = basePath.PlatformImpl.ContourLength;
+                var length = basePath.ContourLength;
 
 
-                if (basePath.PlatformImpl.TryGetSegment(length * 0.05, length * 0.2, true, out var dst1))
+                if (basePath.TryGetSegment(length * 0.05, length * 0.2, true, out var dst1))
                     bitmapCtx.DrawGeometry(null, strokePen1, dst1);
                     bitmapCtx.DrawGeometry(null, strokePen1, dst1);
 
 
-                if (basePath.PlatformImpl.TryGetSegment(length * 0.2, length * 0.8, true, out var dst2))
+                if (basePath.TryGetSegment(length * 0.2, length * 0.8, true, out var dst2))
                     bitmapCtx.DrawGeometry(null, strokePen2, dst2);
                     bitmapCtx.DrawGeometry(null, strokePen2, dst2);
 
 
-                if (basePath.PlatformImpl.TryGetSegment(length * 0.8, length * 0.95, true, out var dst3))
+                if (basePath.TryGetSegment(length * 0.8, length * 0.95, true, out var dst3))
                     bitmapCtx.DrawGeometry(null, strokePen3, dst3);
                     bitmapCtx.DrawGeometry(null, strokePen3, dst3);
                 
                 
                 var pathBounds = basePath.GetRenderBounds(strokePen);
                 var pathBounds = basePath.GetRenderBounds(strokePen);

+ 1 - 1
samples/RenderDemo/Pages/WriteableBitmapPage.cs

@@ -59,7 +59,7 @@ namespace RenderDemo.Pages
                                 color = new Color(fillAlpha, r, g, b);
                                 color = new Color(fillAlpha, r, g, b);
                             }
                             }
 
 
-                            data[y * fb.Size.Width + x] = (int) color.ToUint32();
+                            data[y * fb.Size.Width + x] = (int) color.ToUInt32();
                         }
                         }
                     }
                     }
 
 

+ 1 - 1
samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj

@@ -14,7 +14,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
+    <ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
     <ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
     <ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />

+ 3 - 8
samples/Sandbox/MainWindow.axaml.cs

@@ -1,22 +1,17 @@
 using Avalonia;
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Presenters;
+using Avalonia.Input.TextInput;
 using Avalonia.Markup.Xaml;
 using Avalonia.Markup.Xaml;
 using Avalonia.Win32.WinRT.Composition;
 using Avalonia.Win32.WinRT.Composition;
 
 
 namespace Sandbox
 namespace Sandbox
 {
 {
-    public class MainWindow : Window
+    public partial class MainWindow : Window
     {
     {
         public MainWindow()
         public MainWindow()
         {
         {
-            this.InitializeComponent();
-            this.AttachDevTools();
-        }
-
-        private void InitializeComponent()
-        {
-            AvaloniaXamlLoader.Load(this);
+            InitializeComponent();
         }
         }
     }
     }
 }
 }

+ 2 - 0
samples/Sandbox/Sandbox.csproj

@@ -4,6 +4,7 @@
     <OutputType>WinExe</OutputType>
     <OutputType>WinExe</OutputType>
     <TargetFramework>net6.0</TargetFramework>
     <TargetFramework>net6.0</TargetFramework>
     <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
     <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
+    <IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
@@ -17,4 +18,5 @@
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\ReferenceCoreLibraries.props" />
   <Import Project="..\..\build\ReferenceCoreLibraries.props" />
   <Import Project="..\..\build\BuildTargets.targets" />
   <Import Project="..\..\build\BuildTargets.targets" />
+  <Import Project="..\..\build\SourceGenerators.props" />
 </Project>
 </Project>

+ 3 - 3
samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs

@@ -24,19 +24,19 @@ public class PlaygroundPageViewModel : ViewModelBase
 
 
     public bool Multiple
     public bool Multiple
     {
     {
-        get => _selectionMode.HasAnyFlag(SelectionMode.Multiple);
+        get => _selectionMode.HasFlag(SelectionMode.Multiple);
         set => SetSelectionMode(SelectionMode.Multiple, value);
         set => SetSelectionMode(SelectionMode.Multiple, value);
     }
     }
 
 
     public bool Toggle
     public bool Toggle
     {
     {
-        get => _selectionMode.HasAnyFlag(SelectionMode.Toggle);
+        get => _selectionMode.HasFlag(SelectionMode.Toggle);
         set => SetSelectionMode(SelectionMode.Toggle, value);
         set => SetSelectionMode(SelectionMode.Toggle, value);
     }
     }
 
 
     public bool AlwaysSelected
     public bool AlwaysSelected
     {
     {
-        get => _selectionMode.HasAnyFlag(SelectionMode.AlwaysSelected);
+        get => _selectionMode.HasFlag(SelectionMode.AlwaysSelected);
         set => SetSelectionMode(SelectionMode.AlwaysSelected, value);
         set => SetSelectionMode(SelectionMode.AlwaysSelected, value);
     }
     }
 
 

+ 58 - 54
src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs

@@ -5,8 +5,9 @@ using Avalonia.Input;
 
 
 namespace Avalonia.Android.Platform.Input
 namespace Avalonia.Android.Platform.Input
 {
 {
-    internal class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
-    private static readonly Dictionary<Keycode, Key> KeyDic = new Dictionary<Keycode, Key>
+    internal class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice
+    {
+        private static readonly Dictionary<Keycode, Key> KeyDic = new Dictionary<Keycode, Key>
      {
      {
          //   { Keycode.Cancel?, Key.Cancel },
          //   { Keycode.Cancel?, Key.Cancel },
             { Keycode.Del, Key.Back },
             { Keycode.Del, Key.Back },
@@ -15,7 +16,7 @@ namespace Avalonia.Android.Platform.Input
             { Keycode.Clear, Key.Clear },
             { Keycode.Clear, Key.Clear },
             { Keycode.Enter, Key.Return },
             { Keycode.Enter, Key.Return },
             { Keycode.MediaPause, Key.Pause },
             { Keycode.MediaPause, Key.Pause },
-            //{ Keycode.?, Key.CapsLock }
+            { Keycode.CapsLock, Key.CapsLock },
             //{ Keycode.?, Key.HangulMode }
             //{ Keycode.?, Key.HangulMode }
             //{ Keycode.?, Key.JunjaMode }
             //{ Keycode.?, Key.JunjaMode }
             //{ Keycode.?, Key.FinalMode }
             //{ Keycode.?, Key.FinalMode }
@@ -28,8 +29,8 @@ namespace Avalonia.Android.Platform.Input
             { Keycode.Space, Key.Space },
             { Keycode.Space, Key.Space },
             { Keycode.PageUp, Key.Prior },
             { Keycode.PageUp, Key.Prior },
             { Keycode.PageDown, Key.PageDown },
             { Keycode.PageDown, Key.PageDown },
-           // { Keycode.end?, Key.End },
-            { Keycode.Home, Key.Home },
+            { Keycode.MoveEnd, Key.End },
+            { Keycode.MoveHome, Key.Home },
             { Keycode.DpadLeft, Key.Left },
             { Keycode.DpadLeft, Key.Left },
             { Keycode.DpadUp, Key.Up },
             { Keycode.DpadUp, Key.Up },
             { Keycode.DpadRight, Key.Right },
             { Keycode.DpadRight, Key.Right },
@@ -37,20 +38,20 @@ namespace Avalonia.Android.Platform.Input
            // { Keycode.ButtonSelect?, Key.Select },
            // { Keycode.ButtonSelect?, Key.Select },
            // { Keycode.print?, Key.Print },
            // { Keycode.print?, Key.Print },
             //{ Keycode.execute?, Key.Execute },
             //{ Keycode.execute?, Key.Execute },
-           // { Keycode.snap, Key.Snapshot }
+            //{ Keycode.snap?, Key.Snapshot }
             { Keycode.Insert, Key.Insert },
             { Keycode.Insert, Key.Insert },
             { Keycode.ForwardDel, Key.Delete },
             { Keycode.ForwardDel, Key.Delete },
-            //{ Keycode.help, Key.Help },
-            //{ Keycode.?, Key.D0 }
-            //{ Keycode.?, Key.D1 }
-            //{ Keycode.?, Key.D2 }
-            //{ Keycode.?, Key.D3 }
-            //{ Keycode.?, Key.D4 }
-            //{ Keycode.?, Key.D5 }
-            //{ Keycode.?, Key.D6 }
-            //{ Keycode.?, Key.D7 }
-            //{ Keycode.?, Key.D8 }
-            //{ Keycode.?, Key.D9 }
+            { Keycode.Help, Key.Help },
+            { Keycode.Num0, Key.D0 },
+            { Keycode.Num1, Key.D1 },
+            { Keycode.Num2, Key.D2 },
+            { Keycode.Num3, Key.D3 },
+            { Keycode.Num4, Key.D4 },
+            { Keycode.Num5, Key.D5 },
+            { Keycode.Num6, Key.D6 },
+            { Keycode.Num7, Key.D7 },
+            { Keycode.Num8, Key.D8 },
+            { Keycode.Num9, Key.D9 },
             { Keycode.A, Key.A },
             { Keycode.A, Key.A },
             { Keycode.B, Key.B },
             { Keycode.B, Key.B },
             { Keycode.C, Key.C },
             { Keycode.C, Key.C },
@@ -106,22 +107,22 @@ namespace Avalonia.Android.Platform.Input
             //{ Keycode.?, Key.LWin }
             //{ Keycode.?, Key.LWin }
             //{ Keycode.?, Key.RWin }
             //{ Keycode.?, Key.RWin }
             //{ Keycode.?, Key.Apps }
             //{ Keycode.?, Key.Apps }
-            //{ Keycode.?, Key.Sleep }
-            //{ Keycode.?, Key.NumPad0 }
-            //{ Keycode.?, Key.NumPad1 }
-            //{ Keycode.?, Key.NumPad2 }
-            //{ Keycode.?, Key.NumPad3 }
-            //{ Keycode.?, Key.NumPad4 }
-            //{ Keycode.?, Key.NumPad5 }
-            //{ Keycode.?, Key.NumPad6 }
-            //{ Keycode.?, Key.NumPad7 }
-            //{ Keycode.?, Key.NumPad8 }
-            //{ Keycode.?, Key.NumPad9 }
+            { Keycode.Sleep, Key.Sleep },
+            { Keycode.Numpad0, Key.NumPad0 },
+            { Keycode.Numpad1, Key.NumPad1 },
+            { Keycode.Numpad2, Key.NumPad2 },
+            { Keycode.Numpad3, Key.NumPad3 },
+            { Keycode.Numpad4, Key.NumPad4 },
+            { Keycode.Numpad5, Key.NumPad5 },
+            { Keycode.Numpad6, Key.NumPad6 },
+            { Keycode.Numpad7, Key.NumPad7 },
+            { Keycode.Numpad8, Key.NumPad8 },
+            { Keycode.Numpad9, Key.NumPad9 },
             { Keycode.NumpadMultiply, Key.Multiply },
             { Keycode.NumpadMultiply, Key.Multiply },
             { Keycode.NumpadAdd, Key.Add },
             { Keycode.NumpadAdd, Key.Add },
             { Keycode.NumpadComma, Key.Separator },
             { Keycode.NumpadComma, Key.Separator },
             { Keycode.NumpadSubtract, Key.Subtract },
             { Keycode.NumpadSubtract, Key.Subtract },
-            //{ Keycode.numpaddecimal?, Key.Decimal }
+            { Keycode.NumpadDot, Key.Decimal },
             { Keycode.NumpadDivide, Key.Divide },
             { Keycode.NumpadDivide, Key.Divide },
             { Keycode.F1, Key.F1 },
             { Keycode.F1, Key.F1 },
             { Keycode.F2, Key.F2 },
             { Keycode.F2, Key.F2 },
@@ -147,14 +148,14 @@ namespace Avalonia.Android.Platform.Input
             //{ Keycode.R2, Key.F22 },
             //{ Keycode.R2, Key.F22 },
             //{ Keycode.F23, Key.F23 },
             //{ Keycode.F23, Key.F23 },
             //{ Keycode.R4, Key.F24 },
             //{ Keycode.R4, Key.F24 },
-           // { Keycode.numpad, Key.NumLock }
+            { Keycode.NumLock, Key.NumLock },
             { Keycode.ScrollLock, Key.Scroll },
             { Keycode.ScrollLock, Key.Scroll },
             { Keycode.ShiftLeft, Key.LeftShift },
             { Keycode.ShiftLeft, Key.LeftShift },
-            //{ Keycode.?, Key.RightShift }
-            //{ Keycode.?, Key.LeftCtrl }
-            //{ Keycode.?, Key.RightCtrl }
-            //{ Keycode.?, Key.LeftAlt }
-            //{ Keycode.?, Key.RightAlt }
+            { Keycode.ShiftRight, Key.RightShift },
+            { Keycode.CtrlLeft, Key.LeftCtrl },
+            { Keycode.CtrlRight, Key.RightCtrl },
+            { Keycode.AltLeft, Key.LeftAlt },
+            { Keycode.AltRight, Key.RightAlt },
             //{ Keycode.?, Key.BrowserBack }
             //{ Keycode.?, Key.BrowserBack }
             //{ Keycode.?, Key.BrowserForward }
             //{ Keycode.?, Key.BrowserForward }
             //{ Keycode.?, Key.BrowserRefresh }
             //{ Keycode.?, Key.BrowserRefresh }
@@ -163,28 +164,30 @@ namespace Avalonia.Android.Platform.Input
             //{ Keycode.?, Key.BrowserFavorites }
             //{ Keycode.?, Key.BrowserFavorites }
             //{ Keycode.?, Key.BrowserHome }
             //{ Keycode.?, Key.BrowserHome }
             //{ Keycode.?, Key.VolumeMute }
             //{ Keycode.?, Key.VolumeMute }
-            //{ Keycode.?, Key.VolumeDown }
-            //{ Keycode.?, Key.VolumeUp }
-            //{ Keycode.?, Key.MediaNextTrack }
-            //{ Keycode.?, Key.MediaPreviousTrack }
-            //{ Keycode.?, Key.MediaStop }
-            //{ Keycode.?, Key.MediaPlayPause }
+            { Keycode.VolumeDown, Key.VolumeDown },
+            { Keycode.VolumeUp, Key.VolumeUp },
+            { Keycode.MediaNext, Key.MediaNextTrack },
+            { Keycode.MediaPrevious, Key.MediaPreviousTrack },
+            { Keycode.MediaStop, Key.MediaStop },
+            { Keycode.MediaPlayPause, Key.MediaPlayPause },
             //{ Keycode.?, Key.LaunchMail }
             //{ Keycode.?, Key.LaunchMail }
             //{ Keycode.?, Key.SelectMedia }
             //{ Keycode.?, Key.SelectMedia }
             //{ Keycode.?, Key.LaunchApplication1 }
             //{ Keycode.?, Key.LaunchApplication1 }
             //{ Keycode.?, Key.LaunchApplication2 }
             //{ Keycode.?, Key.LaunchApplication2 }
-            //{ Keycode.?, Key.OemSemicolon }
-            //{ Keycode.?, Key.OemPlus }
-            //{ Keycode.?, Key.OemComma }
-            //{ Keycode.?, Key.OemMinus }
-            //{ Keycode.?, Key.OemPeriod }
+            { Keycode.Semicolon, Key.OemSemicolon },
+            { Keycode.Plus, Key.OemPlus },
+            { Keycode.Comma, Key.OemComma },
+            { Keycode.Minus, Key.OemMinus },
+            { Keycode.Period, Key.OemPeriod },
             //{ Keycode.?, Key.Oem2 }
             //{ Keycode.?, Key.Oem2 }
-            //{ Keycode.?, Key.OemTilde }
+            { Keycode.Grave, Key.OemTilde },
             //{ Keycode.?, Key.AbntC1 }
             //{ Keycode.?, Key.AbntC1 }
             //{ Keycode.?, Key.AbntC2 }
             //{ Keycode.?, Key.AbntC2 }
-            //{ Keycode.?, Key.Oem4 }
             //{ Keycode.?, Key.OemPipe }
             //{ Keycode.?, Key.OemPipe }
-            //{ Keycode.?, Key.OemCloseBrackets }
+            { Keycode.Apostrophe, Key.OemQuotes },
+            { Keycode.Slash, Key.OemQuestion },
+            { Keycode.LeftBracket, Key.OemOpenBrackets },
+            { Keycode.RightBracket, Key.OemCloseBrackets },
             //{ Keycode.?, Key.Oem7 }
             //{ Keycode.?, Key.Oem7 }
             //{ Keycode.?, Key.Oem8 }
             //{ Keycode.?, Key.Oem8 }
             //{ Keycode.?, Key.Oem102 }
             //{ Keycode.?, Key.Oem102 }
@@ -200,17 +203,18 @@ namespace Avalonia.Android.Platform.Input
             //{ Keycode.?, Key.DbeEnterWordRegisterMode }
             //{ Keycode.?, Key.DbeEnterWordRegisterMode }
             //{ Keycode.?, Key.DbeEnterImeConfigureMode }
             //{ Keycode.?, Key.DbeEnterImeConfigureMode }
             //{ Keycode.?, Key.EraseEof }
             //{ Keycode.?, Key.EraseEof }
-            //{ Keycode.?, Key.Play }
+            { Keycode.MediaPlay, Key.Play },
             //{ Keycode.?, Key.Zoom }
             //{ Keycode.?, Key.Zoom }
             //{ Keycode.?, Key.NoName }
             //{ Keycode.?, Key.NoName }
             //{ Keycode.?, Key.DbeEnterDialogConversionMode }
             //{ Keycode.?, Key.DbeEnterDialogConversionMode }
             //{ Keycode.?, Key.OemClear }
             //{ Keycode.?, Key.OemClear }
             //{ Keycode.?, Key.DeadCharProcessed }
             //{ Keycode.?, Key.DeadCharProcessed }
+            { Keycode.Backslash, Key.OemBackslash }
         };
         };
 
 
-    internal static Key ConvertKey(Keycode key) {
-      Key result;
-      return KeyDic.TryGetValue(key, out result) ? result : Key.None;
+        internal static Key ConvertKey(Keycode key)
+        {
+            return KeyDic.TryGetValue(key, out var result) ? result : Key.None;
+        }
     }
     }
-  }
 }
 }

+ 2 - 2
src/Avalonia.Base/Animation/Animatable.cs

@@ -58,7 +58,7 @@ namespace Avalonia.Animation
         /// This method should not be called from user code, it will be called automatically by the framework
         /// This method should not be called from user code, it will be called automatically by the framework
         /// when a control is added to the visual tree.
         /// when a control is added to the visual tree.
         /// </remarks>
         /// </remarks>
-        protected void EnableTransitions()
+        internal void EnableTransitions()
         {
         {
             if (!_transitionsEnabled)
             if (!_transitionsEnabled)
             {
             {
@@ -83,7 +83,7 @@ namespace Avalonia.Animation
         /// This method should not be called from user code, it will be called automatically by the framework
         /// This method should not be called from user code, it will be called automatically by the framework
         /// when a control is removed from the visual tree.
         /// when a control is removed from the visual tree.
         /// </remarks>
         /// </remarks>
-        protected void DisableTransitions()
+        internal void DisableTransitions()
         {
         {
             if (_transitionsEnabled)
             if (_transitionsEnabled)
             {
             {

+ 7 - 5
src/Avalonia.Base/Animation/Animation.cs

@@ -200,7 +200,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         /// <param name="setter">The animation setter.</param>
         /// <param name="setter">The animation setter.</param>
         /// <param name="value">The property animator value.</param>
         /// <param name="value">The property animator value.</param>
-        public static void SetAnimator(IAnimationSetter setter, 
+        public static void SetAnimator(IAnimationSetter setter,
             [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
             [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
             Type value)
             Type value)
         {
         {
@@ -319,7 +319,7 @@ namespace Avalonia.Animation
             if (animators.Count == 1)
             if (animators.Count == 1)
             {
             {
                 var subscription = animators[0].Apply(this, control, clock, match, onComplete);
                 var subscription = animators[0].Apply(this, control, clock, match, onComplete);
-                
+
                 if (subscription is not null)
                 if (subscription is not null)
                 {
                 {
                     subscriptions.Add(subscription);
                     subscriptions.Add(subscription);
@@ -348,9 +348,11 @@ namespace Avalonia.Animation
 
 
                 if (onComplete != null)
                 if (onComplete != null)
                 {
                 {
-                    Task.WhenAll(completionTasks!).ContinueWith(
-                        (_, state) => ((Action)state!).Invoke(),
-                        onComplete);
+                    Task.WhenAll(completionTasks!)
+                        .ContinueWith((_, state) => ((Action)state!).Invoke()
+                            , onComplete
+                            , TaskScheduler.FromCurrentSynchronizationContext()
+                            );
                 }
                 }
             }
             }
             return new CompositeDisposable(subscriptions);
             return new CompositeDisposable(subscriptions);

+ 1 - 1
src/Avalonia.Base/Animation/AnimatorKeyFrame.cs

@@ -67,7 +67,7 @@ namespace Avalonia.Animation
             }
             }
         }
         }
 
 
-        [RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
+        [RequiresUnreferencedCode(TrimmingMessages.TypeConversionRequiresUnreferencedCodeMessage)]
         public T GetTypedValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
         public T GetTypedValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
         {
         {
             var typeConv = TypeDescriptor.GetConverter(typeof(T));
             var typeConv = TypeDescriptor.GetConverter(typeof(T));

+ 4 - 2
src/Avalonia.Base/AttachedProperty.cs

@@ -13,16 +13,18 @@ namespace Avalonia
         /// </summary>
         /// </summary>
         /// <param name="name">The name of the property.</param>
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The class that is registering the property.</param>
         /// <param name="ownerType">The class that is registering the property.</param>
+        /// <param name="hostType">The class that the property being is registered on.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="inherits">Whether the property inherits its value.</param>
         /// <param name="inherits">Whether the property inherits its value.</param>
         /// <param name="validate">A value validation callback.</param>
         /// <param name="validate">A value validation callback.</param>
-        public AttachedProperty(
+        internal AttachedProperty(
             string name,
             string name,
             Type ownerType,
             Type ownerType,
+            Type hostType,
             StyledPropertyMetadata<TValue> metadata,
             StyledPropertyMetadata<TValue> metadata,
             bool inherits = false,
             bool inherits = false,
             Func<TValue, bool>? validate = null)
             Func<TValue, bool>? validate = null)
-            : base(name, ownerType, metadata, inherits, validate)
+            : base(name, ownerType, hostType, metadata, inherits, validate)
         {
         {
             IsAttached = true;
             IsAttached = true;
         }
         }

+ 2 - 0
src/Avalonia.Base/Avalonia.Base.csproj

@@ -22,6 +22,7 @@
   <Import Project="..\..\build\SourceGenerators.props" />
   <Import Project="..\..\build\SourceGenerators.props" />
   <ItemGroup>
   <ItemGroup>
     <Compile Include="..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" />
     <Compile Include="..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" />
+    <Compile Include="..\Shared\ModuleInitializer.cs" Link="ModuleInitializer.cs" />
     <Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" />
     <Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" />
   </ItemGroup>
   </ItemGroup>
 
 
@@ -62,6 +63,7 @@
     <InternalsVisibleTo Include="Avalonia.iOS, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.iOS, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Dialogs, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Dialogs, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Diagnostics, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Diagnostics, PublicKey=$(AvaloniaPublicKey)" />
+    <InternalsVisibleTo Include="Avalonia.LinuxFramebuffer, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="MiniMvvm, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="MiniMvvm, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="ControlCatalog, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="ControlCatalog, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />
     <InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />

+ 14 - 10
src/Avalonia.Base/AvaloniaProperty.cs

@@ -39,12 +39,14 @@ namespace Avalonia
         /// <param name="name">The name of the property.</param>
         /// <param name="name">The name of the property.</param>
         /// <param name="valueType">The type of the property's value.</param>
         /// <param name="valueType">The type of the property's value.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
+        /// <param name="hostType">The class that the property being is registered on.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="notifying">A <see cref="Notifying"/> callback.</param>
         /// <param name="notifying">A <see cref="Notifying"/> callback.</param>
-        protected AvaloniaProperty(
+        private protected AvaloniaProperty(
             string name,
             string name,
             Type valueType,
             Type valueType,
             Type ownerType,
             Type ownerType,
+            Type hostType,
             AvaloniaPropertyMetadata metadata,
             AvaloniaPropertyMetadata metadata,
             Action<AvaloniaObject, bool>? notifying = null)
             Action<AvaloniaObject, bool>? notifying = null)
         {
         {
@@ -63,9 +65,9 @@ namespace Avalonia
             Notifying = notifying;
             Notifying = notifying;
             Id = s_nextId++;
             Id = s_nextId++;
 
 
-            _metadata.Add(ownerType, metadata ?? throw new ArgumentNullException(nameof(metadata)));
+            _metadata.Add(hostType, metadata ?? throw new ArgumentNullException(nameof(metadata)));
             _defaultMetadata = metadata.GenerateTypeSafeMetadata();
             _defaultMetadata = metadata.GenerateTypeSafeMetadata();
-            _singleMetadata = new(ownerType, metadata);
+            _singleMetadata = new(hostType, metadata);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -74,7 +76,7 @@ namespace Avalonia
         /// <param name="source">The direct property to copy.</param>
         /// <param name="source">The direct property to copy.</param>
         /// <param name="ownerType">The new owner type.</param>
         /// <param name="ownerType">The new owner type.</param>
         /// <param name="metadata">Optional overridden metadata.</param>
         /// <param name="metadata">Optional overridden metadata.</param>
-        protected AvaloniaProperty(
+        private protected AvaloniaProperty(
             AvaloniaProperty source,
             AvaloniaProperty source,
             Type ownerType,
             Type ownerType,
             AvaloniaPropertyMetadata? metadata)
             AvaloniaPropertyMetadata? metadata)
@@ -151,7 +153,7 @@ namespace Avalonia
         /// will be true before the property change notifications are sent and false afterwards. This
         /// will be true before the property change notifications are sent and false afterwards. This
         /// callback is intended to support Control.IsDataContextChanging.
         /// callback is intended to support Control.IsDataContextChanging.
         /// </remarks>
         /// </remarks>
-        public Action<AvaloniaObject, bool>? Notifying { get; }
+        internal Action<AvaloniaObject, bool>? Notifying { get; }
 
 
         /// <summary>
         /// <summary>
         /// Gets the integer ID that represents this property.
         /// Gets the integer ID that represents this property.
@@ -255,6 +257,7 @@ namespace Avalonia
             var result = new StyledProperty<TValue>(
             var result = new StyledProperty<TValue>(
                 name,
                 name,
                 typeof(TOwner),
                 typeof(TOwner),
+                typeof(TOwner),
                 metadata,
                 metadata,
                 inherits,
                 inherits,
                 validate);
                 validate);
@@ -301,6 +304,7 @@ namespace Avalonia
             var result = new StyledProperty<TValue>(
             var result = new StyledProperty<TValue>(
                 name,
                 name,
                 typeof(TOwner),
                 typeof(TOwner),
+                typeof(TOwner),
                 metadata,
                 metadata,
                 inherits,
                 inherits,
                 validate,
                 validate,
@@ -338,7 +342,7 @@ namespace Avalonia
                 defaultBindingMode: defaultBindingMode,
                 defaultBindingMode: defaultBindingMode,
                 coerce: coerce);
                 coerce: coerce);
 
 
-            var result = new AttachedProperty<TValue>(name, typeof(TOwner), metadata, inherits, validate);
+            var result = new AttachedProperty<TValue>(name, typeof(TOwner), typeof(THost), metadata, inherits, validate);
             var registry = AvaloniaPropertyRegistry.Instance;
             var registry = AvaloniaPropertyRegistry.Instance;
             registry.Register(typeof(TOwner), result);
             registry.Register(typeof(TOwner), result);
             registry.RegisterAttached(typeof(THost), result);
             registry.RegisterAttached(typeof(THost), result);
@@ -375,7 +379,7 @@ namespace Avalonia
                 defaultBindingMode: defaultBindingMode,
                 defaultBindingMode: defaultBindingMode,
                 coerce: coerce);
                 coerce: coerce);
 
 
-            var result = new AttachedProperty<TValue>(name, ownerType, metadata, inherits, validate);
+            var result = new AttachedProperty<TValue>(name, ownerType, typeof(THost), metadata, inherits, validate);
             var registry = AvaloniaPropertyRegistry.Instance;
             var registry = AvaloniaPropertyRegistry.Instance;
             registry.Register(ownerType, result);
             registry.Register(ownerType, result);
             registry.RegisterAttached(typeof(THost), result);
             registry.RegisterAttached(typeof(THost), result);
@@ -472,7 +476,7 @@ namespace Avalonia
         /// </summary>
         /// </summary>
         /// <param name="value">The value.</param>
         /// <param name="value">The value.</param>
         /// <returns>True if the value is valid, otherwise false.</returns>
         /// <returns>True if the value is valid, otherwise false.</returns>
-        [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
+        [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConversionRequiresUnreferencedCodeMessage)]
         public bool IsValidValue(object? value)
         public bool IsValidValue(object? value)
         {
         {
             return TypeUtilities.TryConvertImplicit(PropertyType, value, out _);
             return TypeUtilities.TryConvertImplicit(PropertyType, value, out _);
@@ -554,7 +558,7 @@ namespace Avalonia
         /// </summary>
         /// </summary>
         /// <param name="type">The type.</param>
         /// <param name="type">The type.</param>
         /// <param name="metadata">The metadata.</param>
         /// <param name="metadata">The metadata.</param>
-        protected void OverrideMetadata(Type type, AvaloniaPropertyMetadata metadata)
+        private protected void OverrideMetadata(Type type, AvaloniaPropertyMetadata metadata)
         {
         {
             _ = type ?? throw new ArgumentNullException(nameof(type));
             _ = type ?? throw new ArgumentNullException(nameof(type));
             _ = metadata ?? throw new ArgumentNullException(nameof(metadata));
             _ = metadata ?? throw new ArgumentNullException(nameof(metadata));
@@ -573,7 +577,7 @@ namespace Avalonia
             _singleMetadata = null;
             _singleMetadata = null;
         }
         }
 
 
-        protected abstract IObservable<AvaloniaPropertyChangedEventArgs> GetChanged();
+        private protected abstract IObservable<AvaloniaPropertyChangedEventArgs> GetChanged();
 
 
         private AvaloniaPropertyMetadata GetMetadataWithOverrides(Type type)
         private AvaloniaPropertyMetadata GetMetadataWithOverrides(Type type)
         {
         {

+ 1 - 1
src/Avalonia.Base/AvaloniaPropertyExtensions.cs

@@ -7,7 +7,7 @@ namespace Avalonia
     /// <summary>
     /// <summary>
     /// Extensions for <see cref="AvaloniaProperty"/>.
     /// Extensions for <see cref="AvaloniaProperty"/>.
     /// </summary>
     /// </summary>
-    public static class AvaloniaPropertyExtensions
+    internal static class AvaloniaPropertyExtensions
     {
     {
         /// <summary>
         /// <summary>
         /// Checks if values of given property can affect rendering (via <see cref="IAffectsRender"/>).
         /// Checks if values of given property can affect rendering (via <see cref="IAffectsRender"/>).

+ 8 - 6
src/Avalonia.Base/AvaloniaProperty`1.cs

@@ -19,14 +19,16 @@ namespace Avalonia
         /// </summary>
         /// </summary>
         /// <param name="name">The name of the property.</param>
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
+        /// <param name="hostType">The class that the property being is registered on.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="notifying">A <see cref="AvaloniaProperty.Notifying"/> callback.</param>
         /// <param name="notifying">A <see cref="AvaloniaProperty.Notifying"/> callback.</param>
-        protected AvaloniaProperty(
+        private protected AvaloniaProperty(
             string name,
             string name,
             Type ownerType,
             Type ownerType,
+            Type hostType,
             AvaloniaPropertyMetadata metadata,
             AvaloniaPropertyMetadata metadata,
             Action<AvaloniaObject, bool>? notifying = null)
             Action<AvaloniaObject, bool>? notifying = null)
-            : base(name, typeof(TValue), ownerType, metadata, notifying)
+            : base(name, typeof(TValue), ownerType, hostType, metadata, notifying)
         {
         {
             _changed = new LightweightSubject<AvaloniaPropertyChangedEventArgs<TValue>>();
             _changed = new LightweightSubject<AvaloniaPropertyChangedEventArgs<TValue>>();
         }
         }
@@ -37,7 +39,7 @@ namespace Avalonia
         /// <param name="source">The property to copy.</param>
         /// <param name="source">The property to copy.</param>
         /// <param name="ownerType">The new owner type.</param>
         /// <param name="ownerType">The new owner type.</param>
         /// <param name="metadata">Optional overridden metadata.</param>
         /// <param name="metadata">Optional overridden metadata.</param>
-        protected AvaloniaProperty(
+        private protected AvaloniaProperty(
             AvaloniaProperty<TValue> source,
             AvaloniaProperty<TValue> source,
             Type ownerType,
             Type ownerType,
             AvaloniaPropertyMetadata? metadata)
             AvaloniaPropertyMetadata? metadata)
@@ -66,10 +68,10 @@ namespace Avalonia
             _changed.OnNext(e);
             _changed.OnNext(e);
         }
         }
 
 
-        protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
+        private protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
 
 
-        [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
-        protected BindingValue<object?> TryConvert(object? value)
+        [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConversionSupressWarningMessage)]
+        private protected BindingValue<object?> TryConvert(object? value)
         {
         {
             if (value == UnsetValue)
             if (value == UnsetValue)
             {
             {

+ 2 - 0
src/Avalonia.Base/ClassBindingManager.cs

@@ -17,6 +17,8 @@ namespace Avalonia
             return target.Bind(prop, source, anchor);
             return target.Bind(prop, source, anchor);
         }
         }
 
 
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1001:The same AvaloniaProperty should not be registered twice",
+            Justification = "Classes.attr binding feature is implemented using intermediate avalonia properties for each class")]
         private static AvaloniaProperty RegisterClassProxyProperty(string className)
         private static AvaloniaProperty RegisterClassProxyProperty(string className)
         {
         {
             var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);
             var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);

+ 1 - 1
src/Avalonia.Base/Collections/AvaloniaDictionaryExtensions.cs

@@ -35,7 +35,7 @@ namespace Avalonia.Collections
         /// Indicates if a weak subscription should be used to track changes to the collection.
         /// Indicates if a weak subscription should be used to track changes to the collection.
         /// </param>
         /// </param>
         /// <returns>A disposable used to terminate the subscription.</returns>
         /// <returns>A disposable used to terminate the subscription.</returns>
-        internal static IDisposable ForEachItem<TKey, TValue>(
+        public static IDisposable ForEachItem<TKey, TValue>(
             this IAvaloniaReadOnlyDictionary<TKey, TValue> collection,
             this IAvaloniaReadOnlyDictionary<TKey, TValue> collection,
             Action<TKey, TValue> added,
             Action<TKey, TValue> added,
             Action<TKey, TValue> removed,
             Action<TKey, TValue> removed,

+ 1 - 1
src/Avalonia.Base/Collections/AvaloniaListConverter.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Collections
     /// <summary>
     /// <summary>
     /// Creates an <see cref="AvaloniaList{T}"/> from a string representation.
     /// Creates an <see cref="AvaloniaList{T}"/> from a string representation.
     /// </summary>
     /// </summary>
-    [RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
+    [RequiresUnreferencedCode(TrimmingMessages.TypeConversionRequiresUnreferencedCodeMessage)]
     public class AvaloniaListConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : TypeConverter
     public class AvaloniaListConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : TypeConverter
     {
     {
         public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
         public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)

+ 1 - 1
src/Avalonia.Base/Collections/Pooled/ClearMode.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Collections.Pooled
     /// what each option does before using anything other than the default
     /// what each option does before using anything other than the default
     /// of Auto.
     /// of Auto.
     /// </summary>
     /// </summary>
-    public enum ClearMode
+    internal enum ClearMode
     {
     {
         /// <summary>
         /// <summary>
         /// <para><code>Auto</code> has different behavior depending on the host project's target framework.</para>
         /// <para><code>Auto</code> has different behavior depending on the host project's target framework.</para>

+ 1 - 1
src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Collections.Pooled
     /// </summary>
     /// </summary>
     /// <typeparam name="T">The type of elements in the read-only pooled list.</typeparam>
     /// <typeparam name="T">The type of elements in the read-only pooled list.</typeparam>
 
 
-    public interface IReadOnlyPooledList<T> : IReadOnlyList<T>
+    internal interface IReadOnlyPooledList<T> : IReadOnlyList<T>
     {
     {
 #pragma warning disable CS0419
 #pragma warning disable CS0419
         /// <summary>
         /// <summary>

+ 2 - 2
src/Avalonia.Base/Collections/Pooled/PooledList.cs

@@ -29,7 +29,7 @@ namespace Avalonia.Collections.Pooled
     [DebuggerDisplay("Count = {Count}")]
     [DebuggerDisplay("Count = {Count}")]
     [DebuggerTypeProxy(typeof(ICollectionDebugView<>))]
     [DebuggerTypeProxy(typeof(ICollectionDebugView<>))]
     [Serializable]
     [Serializable]
-    public class PooledList<T> : IList<T>, IReadOnlyPooledList<T>, IList, IDisposable, IDeserializationCallback
+    internal class PooledList<T> : IList<T>, IReadOnlyPooledList<T>, IList, IDisposable, IDeserializationCallback
     {
     {
         // internal constant copied from Array.MaxArrayLength
         // internal constant copied from Array.MaxArrayLength
         private const int MaxArrayLength = 0x7FEFFFFF;
         private const int MaxArrayLength = 0x7FEFFFFF;
@@ -1423,7 +1423,7 @@ namespace Avalonia.Collections.Pooled
 
 
         private static bool ShouldClear(ClearMode mode)
         private static bool ShouldClear(ClearMode mode)
         {
         {
-#if NETCOREAPP2_1
+#if NETCOREAPP2_1_OR_GREATER
             return mode == ClearMode.Always
             return mode == ClearMode.Always
                 || (mode == ClearMode.Auto && RuntimeHelpers.IsReferenceOrContainsReferences<T>());
                 || (mode == ClearMode.Auto && RuntimeHelpers.IsReferenceOrContainsReferences<T>());
 #else
 #else

+ 2 - 2
src/Avalonia.Base/Collections/Pooled/PooledStack.cs

@@ -29,7 +29,7 @@ namespace Avalonia.Collections.Pooled
     [DebuggerTypeProxy(typeof(StackDebugView<>))]
     [DebuggerTypeProxy(typeof(StackDebugView<>))]
     [DebuggerDisplay("Count = {Count}")]
     [DebuggerDisplay("Count = {Count}")]
     [Serializable]
     [Serializable]
-    public class PooledStack<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T>, IDisposable, IDeserializationCallback
+    internal class PooledStack<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T>, IDisposable, IDeserializationCallback
     {
     {
         [NonSerialized]
         [NonSerialized]
         private ArrayPool<T> _pool;
         private ArrayPool<T> _pool;
@@ -596,7 +596,7 @@ namespace Avalonia.Collections.Pooled
 
 
         private static bool ShouldClear(ClearMode mode)
         private static bool ShouldClear(ClearMode mode)
         {
         {
-#if NETCOREAPP2_1
+#if NETCOREAPP2_1_OR_GREATER
             return mode == ClearMode.Always
             return mode == ClearMode.Always
                 || (mode == ClearMode.Auto && RuntimeHelpers.IsReferenceOrContainsReferences<T>());
                 || (mode == ClearMode.Auto && RuntimeHelpers.IsReferenceOrContainsReferences<T>());
 #else
 #else

+ 1 - 1
src/Avalonia.Base/Controls/ChildNameScope.cs

@@ -3,7 +3,7 @@ using Avalonia.Utilities;
 
 
 namespace Avalonia.Controls
 namespace Avalonia.Controls
 {
 {
-    public class ChildNameScope : INameScope
+    internal class ChildNameScope : INameScope
     {
     {
         private readonly INameScope _parentScope;
         private readonly INameScope _parentScope;
         private readonly NameScope _inner = new NameScope();
         private readonly NameScope _inner = new NameScope();

+ 1 - 1
src/Avalonia.Base/Controls/IResourceDictionary.cs

@@ -18,6 +18,6 @@ namespace Avalonia.Controls
         /// <summary>
         /// <summary>
         /// Gets a collection of merged resource dictionaries that are specifically keyed and composed to address theme scenarios.
         /// Gets a collection of merged resource dictionaries that are specifically keyed and composed to address theme scenarios.
         /// </summary>
         /// </summary>
-        IDictionary<ThemeVariant, IResourceProvider> ThemeDictionaries { get; }
+        IDictionary<ThemeVariant, IThemeVariantProvider> ThemeDictionaries { get; }
     }
     }
 }
 }

+ 21 - 0
src/Avalonia.Base/Controls/IThemeVariantProvider.cs

@@ -0,0 +1,21 @@
+using Avalonia.Metadata;
+using Avalonia.Styling;
+
+namespace Avalonia.Controls;
+
+/// <summary>
+/// Resource provider with theme variant awareness.
+/// Can be used with <see cref="IResourceDictionary.ThemeDictionaries"/>.
+/// </summary>
+/// <remarks>
+/// This is a helper interface for the XAML compiler to make Key property accessibly by the markup extensions.
+/// Which means, it can only be used with ResourceDictionaries and markup extensions in the XAML code.
+/// </remarks>
+[Unstable("This XAML-only API might be removed in the future minor updates.")]
+public interface IThemeVariantProvider : IResourceProvider
+{
+    /// <summary>
+    /// Key property set by the compiler.
+    /// </summary>
+    ThemeVariant? Key { get; set; }
+}

+ 7 - 5
src/Avalonia.Base/Controls/ResourceDictionary.cs

@@ -13,13 +13,13 @@ namespace Avalonia.Controls
     /// <summary>
     /// <summary>
     /// An indexed dictionary of resources.
     /// An indexed dictionary of resources.
     /// </summary>
     /// </summary>
-    public class ResourceDictionary : IResourceDictionary
+    public class ResourceDictionary : IResourceDictionary, IThemeVariantProvider
     {
     {
         private object? lastDeferredItemKey;
         private object? lastDeferredItemKey;
         private Dictionary<object, object?>? _inner;
         private Dictionary<object, object?>? _inner;
         private IResourceHost? _owner;
         private IResourceHost? _owner;
         private AvaloniaList<IResourceProvider>? _mergedDictionaries;
         private AvaloniaList<IResourceProvider>? _mergedDictionaries;
-        private AvaloniaDictionary<ThemeVariant, IResourceProvider>? _themeDictionary;
+        private AvaloniaDictionary<ThemeVariant, IThemeVariantProvider>? _themeDictionary;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
         /// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
@@ -93,13 +93,13 @@ namespace Avalonia.Controls
             }
             }
         }
         }
 
 
-        public IDictionary<ThemeVariant, IResourceProvider> ThemeDictionaries
+        public IDictionary<ThemeVariant, IThemeVariantProvider> ThemeDictionaries
         {
         {
             get
             get
             {
             {
                 if (_themeDictionary == null)
                 if (_themeDictionary == null)
                 {
                 {
-                    _themeDictionary = new AvaloniaDictionary<ThemeVariant, IResourceProvider>(2);
+                    _themeDictionary = new AvaloniaDictionary<ThemeVariant, IThemeVariantProvider>(2);
                     _themeDictionary.ForEachItem(
                     _themeDictionary.ForEachItem(
                         (_, x) =>
                         (_, x) =>
                         {
                         {
@@ -120,6 +120,8 @@ namespace Avalonia.Controls
                 return _themeDictionary;
                 return _themeDictionary;
             }
             }
         }
         }
+        
+        ThemeVariant? IThemeVariantProvider.Key { get; set; }
 
 
         bool IResourceNode.HasResources
         bool IResourceNode.HasResources
         {
         {
@@ -192,7 +194,7 @@ namespace Avalonia.Controls
 
 
             if (_themeDictionary is not null)
             if (_themeDictionary is not null)
             {
             {
-                IResourceProvider? themeResourceProvider;
+                IThemeVariantProvider? themeResourceProvider;
                 if (theme is not null && theme != ThemeVariant.Default)
                 if (theme is not null && theme != ThemeVariant.Default)
                 {
                 {
                     if (_themeDictionary.TryGetValue(theme, out themeResourceProvider)
                     if (_themeDictionary.TryGetValue(theme, out themeResourceProvider)

+ 46 - 18
src/Avalonia.Base/Controls/ResourceNodeExtensions.cs

@@ -119,7 +119,19 @@ namespace Avalonia.Controls
             resourceProvider = resourceProvider ?? throw new ArgumentNullException(nameof(resourceProvider));
             resourceProvider = resourceProvider ?? throw new ArgumentNullException(nameof(resourceProvider));
             key = key ?? throw new ArgumentNullException(nameof(key));
             key = key ?? throw new ArgumentNullException(nameof(key));
 
 
-            return new FloatingResourceObservable(resourceProvider, key, converter);
+            return new FloatingResourceObservable(resourceProvider, key, null, converter);
+        }
+
+        public static IObservable<object?> GetResourceObservable(
+            this IResourceProvider resourceProvider,
+            object key,
+            ThemeVariant? defaultThemeVariant,
+            Func<object?, object?>? converter = null)
+        {
+            resourceProvider = resourceProvider ?? throw new ArgumentNullException(nameof(resourceProvider));
+            key = key ?? throw new ArgumentNullException(nameof(key));
+
+            return new FloatingResourceObservable(resourceProvider, key, defaultThemeVariant, converter);
         }
         }
 
 
         private class ResourceObservable : LightweightObservableBase<object?>
         private class ResourceObservable : LightweightObservableBase<object?>
@@ -128,7 +140,10 @@ namespace Avalonia.Controls
             private readonly object _key;
             private readonly object _key;
             private readonly Func<object?, object?>? _converter;
             private readonly Func<object?, object?>? _converter;
 
 
-            public ResourceObservable(IResourceHost target, object key, Func<object?, object?>? converter)
+            public ResourceObservable(
+                IResourceHost target,
+                object key,
+                Func<object?, object?>? converter)
             {
             {
                 _target = target;
                 _target = target;
                 _key = key;
                 _key = key;
@@ -170,11 +185,8 @@ namespace Avalonia.Controls
 
 
             private object? GetValue()
             private object? GetValue()
             {
             {
-                if (_target is not IThemeVariantHost themeVariantHost
-                    || !_target.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
-                {
-                    value = _target.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
-                }
+                var theme = (_target as IThemeVariantHost)?.ActualThemeVariant; 
+                var value = _target.FindResource(theme, _key) ?? AvaloniaProperty.UnsetValue;
 
 
                 return _converter?.Invoke(value) ?? value;
                 return _converter?.Invoke(value) ?? value;
             }
             }
@@ -183,14 +195,20 @@ namespace Avalonia.Controls
         private class FloatingResourceObservable : LightweightObservableBase<object?>
         private class FloatingResourceObservable : LightweightObservableBase<object?>
         {
         {
             private readonly IResourceProvider _target;
             private readonly IResourceProvider _target;
+            private readonly ThemeVariant? _overrideThemeVariant;
             private readonly object _key;
             private readonly object _key;
             private readonly Func<object?, object?>? _converter;
             private readonly Func<object?, object?>? _converter;
             private IResourceHost? _owner;
             private IResourceHost? _owner;
 
 
-            public FloatingResourceObservable(IResourceProvider target, object key, Func<object?, object?>? converter)
+            public FloatingResourceObservable(
+                IResourceProvider target,
+                object key,
+                ThemeVariant? overrideThemeVariant,
+                Func<object?, object?>? converter)
             {
             {
                 _target = target;
                 _target = target;
                 _key = key;
                 _key = key;
+                _overrideThemeVariant = overrideThemeVariant;
                 _converter = converter;
                 _converter = converter;
             }
             }
 
 
@@ -203,11 +221,25 @@ namespace Avalonia.Controls
                 {
                 {
                     _owner.ResourcesChanged += ResourcesChanged;
                     _owner.ResourcesChanged += ResourcesChanged;
                 }
                 }
+                if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
+                {
+                    themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
+                }
             }
             }
 
 
             protected override void Deinitialize()
             protected override void Deinitialize()
             {
             {
                 _target.OwnerChanged -= OwnerChanged;
                 _target.OwnerChanged -= OwnerChanged;
+
+                if (_owner is not null)
+                {
+                    _owner.ResourcesChanged -= ResourcesChanged;
+                }
+                if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
+                {
+                    themeVariantHost.ActualThemeVariantChanged -= ActualThemeVariantChanged;
+                }
+
                 _owner = null;
                 _owner = null;
             }
             }
 
 
@@ -233,9 +265,9 @@ namespace Avalonia.Controls
                 {
                 {
                     _owner.ResourcesChanged -= ResourcesChanged;
                     _owner.ResourcesChanged -= ResourcesChanged;
                 }
                 }
-                if (_owner is IThemeVariantHost themeVariantHost)
+                if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
                 {
                 {
-                    themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
+                    themeVariantHost.ActualThemeVariantChanged -= ActualThemeVariantChanged;
                 }
                 }
 
 
                 _owner = _target.Owner;
                 _owner = _target.Owner;
@@ -244,12 +276,11 @@ namespace Avalonia.Controls
                 {
                 {
                     _owner.ResourcesChanged += ResourcesChanged;
                     _owner.ResourcesChanged += ResourcesChanged;
                 }
                 }
-                if (_owner is IThemeVariantHost themeVariantHost2)
+                if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost2)
                 {
                 {
-                    themeVariantHost2.ActualThemeVariantChanged -= ActualThemeVariantChanged;
+                    themeVariantHost2.ActualThemeVariantChanged += ActualThemeVariantChanged;
                 }
                 }
 
 
-
                 PublishNext();
                 PublishNext();
             }
             }
 
 
@@ -265,11 +296,8 @@ namespace Avalonia.Controls
 
 
             private object? GetValue()
             private object? GetValue()
             {
             {
-                if (!(_target.Owner is IThemeVariantHost themeVariantHost)
-                    || !_target.Owner.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
-                {
-                    value = _target.Owner?.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
-                }
+                var theme = _overrideThemeVariant ?? (_target.Owner as IThemeVariantHost)?.ActualThemeVariant; 
+                var value = _target.Owner?.FindResource(theme, _key) ?? AvaloniaProperty.UnsetValue;
 
 
                 return _converter?.Invoke(value) ?? value;
                 return _converter?.Invoke(value) ?? value;
             }
             }

+ 2 - 1
src/Avalonia.Base/Data/BindingPriority.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.ComponentModel;
 
 
 namespace Avalonia.Data
 namespace Avalonia.Data
 {
 {
@@ -47,7 +48,7 @@ namespace Avalonia.Data
         /// </summary>
         /// </summary>
         Unset = int.MaxValue,
         Unset = int.MaxValue,
 
 
-        [Obsolete("Use Template priority")]
+        [Obsolete("Use Template priority"), EditorBrowsable(EditorBrowsableState.Never)]
         TemplatedParent = Template,
         TemplatedParent = Template,
     }
     }
 }
 }

+ 2 - 2
src/Avalonia.Base/Data/BindingValue.cs

@@ -237,7 +237,7 @@ namespace Avalonia.Data
         /// </summary>
         /// </summary>
         /// <param name="value">The untyped value.</param>
         /// <param name="value">The untyped value.</param>
         /// <returns>The typed binding value.</returns>
         /// <returns>The typed binding value.</returns>
-        [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
+        [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConversionRequiresUnreferencedCodeMessage)]
         public static BindingValue<T> FromUntyped(object? value)
         public static BindingValue<T> FromUntyped(object? value)
         {
         {
             return FromUntyped(value, typeof(T));
             return FromUntyped(value, typeof(T));
@@ -251,7 +251,7 @@ namespace Avalonia.Data
         /// <param name="value">The untyped value.</param>
         /// <param name="value">The untyped value.</param>
         /// <param name="targetType">The runtime target type.</param>
         /// <param name="targetType">The runtime target type.</param>
         /// <returns>The typed binding value.</returns>
         /// <returns>The typed binding value.</returns>
-        [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
+        [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConversionRequiresUnreferencedCodeMessage)]
         public static BindingValue<T> FromUntyped(object? value, Type targetType)
         public static BindingValue<T> FromUntyped(object? value, Type targetType)
         {
         {
             if (value == AvaloniaProperty.UnsetValue)
             if (value == AvaloniaProperty.UnsetValue)

+ 1 - 1
src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Data.Converters
     /// Provides a default set of value conversions for bindings that do not specify a value
     /// Provides a default set of value conversions for bindings that do not specify a value
     /// converter.
     /// converter.
     /// </summary>
     /// </summary>
-    [RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
+    [RequiresUnreferencedCode(TrimmingMessages.TypeConversionRequiresUnreferencedCodeMessage)]
     public class DefaultValueConverter : IValueConverter
     public class DefaultValueConverter : IValueConverter
     {
     {
         /// <summary>
         /// <summary>

+ 6 - 1
src/Avalonia.Base/Data/Converters/StringFormatValueConverter.cs

@@ -35,7 +35,12 @@ namespace Avalonia.Data.Converters
         public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
         public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
         {
         {
             value = Inner?.Convert(value, targetType, parameter, culture) ?? value;
             value = Inner?.Convert(value, targetType, parameter, culture) ?? value;
-            return string.Format(culture, Format, value);
+            var format = Format!;
+            if (!format.Contains('{'))
+            {
+                format = $"{{0:{format}}}";
+            }
+            return string.Format(culture, format, value);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>

+ 1 - 1
src/Avalonia.Base/Data/Core/BindingExpression.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Data.Core
     /// Binds to an expression on an object using a type value converter to convert the values
     /// Binds to an expression on an object using a type value converter to convert the values
     /// that are sent and received.
     /// that are sent and received.
     /// </summary>
     /// </summary>
-    [RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
+    [RequiresUnreferencedCode(TrimmingMessages.TypeConversionRequiresUnreferencedCodeMessage)]
     internal class BindingExpression : LightweightObservableBase<object?>, IAvaloniaSubject<object?>, IDescription
     internal class BindingExpression : LightweightObservableBase<object?>, IAvaloniaSubject<object?>, IDescription
     {
     {
         private readonly ExpressionObserver _inner;
         private readonly ExpressionObserver _inner;

+ 1 - 1
src/Avalonia.Base/Data/Core/CommonPropertyNames.cs

@@ -1,6 +1,6 @@
 namespace Avalonia.Data.Core
 namespace Avalonia.Data.Core
 {
 {
-    public static class CommonPropertyNames
+    internal static class CommonPropertyNames
     {
     {
         public const string IndexerName = "Item";
         public const string IndexerName = "Item";
     }
     }

+ 1 - 1
src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Data.Core.Plugins
     /// <summary>
     /// <summary>
     /// Validates properties on that have <see cref="ValidationAttribute"/>s.
     /// Validates properties on that have <see cref="ValidationAttribute"/>s.
     /// </summary>
     /// </summary>
-    internal class DataAnnotationsValidationPlugin : IDataValidationPlugin
+    public class DataAnnotationsValidationPlugin : IDataValidationPlugin
     {
     {
         /// <inheritdoc/>
         /// <inheritdoc/>
         [RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
         [RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]

+ 1 - 1
src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Data.Core.Plugins
     /// <summary>
     /// <summary>
     /// Validates properties that report errors by throwing exceptions.
     /// Validates properties that report errors by throwing exceptions.
     /// </summary>
     /// </summary>
-    internal class ExceptionValidationPlugin : IDataValidationPlugin
+    public class ExceptionValidationPlugin : IDataValidationPlugin
     {
     {
         /// <inheritdoc/>
         /// <inheritdoc/>
         [RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
         [RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]

+ 1 - 1
src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Data.Core.Plugins
     /// <summary>
     /// <summary>
     /// Validates properties on objects that implement <see cref="INotifyDataErrorInfo"/>.
     /// Validates properties on objects that implement <see cref="INotifyDataErrorInfo"/>.
     /// </summary>
     /// </summary>
-    internal class IndeiValidationPlugin : IDataValidationPlugin
+    public class IndeiValidationPlugin : IDataValidationPlugin
     {
     {
         private static readonly WeakEvent<INotifyDataErrorInfo, DataErrorsChangedEventArgs>
         private static readonly WeakEvent<INotifyDataErrorInfo, DataErrorsChangedEventArgs>
             ErrorsChangedWeakEvent = WeakEvent.Register<INotifyDataErrorInfo, DataErrorsChangedEventArgs>(
             ErrorsChangedWeakEvent = WeakEvent.Register<INotifyDataErrorInfo, DataErrorsChangedEventArgs>(

+ 1 - 1
src/Avalonia.Base/Data/IndexerBinding.cs

@@ -2,7 +2,7 @@
 
 
 namespace Avalonia.Data
 namespace Avalonia.Data
 {
 {
-    public class IndexerBinding : IBinding
+    internal class IndexerBinding : IBinding
     {
     {
         public IndexerBinding(
         public IndexerBinding(
             AvaloniaObject source,
             AvaloniaObject source,

+ 2 - 1
src/Avalonia.Base/Data/InstancedBinding.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.ComponentModel;
 using Avalonia.Reactive;
 using Avalonia.Reactive;
 using ObservableEx = Avalonia.Reactive.Observable;
 using ObservableEx = Avalonia.Reactive.Observable;
 
 
@@ -49,7 +50,7 @@ namespace Avalonia.Data
         /// </summary>
         /// </summary>
         public IObservable<object?> Source { get; }
         public IObservable<object?> Source { get; }
 
 
-        [Obsolete("Use Source property")]
+        [Obsolete("Use Source property"), EditorBrowsable(EditorBrowsableState.Never)]
         public IObservable<object?> Observable => Source;
         public IObservable<object?> Observable => Source;
 
 
         /// <summary>
         /// <summary>

+ 1 - 1
src/Markup/Avalonia.Markup/Data/TemplateBinding.cs → src/Avalonia.Base/Data/TemplateBinding.cs

@@ -109,7 +109,7 @@ namespace Avalonia.Data
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
-        void ISetterValue.Initialize(ISetter setter) => _isSetterValue = true;
+        void ISetterValue.Initialize(SetterBase setter) => _isSetterValue = true;
 
 
         protected override void Subscribed()
         protected override void Subscribed()
         {
         {

+ 18 - 0
src/Avalonia.Base/Diagnostics/AppliedStyle.cs

@@ -0,0 +1,18 @@
+using Avalonia.Styling;
+
+namespace Avalonia.Diagnostics
+{
+    public class AppliedStyle
+    {
+        private readonly IStyleInstance _instance;
+
+        internal AppliedStyle(IStyleInstance instance)
+        {
+            _instance = instance;
+        }
+
+        public bool HasActivator => _instance.HasActivator;
+        public bool IsActive => _instance.IsActive;
+        public StyleBase Style => (StyleBase)_instance.Source;
+    }
+}

+ 1 - 1
src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Diagnostics
     /// <summary>
     /// <summary>
     /// Provides a debug interface into <see cref="AvaloniaObject"/>.
     /// Provides a debug interface into <see cref="AvaloniaObject"/>.
     /// </summary>
     /// </summary>
-    public interface IAvaloniaObjectDebug
+    internal interface IAvaloniaObjectDebug
     {
     {
         /// <summary>
         /// <summary>
         /// Gets the subscriber list for the <see cref="AvaloniaObject.PropertyChanged"/>
         /// Gets the subscriber list for the <see cref="AvaloniaObject.PropertyChanged"/>

+ 1 - 1
src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Diagnostics
     /// Provides a debug interface into <see cref="INotifyCollectionChanged"/> subscribers on
     /// Provides a debug interface into <see cref="INotifyCollectionChanged"/> subscribers on
     /// <see cref="AvaloniaList{T}"/>
     /// <see cref="AvaloniaList{T}"/>
     /// </summary>
     /// </summary>
-    public interface INotifyCollectionChangedDebug
+    internal interface INotifyCollectionChangedDebug
     {
     {
         /// <summary>
         /// <summary>
         /// Gets the subscriber list for the <see cref="INotifyCollectionChanged.CollectionChanged"/>
         /// Gets the subscriber list for the <see cref="INotifyCollectionChanged.CollectionChanged"/>

+ 2 - 2
src/Avalonia.Base/Diagnostics/StyleDiagnostics.cs

@@ -11,9 +11,9 @@ namespace Avalonia.Diagnostics
         /// <summary>
         /// <summary>
         /// Currently applied styles.
         /// Currently applied styles.
         /// </summary>
         /// </summary>
-        public IReadOnlyList<IStyleInstance> AppliedStyles { get; }
+        public IReadOnlyList<AppliedStyle> AppliedStyles { get; }
 
 
-        public StyleDiagnostics(IReadOnlyList<IStyleInstance> appliedStyles)
+        public StyleDiagnostics(IReadOnlyList<AppliedStyle> appliedStyles)
         {
         {
             AppliedStyles = appliedStyles;
             AppliedStyles = appliedStyles;
         }
         }

+ 4 - 4
src/Avalonia.Base/Diagnostics/TrimmingMessages.cs

@@ -2,11 +2,11 @@
 
 
 internal static class TrimmingMessages
 internal static class TrimmingMessages
 {
 {
-    public const string ImplicitTypeConvertionSupressWarningMessage = "Implicit convertion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible.";
-    public const string ImplicitTypeConvertionRequiresUnreferencedCodeMessage = "Implicit convertion methods are required for type conversion.";
+    public const string ImplicitTypeConversionSupressWarningMessage = "Implicit conversion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible.";
+    public const string ImplicitTypeConversionRequiresUnreferencedCodeMessage = "Implicit conversion methods are required for type conversion.";
 
 
-    public const string TypeConvertionSupressWarningMessage = "Convertion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible.";
-    public const string TypeConvertionRequiresUnreferencedCodeMessage = "Convertion methods are required for type conversion, including op_Implicit, op_Explicit, Parse and TypeConverter.";
+    public const string TypeConversionSupressWarningMessage = "Conversion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible.";
+    public const string TypeConversionRequiresUnreferencedCodeMessage = "Conversion methods are required for type conversion, including op_Implicit, op_Explicit, Parse and TypeConverter.";
 
 
     public const string ReflectionBindingRequiresUnreferencedCodeMessage = "BindingExpression and ReflectionBinding heavily use reflection. Consider using CompiledBindings instead.";
     public const string ReflectionBindingRequiresUnreferencedCodeMessage = "BindingExpression and ReflectionBinding heavily use reflection. Consider using CompiledBindings instead.";
     public const string ReflectionBindingSupressWarningMessage = "BindingExpression and ReflectionBinding internal heavily use reflection.";
     public const string ReflectionBindingSupressWarningMessage = "BindingExpression and ReflectionBinding internal heavily use reflection.";

+ 1 - 40
src/Avalonia.Base/DirectProperty.cs

@@ -24,7 +24,7 @@ namespace Avalonia
         /// <param name="getter">Gets the current value of the property.</param>
         /// <param name="getter">Gets the current value of the property.</param>
         /// <param name="setter">Sets the value of the property. May be null.</param>
         /// <param name="setter">Sets the value of the property. May be null.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="metadata">The property metadata.</param>
-        public DirectProperty(
+        internal DirectProperty(
             string name,
             string name,
             Func<TOwner, TValue> getter,
             Func<TOwner, TValue> getter,
             Action<TOwner, TValue>? setter,
             Action<TOwner, TValue>? setter,
@@ -106,45 +106,6 @@ namespace Avalonia
             return result;
             return result;
         }
         }
 
 
-        /// <summary>
-        /// Registers the direct property on another type.
-        /// </summary>
-        /// <typeparam name="TNewOwner">The type of the additional owner.</typeparam>
-        /// <param name="getter">Gets the current value of the property.</param>
-        /// <param name="setter">Sets the value of the property.</param>
-        /// <param name="unsetValue">
-        /// The value to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>
-        /// </param>
-        /// <param name="defaultBindingMode">The default binding mode for the property.</param>
-        /// <param name="enableDataValidation">
-        /// Whether the property is interested in data validation.
-        /// </param>
-        /// <returns>The property.</returns>
-        public DirectProperty<TNewOwner, TValue> AddOwnerWithDataValidation<TNewOwner>(
-            Func<TNewOwner, TValue> getter,
-            Action<TNewOwner,TValue> setter,
-            TValue unsetValue = default!,
-            BindingMode defaultBindingMode = BindingMode.Default,
-            bool enableDataValidation = false)
-                where TNewOwner : AvaloniaObject
-        {
-            var metadata = new DirectPropertyMetadata<TValue>(
-                unsetValue: unsetValue,
-                defaultBindingMode: defaultBindingMode,
-                enableDataValidation: enableDataValidation);
-
-            metadata.Merge(GetMetadata<TOwner>(), this);
-
-            var result = new DirectProperty<TNewOwner, TValue>(
-                this,
-                getter,
-                setter,
-                metadata);
-
-            AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result);
-            return result;
-        }
-
         /// <inheritdoc/>
         /// <inheritdoc/>
         internal override TValue InvokeGetter(AvaloniaObject instance)
         internal override TValue InvokeGetter(AvaloniaObject instance)
         {
         {

+ 3 - 3
src/Avalonia.Base/DirectPropertyBase.cs

@@ -20,11 +20,11 @@ namespace Avalonia
         /// <param name="name">The name of the property.</param>
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
         /// <param name="metadata">The property metadata.</param>
         /// <param name="metadata">The property metadata.</param>
-        protected DirectPropertyBase(
+        private protected DirectPropertyBase(
             string name,
             string name,
             Type ownerType,
             Type ownerType,
             AvaloniaPropertyMetadata metadata)
             AvaloniaPropertyMetadata metadata)
-            : base(name, ownerType, metadata)
+            : base(name, ownerType, ownerType, metadata)
         {
         {
             Owner = ownerType;
             Owner = ownerType;
         }
         }
@@ -35,7 +35,7 @@ namespace Avalonia
         /// <param name="source">The property to copy.</param>
         /// <param name="source">The property to copy.</param>
         /// <param name="ownerType">The new owner type.</param>
         /// <param name="ownerType">The new owner type.</param>
         /// <param name="metadata">Optional overridden metadata.</param>
         /// <param name="metadata">Optional overridden metadata.</param>
-        protected DirectPropertyBase(
+        private protected DirectPropertyBase(
             DirectPropertyBase<TValue> source,
             DirectPropertyBase<TValue> source,
             Type ownerType,
             Type ownerType,
             AvaloniaPropertyMetadata metadata)
             AvaloniaPropertyMetadata metadata)

+ 1 - 1
src/Avalonia.Base/EnumExtensions.cs

@@ -6,7 +6,7 @@ namespace Avalonia
     /// <summary>
     /// <summary>
     /// Provides extension methods for enums.
     /// Provides extension methods for enums.
     /// </summary>
     /// </summary>
-    public static class EnumExtensions
+    internal static class EnumExtensions
     {
     {
             
             
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 4 - 2
src/Avalonia.Base/Input/AccessKeyHandler.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Input
     /// <summary>
     /// <summary>
     /// Handles access keys for a window.
     /// Handles access keys for a window.
     /// </summary>
     /// </summary>
-    public class AccessKeyHandler : IAccessKeyHandler
+    internal class AccessKeyHandler : IAccessKeyHandler
     {
     {
         /// <summary>
         /// <summary>
         /// Defines the AccessKeyPressed attached event.
         /// Defines the AccessKeyPressed attached event.
@@ -141,9 +141,11 @@ namespace Avalonia.Input
 
 
                 if (MainMenu == null || !MainMenu.IsOpen)
                 if (MainMenu == null || !MainMenu.IsOpen)
                 {
                 {
+                    var focusManager = FocusManager.GetFocusManager(e.Source as IInputElement);
+                    
                     // TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
                     // TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
                     // Save currently focused input element.
                     // Save currently focused input element.
-                    _restoreFocusElement = FocusManager.Instance?.Current;
+                    _restoreFocusElement = focusManager?.GetFocusedElement();
 
 
                     // When Alt is pressed without a main menu, or with a closed main menu, show
                     // When Alt is pressed without a main menu, or with a closed main menu, show
                     // access key markers in the window (i.e. "_File").
                     // access key markers in the window (i.e. "_File").

+ 12 - 5
src/Avalonia.Base/Input/Cursor.cs

@@ -42,23 +42,25 @@ namespace Avalonia.Input
     public class Cursor : IDisposable
     public class Cursor : IDisposable
     {
     {
         public static readonly Cursor Default = new Cursor(StandardCursorType.Arrow);
         public static readonly Cursor Default = new Cursor(StandardCursorType.Arrow);
+        private string _name;
 
 
-        internal Cursor(ICursorImpl platformImpl)
+        private Cursor(ICursorImpl platformImpl, string name)
         {
         {
             PlatformImpl = platformImpl;
             PlatformImpl = platformImpl;
+            _name = name;
         }
         }
 
 
         public Cursor(StandardCursorType cursorType)
         public Cursor(StandardCursorType cursorType)
-            : this(GetCursorFactory().GetCursor(cursorType))
+            : this(GetCursorFactory().GetCursor(cursorType), cursorType.ToString())
         {
         {
         }
         }
 
 
-        public Cursor(IBitmap cursor, PixelPoint hotSpot)
-            : this(GetCursorFactory().CreateCursor(cursor.PlatformImpl.Item, hotSpot))
+        public Cursor(Bitmap cursor, PixelPoint hotSpot)
+            : this(GetCursorFactory().CreateCursor(cursor.PlatformImpl.Item, hotSpot), "BitmapCursor")
         {
         {
         }
         }
 
 
-        public ICursorImpl PlatformImpl { get; }
+        internal ICursorImpl PlatformImpl { get; }
 
 
         public void Dispose() => PlatformImpl.Dispose();
         public void Dispose() => PlatformImpl.Dispose();
 
 
@@ -73,5 +75,10 @@ namespace Avalonia.Input
         {
         {
             return AvaloniaLocator.Current.GetRequiredService<ICursorFactory>();
             return AvaloniaLocator.Current.GetRequiredService<ICursorFactory>();
         }
         }
+
+        public override string ToString()
+        {
+            return _name;
+        }
     }
     }
 }
 }

+ 2 - 1
src/Avalonia.Base/Input/DataFormats.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.ComponentModel;
 
 
 namespace Avalonia.Input
 namespace Avalonia.Input
 {
 {
@@ -17,7 +18,7 @@ namespace Avalonia.Input
         /// <summary>
         /// <summary>
         /// Dataformat for one or more filenames
         /// Dataformat for one or more filenames
         /// </summary>
         /// </summary>
-        [Obsolete("Use DataFormats.Files, this format is supported only on desktop platforms.")]
+        [Obsolete("Use DataFormats.Files, this format is supported only on desktop platforms."), EditorBrowsable(EditorBrowsableState.Never)]
         public static readonly string FileNames = nameof(FileNames);
         public static readonly string FileNames = nameof(FileNames);
     }
     }
 }
 }

+ 2 - 1
src/Avalonia.Base/Input/DataObjectExtensions.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
 using System.Linq;
 using Avalonia.Platform.Storage;
 using Avalonia.Platform.Storage;
 
 
@@ -25,7 +26,7 @@ namespace Avalonia.Input
         /// <returns>
         /// <returns>
         /// Collection of file names. If format isn't available, returns null.
         /// Collection of file names. If format isn't available, returns null.
         /// </returns>
         /// </returns>
-        [System.Obsolete("Use GetFiles, this method is supported only on desktop platforms.")]
+        [System.Obsolete("Use GetFiles, this method is supported only on desktop platforms."), EditorBrowsable(EditorBrowsableState.Never)]
         public static IEnumerable<string>? GetFileNames(this IDataObject dataObject)
         public static IEnumerable<string>? GetFileNames(this IDataObject dataObject)
         {
         {
             return (dataObject.Get(DataFormats.FileNames) as IEnumerable<string>)
             return (dataObject.Get(DataFormats.FileNames) as IEnumerable<string>)

+ 1 - 2
src/Avalonia.Base/Input/DragEventArgs.cs

@@ -25,8 +25,7 @@ namespace Avalonia.Input
             return _target.TranslatePoint(_targetLocation, relativeTo) ?? new Point(0, 0);
             return _target.TranslatePoint(_targetLocation, relativeTo) ?? new Point(0, 0);
         }
         }
 
 
-        [Unstable]
-        [Obsolete("This constructor might be removed in 12.0. For unit testing, consider using DragDrop.DoDragDrop or IHeadlessWindow.DragDrop.")]
+        [Unstable("This constructor might be removed in 12.0. For unit testing, consider using DragDrop.DoDragDrop or IHeadlessWindow.DragDrop.")]
         public DragEventArgs(RoutedEvent<DragEventArgs> routedEvent, IDataObject data, Interactive target, Point targetLocation, KeyModifiers keyModifiers)
         public DragEventArgs(RoutedEvent<DragEventArgs> routedEvent, IDataObject data, Interactive target, Point targetLocation, KeyModifiers keyModifiers)
             : base(routedEvent)
             : base(routedEvent)
         {
         {

+ 41 - 20
src/Avalonia.Base/Input/FocusManager.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 using Avalonia.Interactivity;
 using Avalonia.Interactivity;
+using Avalonia.Metadata;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
 
 
 namespace Avalonia.Input
 namespace Avalonia.Input
@@ -10,6 +11,7 @@ namespace Avalonia.Input
     /// <summary>
     /// <summary>
     /// Manages focus for the application.
     /// Manages focus for the application.
     /// </summary>
     /// </summary>
+    [PrivateApi]
     public class FocusManager : IFocusManager
     public class FocusManager : IFocusManager
     {
     {
         /// <summary>
         /// <summary>
@@ -29,15 +31,12 @@ namespace Avalonia.Input
                 RoutingStrategies.Tunnel);
                 RoutingStrategies.Tunnel);
         }
         }
 
 
-        /// <summary>
-        /// Gets the instance of the <see cref="IFocusManager"/>.
-        /// </summary>
-        public static IFocusManager? Instance => AvaloniaLocator.Current.GetService<IFocusManager>();
+        private IInputElement? Current => KeyboardDevice.Instance?.FocusedElement;
 
 
         /// <summary>
         /// <summary>
         /// Gets the currently focused <see cref="IInputElement"/>.
         /// Gets the currently focused <see cref="IInputElement"/>.
         /// </summary>
         /// </summary>
-        public IInputElement? Current => KeyboardDevice.Instance?.FocusedElement;
+        public IInputElement? GetFocusedElement() => Current;
 
 
         /// <summary>
         /// <summary>
         /// Gets the current focus scope.
         /// Gets the current focus scope.
@@ -54,7 +53,7 @@ namespace Avalonia.Input
         /// <param name="control">The control to focus.</param>
         /// <param name="control">The control to focus.</param>
         /// <param name="method">The method by which focus was changed.</param>
         /// <param name="method">The method by which focus was changed.</param>
         /// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
         /// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
-        public void Focus(
+        public bool Focus(
             IInputElement? control, 
             IInputElement? control, 
             NavigationMethod method = NavigationMethod.Unspecified,
             NavigationMethod method = NavigationMethod.Unspecified,
             KeyModifiers keyModifiers = KeyModifiers.None)
             KeyModifiers keyModifiers = KeyModifiers.None)
@@ -67,7 +66,7 @@ namespace Avalonia.Input
                 if (scope != null)
                 if (scope != null)
                 {
                 {
                     Scope = scope;
                     Scope = scope;
-                    SetFocusedElement(scope, control, method, keyModifiers);
+                    return SetFocusedElement(scope, control, method, keyModifiers);
                 }
                 }
             }
             }
             else if (Current != null)
             else if (Current != null)
@@ -79,28 +78,29 @@ namespace Avalonia.Input
                         _focusScopes.TryGetValue(scope, out var element) &&
                         _focusScopes.TryGetValue(scope, out var element) &&
                         element != null)
                         element != null)
                     {
                     {
-                        Focus(element, method);
-                        return;
+                        return Focus(element, method);
                     }
                     }
                 }
                 }
 
 
                 if (Scope is object)
                 if (Scope is object)
                 {
                 {
                     // Couldn't find a focus scope, clear focus.
                     // Couldn't find a focus scope, clear focus.
-                    SetFocusedElement(Scope, null);
+                    return SetFocusedElement(Scope, null);
                 }
                 }
             }
             }
+
+            return false;
         }
         }
 
 
-        public IInputElement? GetFocusedElement(IInputElement e)
+        public void ClearFocus()
         {
         {
-            if (e is IFocusScope scope)
-            {
-                _focusScopes.TryGetValue(scope, out var result);
-                return result;
-            }
+            Focus(null);
+        }
 
 
-            return null;
+        public IInputElement? GetFocusedElement(IFocusScope scope)
+        {
+            _focusScopes.TryGetValue(scope, out var result);
+            return result;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -114,7 +114,7 @@ namespace Avalonia.Input
         /// If the specified scope is the current <see cref="Scope"/> then the keyboard focus
         /// If the specified scope is the current <see cref="Scope"/> then the keyboard focus
         /// will change.
         /// will change.
         /// </remarks>
         /// </remarks>
-        public void SetFocusedElement(
+        public bool SetFocusedElement(
             IFocusScope scope,
             IFocusScope scope,
             IInputElement? element,
             IInputElement? element,
             NavigationMethod method = NavigationMethod.Unspecified,
             NavigationMethod method = NavigationMethod.Unspecified,
@@ -122,6 +122,11 @@ namespace Avalonia.Input
         {
         {
             scope = scope ?? throw new ArgumentNullException(nameof(scope));
             scope = scope ?? throw new ArgumentNullException(nameof(scope));
 
 
+            if (element is not null && !CanFocus(element))
+            {
+                return false;
+            }
+
             if (_focusScopes.TryGetValue(scope, out var existingElement))
             if (_focusScopes.TryGetValue(scope, out var existingElement))
             {
             {
                 if (element != existingElement)
                 if (element != existingElement)
@@ -139,6 +144,8 @@ namespace Avalonia.Input
             {
             {
                 KeyboardDevice.Instance?.SetFocusedElement(element, method, keyModifiers);
                 KeyboardDevice.Instance?.SetFocusedElement(element, method, keyModifiers);
             }
             }
+
+            return true;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -180,6 +187,20 @@ namespace Avalonia.Input
 
 
         public static bool GetIsFocusScope(IInputElement e) => e is IFocusScope;
         public static bool GetIsFocusScope(IInputElement e) => e is IFocusScope;
 
 
+        /// <summary>
+        /// Public API customers should use TopLevel.GetTopLevel(control).FocusManager.
+        /// But since we have split projects, we can't access TopLevel from Avalonia.Base.
+        /// That's why we need this helper method instead.
+        /// </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)?.VisualRoot as IInputRoot)?.FocusManager
+                   // In our unit tests some elements might not have a root. Remove when we migrate to headless tests.
+                ?? (FocusManager?)AvaloniaLocator.Current.GetService<IFocusManager>();
+        }
+        
         /// <summary>
         /// <summary>
         /// Checks if the specified element can be focused.
         /// Checks if the specified element can be focused.
         /// </summary>
         /// </summary>
@@ -232,7 +253,7 @@ namespace Avalonia.Input
                 {
                 {
                     if (element is IInputElement inputElement && CanFocus(inputElement))
                     if (element is IInputElement inputElement && CanFocus(inputElement))
                     {
                     {
-                        Instance?.Focus(inputElement, NavigationMethod.Pointer, ev.KeyModifiers);
+                        inputElement.Focus(NavigationMethod.Pointer, ev.KeyModifiers);
 
 
                         break;
                         break;
                     }
                     }
@@ -242,6 +263,6 @@ namespace Avalonia.Input
             }
             }
         }
         }
 
 
-        private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true;
+        private static bool IsVisible(IInputElement e) => (e as Visual)?.IsEffectivelyVisible ?? true;
     }
     }
 }
 }

+ 1 - 2
src/Avalonia.Base/Input/IAccessKeyHandler.cs

@@ -5,8 +5,7 @@ namespace Avalonia.Input
     /// <summary>
     /// <summary>
     /// Defines the interface for classes that handle access keys for a window.
     /// Defines the interface for classes that handle access keys for a window.
     /// </summary>
     /// </summary>
-    [Unstable]
-    public interface IAccessKeyHandler
+    internal interface IAccessKeyHandler
     {
     {
         /// <summary>
         /// <summary>
         /// Gets or sets the window's main menu.
         /// Gets or sets the window's main menu.

部分文件因为文件数量过多而无法显示