Browse Source

Merge branch 'master' into features/Core/StaticResourceExtensions

pull/12047/head
workgroupengineering 3 years ago
committed by GitHub
parent
commit
e21472809a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      .nuke/build.schema.json
  2. 31
      Documentation/build.md
  3. 64
      api/Avalonia.Controls.ColorPicker.nupkg.xml
  4. 418
      api/Avalonia.Themes.Fluent.nupkg.xml
  5. 406
      api/Avalonia.Themes.Simple.nupkg.xml
  6. 10
      api/Avalonia.nupkg.xml
  7. 8
      build/SourceLink.props
  8. 18
      native/Avalonia.Native/src/OSX/app.mm
  9. 1
      native/Avalonia.Native/src/OSX/common.h
  10. 8
      native/Avalonia.Native/src/OSX/main.mm
  11. 154
      nukebuild/ApiDiffValidation.cs
  12. 19
      nukebuild/Build.cs
  13. 22
      nukebuild/BuildParameters.cs
  14. 2
      nukebuild/Numerge
  15. 4
      nukebuild/Shims.cs
  16. 14
      nukebuild/_build.csproj
  17. 26
      packages/Avalonia/AvaloniaBuildTasks.targets
  18. 6
      readme.md
  19. 5
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  20. 4
      samples/ControlCatalog/Pages/DataGridPage.xaml
  21. 7
      samples/Sandbox/MainWindow.axaml
  22. 1
      src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
  23. 6
      src/Avalonia.Base/Avalonia.Base.csproj
  24. 20
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  25. 5
      src/Avalonia.Base/Interactivity/EventRoute.cs
  26. 6
      src/Avalonia.Base/Media/GlyphRun.cs
  27. 321
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  28. 2
      src/Avalonia.Base/Platform/Storage/PickerOptions.cs
  29. 14
      src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs
  30. 2
      src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs
  31. 21
      src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs
  32. 7
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  33. 16
      src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
  34. 2
      src/Avalonia.Base/Threading/Dispatcher.MainLoop.cs
  35. 20
      src/Avalonia.Base/Threading/Dispatcher.Queue.cs
  36. 2
      src/Avalonia.Base/Threading/Dispatcher.Timers.cs
  37. 3
      src/Avalonia.Base/Threading/Dispatcher.cs
  38. 8
      src/Avalonia.Base/Threading/DispatcherFrame.cs
  39. 2
      src/Avalonia.Base/Threading/DispatcherOperation.cs
  40. 16
      src/Avalonia.Base/Threading/DispatcherTimer.cs
  41. 16
      src/Avalonia.Base/Utilities/SmallDictionary.cs
  42. 39
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  43. 4
      src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs
  44. 2
      src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
  45. 2
      src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs
  46. 2
      src/Avalonia.Controls.DataGrid/DataGridLength.cs
  47. 11
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  48. 2
      src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
  49. 4
      src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs
  50. 10
      src/Avalonia.Controls/ComboBox.cs
  51. 4
      src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs
  52. 4
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  53. 19
      src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
  54. 4
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  55. 10
      src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs
  56. 22
      src/Avalonia.Controls/Utils/StringUtils.cs
  57. 2
      src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs
  58. 7
      src/Avalonia.Controls/Window.cs
  59. 3
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs
  60. 5
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/FiredEvent.cs
  61. 10
      src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml
  62. 10
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  63. 2
      src/Avalonia.Native/NativePlatformSettings.cs
  64. 8
      src/Avalonia.Remote.Protocol/MetsysBson.cs
  65. 50
      src/Avalonia.X11/X11Clipboard.cs
  66. 5
      src/Avalonia.X11/X11Structs.cs
  67. 12
      src/Browser/Avalonia.Browser/webapp/package-lock.json
  68. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  69. 6
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  70. 20
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs
  71. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs
  72. 34
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs
  73. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs
  74. 8
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs
  75. 3
      src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs
  76. 16
      src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs
  77. 4
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  78. 3
      src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
  79. 104
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
  80. 30
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
  81. 9
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
  82. 72
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
  83. 3
      src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
  84. 23
      src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
  85. 13
      src/Windows/Avalonia.Win32/WindowImpl.cs
  86. 1
      src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj
  87. 1
      src/tools/Avalonia.Generators/Avalonia.Generators.csproj
  88. 8
      src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs
  89. 15
      src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs
  90. 3
      src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs
  91. 2
      tests/Avalonia.Base.UnitTests/Media/GlyphRunTests.cs
  92. 53
      tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs
  93. 37
      tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
  94. 31
      tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs
  95. 16
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs
  96. 35
      tests/Avalonia.Controls.UnitTests/WindowTests.cs
  97. 116
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
  98. 1
      tests/Avalonia.UnitTests/TestRoot.cs

28
.nuke/build.schema.json

@ -6,17 +6,18 @@
"build": {
"type": "object",
"properties": {
"Configuration": {
"type": "string",
"description": "configuration"
"api-baseline": {
"type": "string"
},
"configuration": {
"type": "string"
},
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
},
"ForceNugetVersion": {
"type": "string",
"description": "force-nuget-version"
"force-nuget-version": {
"type": "string"
},
"Help": {
"type": "boolean",
@ -89,17 +90,16 @@
"RunRenderTests",
"RunTests",
"RunToolsTests",
"ValidateApiDiff",
"ZipFiles"
]
}
},
"SkipPreviewer": {
"type": "boolean",
"description": "skip-previewer"
"skip-previewer": {
"type": "boolean"
},
"SkipTests": {
"type": "boolean",
"description": "skip-tests"
"skip-tests": {
"type": "boolean"
},
"Target": {
"type": "array",
@ -124,10 +124,14 @@
"RunRenderTests",
"RunTests",
"RunToolsTests",
"ValidateApiDiff",
"ZipFiles"
]
}
},
"update-api-suppression": {
"type": "boolean"
},
"Verbosity": {
"type": "string",
"description": "Logging verbosity during build execution. Default is 'Normal'",

31
Documentation/build.md

@ -14,6 +14,18 @@ git submodule update --init
Go to https://dotnet.microsoft.com/download/visual-studio-sdks and install the latest version of the .NET Core SDK compatible with Avalonia UI. Make sure to download the SDK (not just the "runtime") package. The version compatible is indicated within the [global.json](https://github.com/AvaloniaUI/Avalonia/blob/master/global.json) file. Note that Avalonia UI does not always use the latest version and is hardcoded to use the last version known to be compatible (SDK releases may break the builds from time-to-time).
### Installing necessary .NET Workloads
.NET SDK requires developers to install workloads for each platform they are targeting.
Since Avalonia targets pretty much every supported .NET platform, you need to install these workloads as well.
Running it from the command line:
```
dotnet workload install android ios wasm-tools wasm-experimental
```
macOS workloads are not required to build Avalonia.
Note: on Unix OS you need to run this command from sudo.
## Build and Run Avalonia
```
@ -43,6 +55,25 @@ Build and run `ControlCatalog.NetCore` project to see the sample application.
>CSC : error CS0006: Metadata file 'C:\...\Avalonia\packages\Avalonia\bin\Debug\netcoreapp2.0\Avalonia.dll' could not be found
```
To correct this, right click on the `Avalonia.DesktopRuntime` project then press `Build` to build the project manually. Afterwards the solution should build normally and the ControlCatalog can be run.
* **Error MSB4062 GenerateAvaloniaResourcesTask**
Same as previous one, you need to manually build `Avalonia.Build.Tasks` project at least once.
Alternatively, you can build the solution once with Nuke.
## Building packages with Nuke
Install Nuke
`dotnet tool install --global Nuke.GlobalTool --version 6.2.1`
Build project:
`nuke --target Compile --configuration Release`
And run tests:
`nuke --target RunTests --configuration Release`
Or if you need to create nuget packages as well (it will compile and run tests automatically):
`nuke --target Package --configuration Release`
# Linux/macOS

64
api/Avalonia.Controls.ColorPicker.nupkg.xml

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorPicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorPreviewer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorSlider.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorSpectrum.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorView.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorPicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorPreviewer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorSlider.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorSpectrum.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorView.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.ColorPicker.dll</Right>
</Suppression>
</Suppressions>

418
api/Avalonia.Themes.Fluent.nupkg.xml

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/BaseResources.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/FluentControlResources.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AdornerLayer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AutoCompleteBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Button.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ButtonSpinner.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Calendar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDatePicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDayButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CaptionButtons.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Carousel.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CheckBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBoxItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContentControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContextMenu.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DataValidationErrors.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DatePicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DateTimePickerShared.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DropDownButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/EmbeddableControlRoot.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Expander.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FlyoutPresenter.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/GridSplitter.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ItemsControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Label.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBoxItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ManagedFileChooser.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Menu.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuFlyoutPresenter.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuScrollViewer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NativeMenuBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NotificationCard.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NumericUpDown.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/OverlayPopupHost.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PathIcon.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PopupRoot.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ProgressBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RadioButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshContainer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshVisualizer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RepeatButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollViewer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SelectableTextBlock.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Separator.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Slider.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitView.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStrip.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStripItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TextBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ThemeVariantScope.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TimePicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TitleBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleSwitch.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToolTip.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TransitioningContentControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeView.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeViewItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Window.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/WindowNotificationManager.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
</Suppressions>

406
api/Avalonia.Themes.Simple.nupkg.xml

@ -0,0 +1,406 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/Base.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AdornerLayer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AutoCompleteBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Button.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ButtonSpinner.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Calendar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDatePicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDayButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CaptionButtons.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Carousel.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CheckBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBoxItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContentControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContextMenu.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DataValidationErrors.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DatePicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DateTimePickerShared.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DropDownButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/EmbeddableControlRoot.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Expander.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FlyoutPresenter.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/GridSplitter.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ItemsControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Label.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBoxItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ManagedFileChooser.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Menu.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuFlyoutPresenter.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NativeMenuBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NotificationCard.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NumericUpDown.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/OverlayPopupHost.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PathIcon.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PopupRoot.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ProgressBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RadioButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshContainer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshVisualizer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RepeatButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollViewer.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SelectableTextBlock.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Separator.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Slider.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitView.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStrip.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStripItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TextBox.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ThemeVariantScope.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TimePicker.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TitleBar.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleButton.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleSwitch.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToolTip.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TransitioningContentControl.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeView.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeViewItem.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Window.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/WindowNotificationManager.xaml</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Simple.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Simple.dll</Right>
</Suppression>
</Suppressions>

10
api/Avalonia.nupkg.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Rendering.Composition.ICompositionGpuImportedObject.ImportCompleted</Target>
<Left>baseline/netstandard2.0/Avalonia.Base.dll</Left>
<Right>target/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
</Suppressions>

8
build/SourceLink.props

@ -1,9 +1,9 @@
<Project>
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>false</IncludeSymbols>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
@ -14,10 +14,6 @@
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<PropertyGroup>
<DebugType Condition="$(ContinuousIntegrationBuild) == 'true'">embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
</ItemGroup>

18
native/Avalonia.Native/src/OSX/app.mm

@ -2,6 +2,7 @@
#include "AvnString.h"
@interface AvnAppDelegate : NSObject<NSApplicationDelegate>
-(AvnAppDelegate* _Nonnull) initWithEvents: (IAvnApplicationEvents* _Nonnull) events;
-(void) releaseEvents;
@end
NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
@ -15,6 +16,11 @@ ComPtr<IAvnApplicationEvents> _events;
return self;
}
- (void)releaseEvents
{
_events = nil;
}
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
if([[NSApplication sharedApplication] activationPolicy] != AvnDesiredActivationPolicy)
@ -105,6 +111,18 @@ extern void InitializeAvnApp(IAvnApplicationEvents* events, bool disableAppDeleg
}
}
extern void ReleaseAvnAppEvents()
{
NSApplication* app = [AvnApplication sharedApplication];
id delegate = [app delegate];
if ([delegate isMemberOfClass:[AvnAppDelegate class]])
{
AvnAppDelegate* avnDelegate = delegate;
[avnDelegate releaseEvents];
[app setDelegate:nil];
}
}
HRESULT AvnApplicationCommands::HideApp()
{
START_COM_CALL;

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

@ -38,6 +38,7 @@ extern IAvnMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
extern void InitializeAvnApp(IAvnApplicationEvents* events, bool disableAppDelegate);
extern void ReleaseAvnAppEvents();
extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;
extern NSPoint ToNSPoint (AvnPoint p);
extern NSRect ToNSRect (AvnRect r);

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

@ -197,6 +197,14 @@ class AvaloniaNative : public ComSingleObject<IAvaloniaNativeFactory, &IID_IAval
public:
FORWARD_IUNKNOWN()
virtual ~AvaloniaNative() override
{
ReleaseAvnAppEvents();
_deallocator = nullptr;
_dispatcher = nullptr;
}
virtual HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator,
IAvnApplicationEvents* events,
IAvnDispatcher* dispatcher) override

154
nukebuild/ApiDiffValidation.cs

@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Nuke.Common.Tooling;
public static class ApiDiffValidation
{
private static readonly HttpClient s_httpClient = new();
public static async Task ValidatePackage(
Tool apiCompatTool, string packagePath, string baselineVersion,
string suppressionFilesFolder, bool updateSuppressionFile)
{
if (baselineVersion is null)
{
throw new InvalidOperationException(
"Build \"api-baseline\" parameter must be set when running Nuke CreatePackages");
}
if (!Directory.Exists(suppressionFilesFolder))
{
Directory.CreateDirectory(suppressionFilesFolder!);
}
await using (var baselineStream = await DownloadBaselinePackage(packagePath, baselineVersion))
using (var target = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.Read), ZipArchiveMode.Read))
using (var baseline = new ZipArchive(baselineStream, ZipArchiveMode.Read))
using (Helpers.UseTempDir(out var tempFolder))
{
var targetDlls = GetDlls(target);
var baselineDlls = GetDlls(baseline);
var left = new List<string>();
var right = new List<string>();
var packageId = GetPackageId(packagePath);
var suppressionFile = Path.Combine(suppressionFilesFolder, packageId + ".nupkg.xml");
// Don't use Path.Combine with these left and right tool parameters.
// Microsoft.DotNet.ApiCompat.Tool is stupid and treats '/' and '\' as different assemblies in suppression files.
// So, always use Unix '/'
foreach (var baselineDll in baselineDlls)
{
var baselineDllPath = $"baseline/{baselineDll.target}/{baselineDll.entry.Name}";
var baselineDllRealPath = Path.Combine(tempFolder, baselineDllPath);
Directory.CreateDirectory(Path.GetDirectoryName(baselineDllRealPath)!);
await using (var baselineDllFile = File.Create(baselineDllRealPath))
{
await baselineDll.entry.Open().CopyToAsync(baselineDllFile);
}
var targetDll = targetDlls.FirstOrDefault(e =>
e.target == baselineDll.target && e.entry.Name == baselineDll.entry.Name);
if (targetDll.entry is null)
{
throw new InvalidOperationException($"Some assemblies are missing in the new package {packageId}: {baselineDll.entry.Name} for {baselineDll.target}");
}
var targetDllPath = $"target/{targetDll.target}/{targetDll.entry.Name}";
var targetDllRealPath = Path.Combine(tempFolder, targetDllPath);
Directory.CreateDirectory(Path.GetDirectoryName(targetDllRealPath)!);
await using (var targetDllFile = File.Create(targetDllRealPath))
{
await targetDll.entry.Open().CopyToAsync(targetDllFile);
}
left.Add(baselineDllPath);
right.Add(targetDllPath);
}
if (left.Any())
{
var args = $""" -l={string.Join(',', left)} -r="{string.Join(',', right)}" """;
if (File.Exists(suppressionFile))
{
args += $""" --suppression-file="{suppressionFile}" """;
}
if (updateSuppressionFile)
{
args += $""" --suppression-output-file="{suppressionFile}" --generate-suppression-file=true """;
}
var result = apiCompatTool(args, tempFolder)
.Where(t => t.Type == OutputType.Err).ToArray();
if (result.Any())
{
throw new AggregateException(
$"ApiDiffValidation task has failed for \"{Path.GetFileName(packagePath)}\" package",
result.Select(r => new Exception(r.Text)));
}
}
}
}
private static IReadOnlyCollection<(string target, ZipArchiveEntry entry)> GetDlls(ZipArchive archive)
{
return archive.Entries
.Where(e => Path.GetExtension(e.FullName) == ".dll"
// Exclude analyzers and build task, as we don't care about breaking changes there
&& !e.FullName.Contains("analyzers/") && !e.FullName.Contains("analyzers\\")
&& !e.Name.Contains("Avalonia.Build.Tasks"))
.Select(e => (
entry: e,
isRef: e.FullName.Contains("ref/") || e.FullName.Contains("ref\\"),
target: Path.GetDirectoryName(e.FullName)!.Split(new [] { '/', '\\' }).Last())
)
.GroupBy(e => (e.target, e.entry.Name))
.Select(g => g.MaxBy(e => e.isRef))
.Select(e => (e.target, e.entry))
.ToArray();
}
static async Task<Stream> DownloadBaselinePackage(string packagePath, string baselineVersion)
{
/*
Gets package name from versions like:
Avalonia.0.10.0-preview1
Avalonia.11.0.999-cibuild0037534-beta
Avalonia.11.0.0
*/
var packageId = GetPackageId(packagePath);
Build.Information("Downloading {0} {1} baseline package", packageId, baselineVersion);
try
{
using var response = await s_httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get,
$"https://www.nuget.org/api/v2/package/{packageId}/{baselineVersion}"), HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync();
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
catch (Exception ex)
{
throw new InvalidOperationException($"Downloading baseline package for {packageId} {baselineVersion} failed.\r" + ex.Message, ex);
}
}
static string GetPackageId(string packagePath)
{
return Regex.Replace(
Path.GetFileNameWithoutExtension(packagePath),
"""(\.\d+\.\d+\.\d+(?:-.+)?)$""", "");
}
}

19
nukebuild/Build.cs

@ -36,6 +36,10 @@ using MicroCom.CodeGenerator;
partial class Build : NukeBuild
{
BuildParameters Parameters { get; set; }
[PackageExecutable("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net6.0")]
Tool ApiCompatTool;
protected override void OnBuildInitialized()
{
Parameters = new BuildParameters(this);
@ -278,7 +282,17 @@ partial class Build : NukeBuild
RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
Parameters.Version + ".nupkg");
});
Target ValidateApiDiff => _ => _
.DependsOn(CreateNugetPackages)
.Executes(async () =>
{
await Task.WhenAll(
Directory.GetFiles(Parameters.NugetRoot, "*.nupkg").Select(nugetPackage => ApiDiffValidation.ValidatePackage(
ApiCompatTool, nugetPackage, Parameters.ApiValidationBaseline,
Parameters.ApiValidationSuppressionFiles, Parameters.UpdateApiValidationSuppression)));
});
Target RunTests => _ => _
.DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests)
@ -288,7 +302,8 @@ partial class Build : NukeBuild
Target Package => _ => _
.DependsOn(RunTests)
.DependsOn(CreateNugetPackages);
.DependsOn(CreateNugetPackages)
.DependsOn(ValidateApiDiff);
Target CiAzureLinux => _ => _
.DependsOn(RunTests);

22
nukebuild/BuildParameters.cs

@ -10,18 +10,24 @@ using static Nuke.Common.IO.PathConstruction;
public partial class Build
{
[Parameter("configuration")]
[Parameter(Name = "configuration")]
public string Configuration { get; set; }
[Parameter("skip-tests")]
[Parameter(Name = "skip-tests")]
public bool SkipTests { get; set; }
[Parameter("force-nuget-version")]
[Parameter(Name = "force-nuget-version")]
public string ForceNugetVersion { get; set; }
[Parameter("skip-previewer")]
[Parameter(Name = "skip-previewer")]
public bool SkipPreviewer { get; set; }
[Parameter(Name = "api-baseline")]
public string ApiValidationBaseline { get; set; }
[Parameter(Name = "update-api-suppression")]
public bool? UpdateApiValidationSuppression { get; set; }
public class BuildParameters
{
public string Configuration { get; }
@ -57,7 +63,9 @@ public partial class Build
public string FileZipSuffix { get; }
public AbsolutePath ZipCoreArtifacts { get; }
public AbsolutePath ZipNuGetArtifacts { get; }
public string ApiValidationBaseline { get; }
public bool UpdateApiValidationSuppression { get; }
public AbsolutePath ApiValidationSuppressionFiles { get; }
public BuildParameters(Build b)
{
@ -103,6 +111,9 @@ public partial class Build
// VERSION
Version = b.ForceNugetVersion ?? GetVersion();
ApiValidationBaseline = b.ApiValidationBaseline ?? new Version(new Version(Version).Major, 0).ToString();
UpdateApiValidationSuppression = b.UpdateApiValidationSuppression ?? IsLocalBuild;
if (IsRunningOnAzure)
{
if (!IsNuGetRelease)
@ -125,6 +136,7 @@ public partial class Build
FileZipSuffix = Version + ".zip";
ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix);
ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix);
ApiValidationSuppressionFiles = RootDirectory / "api";
}
string GetVersion()

2
nukebuild/Numerge

@ -1 +1 @@
Subproject commit aef10ae67dc55c95f49b52a505a0be33bfa297a5
Subproject commit 9738c6121fdd143c78d3e25686a7e4e13c00f586

4
nukebuild/Shims.cs

@ -9,12 +9,12 @@ using Numerge;
public partial class Build
{
static void Information(string info)
internal static void Information(string info)
{
Logger.Info(info);
}
static void Information(string info, params object[] args)
internal static void Information(string info, params object[] args)
{
Logger.Info(info, args);
}

14
nukebuild/_build.csproj

@ -8,8 +8,8 @@
<NukeTelemetryVersion>1</NukeTelemetryVersion>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<Import Project="..\build\JetBrains.dotMemoryUnit.props" />
<Import Project="..\build\JetBrains.dotMemoryUnit.props" />
<ItemGroup>
<PackageReference Include="Nuke.Common" Version="6.2.1" />
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
@ -22,6 +22,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageDownload Include="Microsoft.DotNet.ApiCompat.Tool" Version="[7.0.305]" />
</ItemGroup>
<ItemGroup>
@ -30,9 +32,9 @@
<!-- Common build related files -->
<Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" />
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<Compile Include="Numerge/Numerge/**/*.cs" Exclude="Numerge/Numerge/obj/**/*.cs" />
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe" />
<EmbeddedResource Include="../build/avalonia.snk" />
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup>
@ -41,7 +43,5 @@
<Link>dirs.proj</Link>
</Content>
</ItemGroup>
</Project>

26
packages/Avalonia/AvaloniaBuildTasks.targets

@ -144,4 +144,30 @@
<UpToDateCheckInput Include="@(AvaloniaResource)" />
<UpToDateCheckInput Include="@(AvaloniaXaml)" />
</ItemGroup>
<PropertyGroup>
<AvaloniaFilePreviewDependsOn Condition="'$(SkipBuild)'!='True'">Build</AvaloniaFilePreviewDependsOn>
</PropertyGroup>
<Target Name="AvaloniaFilePreview" DependsOnTargets="$(AvaloniaFilePreviewDependsOn)">
<PropertyGroup>
<APreviewerUrl>http://127.0.0.1:6001</APreviewerUrl>
<APreviewExecutable>$(OutputPath)/$(AssemblyName).dll</APreviewExecutable>
<APreviewFile Condition="$(APreviewFile) == ''">MainWindow.axaml</APreviewFile>
<APreviewAssembly Condition="$(APreviewAssembly) == ''">$(APreviewExecutable)</APreviewAssembly>
<APreviewerDepsJsonPath>$([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.deps.json'))</APreviewerDepsJsonPath>
<APreviewerRuntimeConfigPath>$([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.runtimeconfig.json'))</APreviewerRuntimeConfigPath>
<APreviewTransportUrl>$([System.IO.Path]::GetFullPath('$(APreviewFile)'))</APreviewTransportUrl>
</PropertyGroup>
<Message Importance="high" Text="Launching previewer for"/>
<Message Importance="high" Text="File (APreviewFile): $(APreviewTransportUrl)"/>
<Message Importance="high" Text="Containing assembly (APreviewAssembly): $(APreviewDefiningAssembly)"/>
<Message Importance="high" Text="Executable: $(APreviewExecutable)"/>
<Message Importance="high" Text="Url (APreviewerUrl): $(APreviewerUrl)"/>
<Exec Command="dotnet exec --runtimeconfig &quot;$(APreviewerRuntimeConfigPath)&quot; --depsfile &quot;$(APreviewerDepsJsonPath)&quot; &quot;$(AvaloniaPreviewerNetCoreToolPath)&quot; --method html --html-url $(APreviewerUrl) --transport $(APreviewTransportUrl) &quot;$(APreviewExecutable)&quot;"/>
</Target>
</Project>

6
readme.md

@ -6,18 +6,16 @@
<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)
⚠️ **v11 Update - [Pausing community contributions](https://github.com/AvaloniaUI/Avalonia/discussions/10599)**
## 📖 About
[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.
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/docs/next/get-started/wpf/), it isn't a 1:1 copy, and you'll find plenty of improvements.
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.
#### Roadmap
To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239).
To see the status of some of our features, look at 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.

5
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -18,6 +18,10 @@
<Setter Property="Margin" Value="8" />
</Style>
</UniformGrid.Styles>
<StackPanel>
<TextBlock Text="MinimumPrefixLength: 0" />
<AutoCompleteBox MinimumPrefixLength="0" />
</StackPanel>
<StackPanel>
<TextBlock Text="MinimumPrefixLength: 1" />
<AutoCompleteBox MinimumPrefixLength="1" />
@ -42,7 +46,6 @@
<TextBlock Text="Disabled" />
<AutoCompleteBox IsEnabled="False" />
</StackPanel>
<StackPanel>
<TextBlock Text="ValueMemberBinding" />
<AutoCompleteBox ValueMemberBinding="{Binding Capital, x:DataType=models:StateData}" />

4
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -34,7 +34,7 @@
RowBackground="#1000">
<DataGrid.Columns>
<!-- Using HeaderTemplate -->
<DataGridTextColumn Header="Country" HeaderTemplate="{StaticResource Demo.DataTemplates.CountryHeader}" Binding="{Binding Name}" Width="6*" x:DataType="local:Country" />
<DataGridTextColumn Header="Country or Region" HeaderTemplate="{StaticResource Demo.DataTemplates.CountryHeader}" Binding="{Binding Name}" Width="6*" x:DataType="local:Country" />
<DataGridTextColumn Header="Region" Binding="{Binding Region}" Width="4*" x:DataType="local:Country" />
<DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" x:DataType="local:Country" />
<DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" x:DataType="local:Country" />
@ -68,7 +68,7 @@
<TabItem Header="Grouping">
<DataGrid Name="dataGridGrouping" Margin="12">
<DataGrid.Columns>
<DataGridTextColumn Header="Country" Binding="{Binding Name}" Width="6*" x:DataType="local:Country" />
<DataGridTextColumn Header="Country or Region" Binding="{Binding Name}" Width="6*" x:DataType="local:Country" />
<DataGridTextColumn Header="Region" Binding="{Binding Region}" Width="4*" x:DataType="local:Country" />
<DataGridTextColumn DisplayIndex="3" Header="Population" Binding="{Binding Population}" Width="3*" x:DataType="local:Country" />
<DataGridTextColumn DisplayIndex="2" Header="Area" Binding="{Binding Area}" Width="3*" x:DataType="local:Country" />

7
samples/Sandbox/MainWindow.axaml

@ -1,11 +1,4 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="Sandbox.MainWindow">
<ScrollViewer>
<StackPanel>
<Button Margin="0 100000000000000000 0 0">0</Button>
<Button>1</Button>
</StackPanel>
</ScrollViewer>
</Window>

1
src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs

@ -89,6 +89,7 @@ public class Rotate3DTransition: PageSlide
{
Easing = SlideInEasing,
Duration = Duration,
FillMode = FillMode.Forward,
Children =
{
CreateKeyFrame(0d, 90d * (forward ? 1 : -1), 1),

6
src/Avalonia.Base/Avalonia.Base.csproj

@ -43,21 +43,15 @@
<InternalsVisibleTo Include="Avalonia.FreeDesktop, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.X11, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Browser, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.OpenGL, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.DesignerSupport, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Direct2D1.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.LeakTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Benchmarks, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.X11, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Win32, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Android, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.iOS, PublicKey=$(AvaloniaPublicKey)" />

20
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@ -60,6 +60,8 @@ namespace Avalonia
}
/// <inheritdoc cref="GetObservable{T}(AvaloniaObject, AvaloniaProperty{T})"/>
/// <typeparam name="TSource">The type of the values held by the <paramref name="property"/>.</typeparam>
/// <typeparam name="TResult">The type of the value returned by the <paramref name="converter"/>.</typeparam>
/// <param name="o"/>
/// <param name="property"/>
/// <param name="converter">A method which is executed to convert each property value to <typeparamref name="TResult"/>.</param>
@ -71,6 +73,15 @@ namespace Avalonia
converter ?? throw new ArgumentNullException(nameof(converter)));
}
/// <inheritdoc cref="GetObservable{TSource,TResult}"/>
public static IObservable<TResult> GetObservable<TResult>(this AvaloniaObject o, AvaloniaProperty property, Func<object?, TResult> converter)
{
return new AvaloniaPropertyObservable<object?, TResult>(
o ?? throw new ArgumentNullException(nameof(o)),
property ?? throw new ArgumentNullException(nameof(property)),
converter ?? throw new ArgumentNullException(nameof(converter)));
}
/// <summary>
/// Gets an observable for an <see cref="AvaloniaProperty"/>.
/// </summary>
@ -92,6 +103,15 @@ namespace Avalonia
property ?? throw new ArgumentNullException(nameof(property)));
}
/// <inheritdoc cref="GetObservable{TSource,TResult}"/>
public static IObservable<BindingValue<TResult>> GetBindingObservable<TResult>(this AvaloniaObject o, AvaloniaProperty property, Func<object?, TResult> converter)
{
return new AvaloniaPropertyBindingObservable<object?, TResult>(
o ?? throw new ArgumentNullException(nameof(o)),
property ?? throw new ArgumentNullException(nameof(property)),
converter?? throw new ArgumentNullException(nameof(converter)));
}
/// <summary>
/// Gets an observable for an <see cref="AvaloniaProperty"/>.
/// </summary>

5
src/Avalonia.Base/Interactivity/EventRoute.cs

@ -120,11 +120,6 @@ namespace Avalonia.Interactivity
return;
}
if (e.Source is null)
{
throw new ArgumentException("Event source may not be null", nameof(e));
}
Interactive? lastTarget = null;
var start = 0;
var end = _route.Count;

6
src/Avalonia.Base/Media/GlyphRun.cs

@ -424,13 +424,13 @@ namespace Avalonia.Media
/// </returns>
public CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit)
{
var previousCharacterHit = FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
if (characterHit.TrailingLength != 0)
{
return new CharacterHit(characterHit.FirstCharacterIndex);
return previousCharacterHit;
}
var previousCharacterHit = FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
return new CharacterHit(previousCharacterHit.FirstCharacterIndex);
}

321
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -9,7 +9,7 @@ namespace Avalonia.Media.TextFormatting
internal static Comparer<TextBounds> TextBoundsComparer { get; } =
Comparer<TextBounds>.Create((x, y) => x.Rectangle.Left.CompareTo(y.Rectangle.Left));
private IReadOnlyList<IndexedTextRun>? _indexedTextRuns;
internal IReadOnlyList<IndexedTextRun>? _indexedTextRuns;
private readonly TextRun[] _textRuns;
private readonly double _paragraphWidth;
private readonly TextParagraphProperties _paragraphProperties;
@ -512,38 +512,45 @@ namespace Avalonia.Media.TextFormatting
/// <inheritdoc/>
public override CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit)
{
if (_textRuns.Length == 0)
if (_textRuns.Length == 0 || _indexedTextRuns is null)
{
return new CharacterHit();
}
if (TryFindNextCharacterHit(characterHit, out var nextCharacterHit))
{
return nextCharacterHit;
}
var lastTextPosition = FirstTextSourceIndex + Length;
var currentCharacterrHit = characterHit;
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
// Can't move, we're after the last character
var runIndex = GetRunIndexAtCharacterIndex(lastTextPosition, LogicalDirection.Forward, out var currentPosition);
var currentRun = GetRunAtCharacterIndex(characterIndex, LogicalDirection.Forward, out var currentPosition);
var currentRun = _textRuns[runIndex];
var nextCharacterHit = characterHit;
switch (currentRun)
{
case ShapedTextRun shapedRun:
{
nextCharacterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(characterHit);
var offset = Math.Max(0, currentPosition - shapedRun.GlyphRun.Metrics.FirstCluster - characterHit.TrailingLength);
if (offset > 0)
{
currentCharacterrHit = new CharacterHit(Math.Max(0, characterHit.FirstCharacterIndex - offset), characterHit.TrailingLength);
}
nextCharacterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(currentCharacterrHit);
if (offset > 0)
{
nextCharacterHit = new CharacterHit(nextCharacterHit.FirstCharacterIndex + offset, nextCharacterHit.TrailingLength);
}
break;
}
default:
case TextRun:
{
nextCharacterHit = new CharacterHit(currentPosition + currentRun.Length);
break;
}
}
if (characterHit.FirstCharacterIndex + characterHit.TrailingLength == nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength)
if (characterIndex == nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength)
{
return characterHit;
}
@ -554,17 +561,75 @@ namespace Avalonia.Media.TextFormatting
/// <inheritdoc/>
public override CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit)
{
if (TryFindPreviousCharacterHit(characterHit, out var previousCharacterHit))
if (_textRuns.Length == 0 || _indexedTextRuns is null)
{
return new CharacterHit();
}
if (characterHit.TrailingLength > 0 && characterHit.FirstCharacterIndex <= FirstTextSourceIndex)
{
return new CharacterHit(FirstTextSourceIndex);
}
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
if (characterIndex <= FirstTextSourceIndex)
{
return previousCharacterHit;
return new CharacterHit(FirstTextSourceIndex);
}
var currentCharacterrHit = characterHit;
var currentRun = GetRunAtCharacterIndex(characterIndex, LogicalDirection.Backward, out var currentPosition);
if (currentPosition == characterHit.FirstCharacterIndex)
{
currentRun = GetRunAtCharacterIndex(characterHit.FirstCharacterIndex, LogicalDirection.Backward, out currentPosition);
}
var previousCharacterHit = characterHit;
switch (currentRun)
{
case ShapedTextRun shapedRun:
{
var offset = Math.Max(0, currentPosition - shapedRun.GlyphRun.Metrics.FirstCluster);
if (offset > 0)
{
currentCharacterrHit = new CharacterHit(Math.Max(0, characterHit.FirstCharacterIndex - offset), characterHit.TrailingLength);
}
previousCharacterHit = shapedRun.GlyphRun.GetPreviousCaretCharacterHit(currentCharacterrHit);
if (offset > 0)
{
previousCharacterHit = new CharacterHit(previousCharacterHit.FirstCharacterIndex + offset, previousCharacterHit.TrailingLength);
}
break;
}
case TextRun:
{
if (characterHit.TrailingLength > 0)
{
previousCharacterHit = new CharacterHit(currentPosition, currentRun.Length);
}
else
{
previousCharacterHit = new CharacterHit(currentPosition + currentRun.Length);
}
break;
}
}
if (characterHit.FirstCharacterIndex <= FirstTextSourceIndex)
if (characterIndex == previousCharacterHit.FirstCharacterIndex + previousCharacterHit.TrailingLength)
{
characterHit = new CharacterHit(FirstTextSourceIndex);
return characterHit;
}
return characterHit; // Can't move, we're before the first character
return previousCharacterHit;
}
/// <inheritdoc/>
@ -1009,161 +1074,7 @@ namespace Avalonia.Media.TextFormatting
if (_textLineBreak is null && _textRuns.Length > 1 && _textRuns[_textRuns.Length - 1] is TextEndOfLine textEndOfLine)
{
_textLineBreak = new TextLineBreak(textEndOfLine);
}
}
/// <summary>
/// Tries to find the next character hit.
/// </summary>
/// <param name="characterHit">The current character hit.</param>
/// <param name="nextCharacterHit">The next character hit.</param>
/// <returns></returns>
private bool TryFindNextCharacterHit(CharacterHit characterHit, out CharacterHit nextCharacterHit)
{
nextCharacterHit = characterHit;
var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
var lastCodepointIndex = FirstTextSourceIndex + Length;
if (codepointIndex >= lastCodepointIndex)
{
return false; // Cannot go forward anymore
}
if (codepointIndex < FirstTextSourceIndex)
{
codepointIndex = FirstTextSourceIndex;
}
var runIndex = GetRunIndexAtCharacterIndex(codepointIndex, LogicalDirection.Forward, out var currentPosition);
while (runIndex < _textRuns.Length)
{
var currentRun = _textRuns[runIndex];
switch (currentRun)
{
case ShapedTextRun shapedRun:
{
var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);
var isAtEnd = foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength == FirstTextSourceIndex + Length;
if (isAtEnd && !shapedRun.GlyphRun.IsLeftToRight)
{
nextCharacterHit = foundCharacterHit;
return true;
}
nextCharacterHit = isAtEnd || characterHit.TrailingLength != 0 ?
foundCharacterHit :
new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength);
if (isAtEnd || nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex)
{
return true;
}
break;
}
default:
{
var textPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
if (textPosition == currentPosition)
{
nextCharacterHit = new CharacterHit(currentPosition + currentRun.Length);
return true;
}
break;
}
}
currentPosition += currentRun.Length;
runIndex++;
}
return false;
}
/// <summary>
/// Tries to find the previous character hit.
/// </summary>
/// <param name="characterHit">The current character hit.</param>
/// <param name="previousCharacterHit">The previous character hit.</param>
/// <returns></returns>
private bool TryFindPreviousCharacterHit(CharacterHit characterHit, out CharacterHit previousCharacterHit)
{
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
if (characterIndex == FirstTextSourceIndex)
{
previousCharacterHit = new CharacterHit(FirstTextSourceIndex);
return true;
}
previousCharacterHit = characterHit;
if (characterIndex < FirstTextSourceIndex)
{
return false; // Cannot go backward anymore.
}
var runIndex = GetRunIndexAtCharacterIndex(characterIndex, LogicalDirection.Backward, out var currentPosition);
while (runIndex >= 0)
{
var currentRun = _textRuns[runIndex];
switch (currentRun)
{
case ShapedTextRun shapedRun:
{
var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
if (foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength < characterIndex)
{
previousCharacterHit = foundCharacterHit;
return true;
}
var previousPosition = foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength;
if (foundCharacterHit.TrailingLength > 0 && previousPosition == characterIndex)
{
previousCharacterHit = new CharacterHit(foundCharacterHit.FirstCharacterIndex);
}
if (previousCharacterHit != characterHit)
{
return true;
}
break;
}
default:
{
if (characterIndex == currentPosition + currentRun.Length)
{
previousCharacterHit = new CharacterHit(currentPosition);
return true;
}
break;
}
}
currentPosition -= currentRun.Length;
runIndex--;
}
return false;
}
/// <summary>
@ -1173,15 +1084,23 @@ namespace Avalonia.Media.TextFormatting
/// <param name="direction">The logical direction.</param>
/// <param name="textPosition">The text position of the found run index.</param>
/// <returns>The text run index.</returns>
private int GetRunIndexAtCharacterIndex(int codepointIndex, LogicalDirection direction, out int textPosition)
private TextRun? GetRunAtCharacterIndex(int codepointIndex, LogicalDirection direction, out int textPosition)
{
var runIndex = 0;
textPosition = FirstTextSourceIndex;
if (_indexedTextRuns is null)
{
return null;
}
TextRun? currentRun = null;
TextRun? previousRun = null;
while (runIndex < _textRuns.Length)
while (runIndex < _indexedTextRuns.Count)
{
var currentRun = _textRuns[runIndex];
var indexedRun = _indexedTextRuns[runIndex];
currentRun = indexedRun.TextRun;
switch (currentRun)
{
@ -1189,64 +1108,49 @@ namespace Avalonia.Media.TextFormatting
{
var firstCluster = shapedRun.GlyphRun.Metrics.FirstCluster;
if (firstCluster > codepointIndex)
{
break;
}
if (previousRun is ShapedTextRun previousShaped && !previousShaped.ShapedBuffer.IsLeftToRight)
{
if (shapedRun.ShapedBuffer.IsLeftToRight)
{
if (firstCluster >= codepointIndex)
{
return --runIndex;
}
}
else
{
if (codepointIndex > firstCluster + currentRun.Length)
{
return --runIndex;
}
}
}
firstCluster += Math.Max(0, indexedRun.TextSourceCharacterIndex - firstCluster);
if (direction == LogicalDirection.Forward)
{
if (codepointIndex >= firstCluster && codepointIndex <= firstCluster + currentRun.Length)
if (codepointIndex >= firstCluster && codepointIndex < firstCluster + currentRun.Length)
{
return runIndex;
return currentRun;
}
}
else
{
if (codepointIndex > firstCluster &&
codepointIndex <= firstCluster + currentRun.Length)
if (previousRun is not null && previousRun is not ShapedTextRun && codepointIndex == textPosition + firstCluster)
{
textPosition -= previousRun.Length;
return previousRun;
}
if (codepointIndex > firstCluster && codepointIndex <= firstCluster + currentRun.Length)
{
return runIndex;
return currentRun;
}
}
if (runIndex + 1 >= _textRuns.Length)
{
return runIndex;
return currentRun;
}
textPosition += currentRun.Length;
break;
}
default:
case TextRun:
{
if (codepointIndex == textPosition)
{
return runIndex;
return currentRun;
}
if (runIndex + 1 >= _textRuns.Length)
{
return runIndex;
return currentRun;
}
textPosition += currentRun.Length;
@ -1257,10 +1161,11 @@ namespace Avalonia.Media.TextFormatting
}
runIndex++;
previousRun = currentRun;
}
return runIndex;
return currentRun;
}
private TextLineMetrics CreateLineMetrics()

2
src/Avalonia.Base/Platform/Storage/PickerOptions.cs

@ -6,7 +6,7 @@
public class PickerOptions
{
/// <summary>
/// Gets or sets the text that appears in the title bar of a folder dialog.
/// Gets or sets the text that appears in the title bar of a picker.
/// </summary>
public string? Title { get; set; }

14
src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs

@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Avalonia.Metadata;
using Avalonia.Platform;
namespace Avalonia.Rendering.Composition;
[NotClientImplementable]
public interface ICompositionGpuInterop
{
/// <summary>
@ -84,15 +87,22 @@ public enum CompositionGpuImportedImageSynchronizationCapabilities
/// <summary>
/// An imported GPU object that's usable by composition APIs
/// </summary>
[NotClientImplementable]
public interface ICompositionGpuImportedObject : IAsyncDisposable
{
/// <summary>
/// Tracks the import status of the object. Once the task is completed,
/// the user code is allowed to free the resource owner in case when a non-owning
/// sharing handle was used
/// sharing handle was used.
/// </summary>
Task ImportCompleted { get; }
/// <inheritdoc cref="ImportCompleted"/>
/// <seealso cref="ImportCompleted">ImportCompleted (recommended replacement)</seealso>
[Obsolete("Please use ICompositionGpuImportedObject.ImportCompleted instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
Task ImportCompeted { get; }
/// <summary>
/// Indicates if the device context this instance is associated with is no longer available
/// </summary>

2
src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs

@ -74,6 +74,8 @@ abstract class CompositionGpuImportedObjectBase : ICompositionGpuImportedObject
public abstract void Dispose();
public Task ImportCompleted { get; }
public Task ImportCompeted => ImportCompleted;
public bool IsLost => Context.IsLost;
public ValueTask DisposeAsync() => new(Compositor.InvokeServerJobAsync(() =>

21
src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs

@ -42,22 +42,31 @@ class ServerCompositionRenderData : SimpleServerRenderResource
_items.Add(reader.ReadObject<IRenderDataItem>());
var collector = s_resourceHashSetPool.Get();
foreach(var item in _items)
if (item is IRenderDataItemWithServerResources resourceItem)
resourceItem.Collect(collector);
CollectResources(_items, collector);
foreach (var r in collector.Resources)
{
_referencedResources.Add(r);
r.AddObserver(this);
}
collector.Resources.Clear();
s_resourceHashSetPool.ReturnAndSetNull(ref collector);
base.DeserializeChangesCore(reader, committedAt);
}
private static void CollectResources(PooledInlineList<IRenderDataItem> items, IRenderDataServerResourcesCollector collector)
{
foreach (var item in items)
{
if (item is IRenderDataItemWithServerResources resourceItem)
resourceItem.Collect(collector);
else if (item is RenderDataPushNode pushNode)
CollectResources(pushNode.Children, collector);
}
}
public Rect? Bounds
{
get
@ -133,4 +142,4 @@ class ServerCompositionRenderData : SimpleServerRenderResource
Reset();
base.Dispose();
}
}
}

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

@ -99,14 +99,15 @@ namespace Avalonia.Threading
}
}
public static RestoreContext Ensure(DispatcherPriority priority)
public static RestoreContext Ensure(DispatcherPriority priority) => Ensure(Dispatcher.UIThread, priority);
public static RestoreContext Ensure(Dispatcher dispatcher, DispatcherPriority priority)
{
if (Current is AvaloniaSynchronizationContext avaloniaContext
&& avaloniaContext.Priority == priority)
return default;
var oldContext = Current;
Dispatcher.UIThread.VerifyAccess();
SetSynchronizationContext(Dispatcher.UIThread.GetContextWithPriority(priority));
dispatcher.VerifyAccess();
SetSynchronizationContext(dispatcher.GetContextWithPriority(priority));
return new RestoreContext(oldContext);
}
}

16
src/Avalonia.Base/Threading/Dispatcher.Invoke.cs

@ -90,7 +90,7 @@ public partial class Dispatcher
{
if (callback == null)
{
throw new ArgumentNullException("callback");
throw new ArgumentNullException(nameof(callback));
}
DispatcherPriority.Validate(priority, "priority");
@ -98,7 +98,7 @@ public partial class Dispatcher
if (timeout.TotalMilliseconds < 0 &&
timeout != TimeSpan.FromMilliseconds(-1))
{
throw new ArgumentOutOfRangeException("timeout");
throw new ArgumentOutOfRangeException(nameof(timeout));
}
// Fast-Path: if on the same thread, and invoking at Send priority,
@ -106,7 +106,7 @@ public partial class Dispatcher
// call the callback directly.
if (!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess())
{
using (AvaloniaSynchronizationContext.Ensure(priority))
using (AvaloniaSynchronizationContext.Ensure(this, priority))
callback();
return;
}
@ -212,7 +212,7 @@ public partial class Dispatcher
{
if (callback == null)
{
throw new ArgumentNullException("callback");
throw new ArgumentNullException(nameof(callback));
}
DispatcherPriority.Validate(priority, "priority");
@ -220,7 +220,7 @@ public partial class Dispatcher
if (timeout.TotalMilliseconds < 0 &&
timeout != TimeSpan.FromMilliseconds(-1))
{
throw new ArgumentOutOfRangeException("timeout");
throw new ArgumentOutOfRangeException(nameof(timeout));
}
// Fast-Path: if on the same thread, and invoking at Send priority,
@ -228,7 +228,7 @@ public partial class Dispatcher
// call the callback directly.
if (!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess())
{
using (AvaloniaSynchronizationContext.Ensure(priority))
using (AvaloniaSynchronizationContext.Ensure(this, priority))
return callback();
}
@ -304,7 +304,7 @@ public partial class Dispatcher
{
if (callback == null)
{
throw new ArgumentNullException("callback");
throw new ArgumentNullException(nameof(callback));
}
DispatcherPriority.Validate(priority, "priority");
@ -379,7 +379,7 @@ public partial class Dispatcher
{
if (callback == null)
{
throw new ArgumentNullException("callback");
throw new ArgumentNullException(nameof(callback));
}
DispatcherPriority.Validate(priority, "priority");

2
src/Avalonia.Base/Threading/Dispatcher.MainLoop.cs

@ -49,7 +49,7 @@ public partial class Dispatcher
try
{
_frames.Push(frame);
using (AvaloniaSynchronizationContext.Ensure(DispatcherPriority.Normal))
using (AvaloniaSynchronizationContext.Ensure(this, DispatcherPriority.Normal))
frame.Run(_controlledImpl);
}
finally

20
src/Avalonia.Base/Threading/Dispatcher.Queue.cs

@ -9,7 +9,9 @@ public partial class Dispatcher
private readonly DispatcherPriorityQueue _queue = new();
private bool _signaled;
private bool _explicitBackgroundProcessingRequested;
private const int MaximumTimeProcessingBackgroundJobs = 50;
private const int MaximumInputStarvationTimeInFallbackMode = 50;
private const int MaximumInputStarvationTimeInExplicitProcessingExplicitMode = 50;
private int _maximumInputStarvationTime;
void RequestBackgroundProcessing()
{
@ -35,8 +37,8 @@ public partial class Dispatcher
lock (InstanceLock)
{
_explicitBackgroundProcessingRequested = false;
ExecuteJobsCore();
}
ExecuteJobsCore(true);
}
/// <summary>
@ -130,10 +132,10 @@ public partial class Dispatcher
lock (InstanceLock)
_signaled = false;
ExecuteJobsCore();
ExecuteJobsCore(false);
}
void ExecuteJobsCore()
void ExecuteJobsCore(bool fromExplicitBackgroundProcessingCallback)
{
long? backgroundJobExecutionStartedAt = null;
while (true)
@ -151,7 +153,6 @@ public partial class Dispatcher
if (job.Priority > DispatcherPriority.Input)
{
ExecuteJob(job);
backgroundJobExecutionStartedAt = null;
}
// If platform supports pending input query, ask the platform if we can continue running low priority jobs
else if (_pendingInputImpl?.CanQueryPendingInput == true)
@ -164,6 +165,13 @@ public partial class Dispatcher
return;
}
}
// We can't ask if the implementation has pending input, so we should let it to call us back
// Once it thinks that input is handled
else if (_backgroundProcessingImpl != null && !fromExplicitBackgroundProcessingCallback)
{
RequestBackgroundProcessing();
return;
}
// We can't check if there is pending input, but still need to enforce interactivity
// so we stop processing background jobs after some timeout and start a timer to continue later
else
@ -171,7 +179,7 @@ public partial class Dispatcher
if (backgroundJobExecutionStartedAt == null)
backgroundJobExecutionStartedAt = Now;
if (Now - backgroundJobExecutionStartedAt.Value > MaximumTimeProcessingBackgroundJobs)
if (Now - backgroundJobExecutionStartedAt.Value > _maximumInputStarvationTime)
{
_signaled = true;
RequestBackgroundProcessing();

2
src/Avalonia.Base/Threading/Dispatcher.Timers.cs

@ -127,7 +127,7 @@ public partial class Dispatcher
if (needToPromoteTimers)
PromoteTimers();
if (needToProcessQueue)
ExecuteJobsCore();
ExecuteJobsCore(false);
UpdateOSTimer();
}

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

@ -34,6 +34,9 @@ public partial class Dispatcher : IDispatcher
_controlledImpl = _impl as IControlledDispatcherImpl;
_pendingInputImpl = _impl as IDispatcherImplWithPendingInput;
_backgroundProcessingImpl = _impl as IDispatcherImplWithExplicitBackgroundProcessing;
_maximumInputStarvationTime = _backgroundProcessingImpl == null ?
MaximumInputStarvationTimeInFallbackMode :
MaximumInputStarvationTimeInExplicitProcessingExplicitMode;
if (_backgroundProcessingImpl != null)
_backgroundProcessingImpl.ReadyForBackgroundProcessing += OnReadyForExplicitBackgroundProcessing;
}

8
src/Avalonia.Base/Threading/DispatcherFrame.cs

@ -38,10 +38,14 @@ public class DispatcherFrame
/// for their important criteria to be met. These frames
/// should have a timeout associated with them.
/// </param>
public DispatcherFrame(bool exitWhenRequested)
public DispatcherFrame(bool exitWhenRequested) : this(Dispatcher.UIThread, exitWhenRequested)
{
Dispatcher = Dispatcher.UIThread;
Dispatcher.VerifyAccess();
}
internal DispatcherFrame(Dispatcher dispatcher, bool exitWhenRequested)
{
Dispatcher = dispatcher;
_exitWhenRequested = exitWhenRequested;
_continue = true;
}

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

@ -258,7 +258,7 @@ public class DispatcherOperation
try
{
using (AvaloniaSynchronizationContext.Ensure(Priority))
using (AvaloniaSynchronizationContext.Ensure(Dispatcher, Priority))
InvokeCore();
}
finally

16
src/Avalonia.Base/Threading/DispatcherTimer.cs

@ -62,7 +62,7 @@ public partial class DispatcherTimer
{
if (callback == null)
{
throw new ArgumentNullException("callback");
throw new ArgumentNullException(nameof(callback));
}
Tick += callback;
@ -112,11 +112,11 @@ public partial class DispatcherTimer
bool updateOSTimer = false;
if (value.TotalMilliseconds < 0)
throw new ArgumentOutOfRangeException("value",
throw new ArgumentOutOfRangeException(nameof(value),
"TimeSpan period must be greater than or equal to zero.");
if (value.TotalMilliseconds > Int32.MaxValue)
throw new ArgumentOutOfRangeException("value",
throw new ArgumentOutOfRangeException(nameof(value),
"TimeSpan period must be less than or equal to Int32.MaxValue.");
lock (_instanceLock)
@ -253,20 +253,20 @@ public partial class DispatcherTimer
{
if (dispatcher == null)
{
throw new ArgumentNullException("dispatcher");
throw new ArgumentNullException(nameof(dispatcher));
}
DispatcherPriority.Validate(priority, "priority");
if (priority == DispatcherPriority.Inactive)
{
throw new ArgumentException("Specified priority is not valid.", "priority");
throw new ArgumentException("Specified priority is not valid.", nameof(priority));
}
if (interval.TotalMilliseconds < 0)
throw new ArgumentOutOfRangeException("interval", "TimeSpan period must be greater than or equal to zero.");
throw new ArgumentOutOfRangeException(nameof(interval), "TimeSpan period must be greater than or equal to zero.");
if (interval.TotalMilliseconds > Int32.MaxValue)
throw new ArgumentOutOfRangeException("interval",
throw new ArgumentOutOfRangeException(nameof(interval),
"TimeSpan period must be less than or equal to Int32.MaxValue.");
@ -349,4 +349,4 @@ public partial class DispatcherTimer
// used by Dispatcher
internal long DueTimeInMs { get; private set; }
}
}

16
src/Avalonia.Base/Utilities/SmallDictionary.cs

@ -51,7 +51,7 @@ internal struct InlineDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey,
throw new ArgumentException("Key already exists in dictionary");
}
if (arr[c].Key == null)
if (arr[c].Key == null && free == -1)
free = c;
}
@ -337,11 +337,15 @@ internal struct InlineDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey,
}
else if (_type == Type.Array)
{
var next = _index + 1;
if (_arr!.Length - 1 < next || _arr[next].Key == null)
return false;
_index = next;
return true;
for (var next = _index + 1; next < _arr!.Length; ++next)
{
if (_arr[next].Key != null)
{
_index = next;
return true;
}
}
return false;
}
else if (_type == Type.Dictionary)
return _inner.MoveNext();

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

@ -304,7 +304,7 @@ namespace Avalonia.Build.Tasks
|| "Internal".Equals(classModifierText, StringComparison.OrdinalIgnoreCase))
classModifierPublic = false;
else
throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", precompileDirective);
throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", classModifierDirective);
}
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
@ -353,10 +353,16 @@ namespace Avalonia.Build.Tasks
((List<XamlDocumentResource>)parsedXamlDocuments).Add(new XamlDocumentResource(
parsed, res.Uri, res, classType,
classModifierPublic.Value,
populateBuilder,
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
classTypeDefinition == null && classModifierPublic.Value),
buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value)));
() => new XamlDocumentTypeBuilderProvider(
populateBuilder,
compiler.DefinePopulateMethod(
populateBuilder,
parsed,
populateName,
classTypeDefinition == null && classModifierPublic.Value),
buildName == null ?
null :
compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value))));
}
catch (Exception e)
{
@ -387,10 +393,17 @@ namespace Avalonia.Build.Tasks
foreach (var document in parsedXamlDocuments)
{
var res = (IResource)document.FileSource!;
if (document.Usage == XamlDocumentUsage.Merged && !document.IsPublic)
{
res.Remove();
continue;
}
var parsed = document.XamlDocument;
var res = (IResource)document.FileSource;
var classType = document.ClassType;
var populateBuilder = document.TypeBuilder;
var populateBuilder = document.TypeBuilderProvider.TypeBuilder;
try
{
@ -399,8 +412,8 @@ namespace Avalonia.Build.Tasks
compiler.Compile(parsed,
contextClass,
document.PopulateMethod,
document.BuildMethod,
document.TypeBuilderProvider.PopulateMethod,
document.TypeBuilderProvider.BuildMethod,
builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, true),
(closureName, closureBaseType) =>
populateBuilder.DefineSubType(closureBaseType, closureName, false),
@ -412,7 +425,7 @@ namespace Avalonia.Build.Tasks
if (classTypeDefinition != null)
{
var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve()
.Methods.First(m => m.Name == document.PopulateMethod.Name);
.Methods.First(m => m.Name == document.TypeBuilderProvider.PopulateMethod.Name);
var designLoaderFieldType = typeSystem
.GetType("System.Action`1")
@ -536,12 +549,12 @@ namespace Avalonia.Build.Tasks
}
if (document.IsPublic
&& (document.BuildMethod != null || classTypeDefinition != null))
&& (document.TypeBuilderProvider.BuildMethod != null || classTypeDefinition != null))
{
var compiledBuildMethod = document.BuildMethod == null ?
var compiledBuildMethod = document.TypeBuilderProvider.BuildMethod is not { } buildMethod ?
null :
typeSystem.GetTypeReference(builder).Resolve()
.Methods.First(m => m.Name == document.BuildMethod?.Name);
.Methods.First(m => m.Name == buildMethod.Name);
var parameterlessConstructor = compiledBuildMethod != null ?
null :
classTypeDefinition.GetConstructors().FirstOrDefault(c =>

4
src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs

@ -807,7 +807,7 @@ namespace Avalonia.Collections
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("PageSize cannot have a negative value.");
throw new ArgumentOutOfRangeException(nameof(value), "PageSize cannot have a negative value.");
}
// if the Refresh is currently deferred, cache the desired PageSize
@ -1954,7 +1954,7 @@ namespace Avalonia.Collections
// for indices larger than the count
if (index >= Count || index < 0)
{
throw new ArgumentOutOfRangeException("index");
throw new ArgumentOutOfRangeException(nameof(index));
}
if (IsGrouping)

2
src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs

@ -222,7 +222,7 @@ namespace Avalonia.Controls
{
if (element == null)
{
throw new ArgumentNullException("element");
throw new ArgumentNullException(nameof(element));
}
if (element is CheckBox checkBox)
{

2
src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs

@ -191,7 +191,7 @@ namespace Avalonia.Controls
}
if (dataGridColumn == null)
{
throw new ArgumentNullException("dataGridColumn");
throw new ArgumentNullException(nameof(dataGridColumn));
}
int columnIndexWithFiller = columnIndex;

2
src/Avalonia.Controls.DataGrid/DataGridLength.cs

@ -499,7 +499,7 @@ namespace Avalonia.Controls
{
if (destinationType == null)
{
throw new ArgumentNullException("destinationType");
throw new ArgumentNullException(nameof(destinationType));
}
if (destinationType != typeof(string))
{

11
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -1320,17 +1320,14 @@ namespace Avalonia.Controls
// Evaluate the conditions needed for completion.
// 1. Minimum prefix length
// 2. If a delay timer is in use, use it
bool populateReady = newText.Length >= MinimumPrefixLength && MinimumPrefixLength >= 0;
if (populateReady && MinimumPrefixLength == 0 && String.IsNullOrEmpty(newText) && String.IsNullOrEmpty(SearchText))
{
populateReady = false;
}
_userCalledPopulate = populateReady ? userInitiated : false;
bool minimumLengthReached = newText.Length >= MinimumPrefixLength && MinimumPrefixLength >= 0;
_userCalledPopulate = minimumLengthReached && userInitiated;
// Update the interface and values only as necessary
UpdateTextValue(newText, userInitiated);
if (populateReady)
if (minimumLengthReached)
{
_ignoreTextSelectionChange = true;

2
src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs

@ -18,7 +18,7 @@ namespace Avalonia.Automation.Peers
public ControlAutomationPeer(Control owner)
{
Owner = owner ?? throw new ArgumentNullException("owner");
Owner = owner ?? throw new ArgumentNullException(nameof(owner));
Initialize();
}

4
src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs

@ -146,12 +146,12 @@ namespace Avalonia.Automation.Peers
if (scrollHorizontally && (horizontalPercent < 0.0) || (horizontalPercent > 100.0))
{
throw new ArgumentOutOfRangeException("horizontalPercent");
throw new ArgumentOutOfRangeException(nameof(horizontalPercent));
}
if (scrollVertically && (verticalPercent < 0.0) || (verticalPercent > 100.0))
{
throw new ArgumentOutOfRangeException("verticalPercent");
throw new ArgumentOutOfRangeException(nameof(verticalPercent));
}
var offset = Owner.Offset;

10
src/Avalonia.Controls/ComboBox.cs

@ -270,6 +270,7 @@ namespace Avalonia.Controls
{
if (_popup?.IsInsidePopup(source) == true)
{
e.Handled = true;
return;
}
}
@ -516,5 +517,14 @@ namespace Avalonia.Controls
}
}
}
/// <summary>
/// Clears the selection
/// </summary>
public void Clear()
{
SelectedItem = null;
SelectedIndex = -1;
}
}
}

4
src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs

@ -165,7 +165,7 @@ namespace Avalonia.Controls.Primitives
set
{
if (value > MaximumValue || value < MinimumValue)
throw new ArgumentOutOfRangeException("SelectedValue");
throw new ArgumentOutOfRangeException(nameof(value));
var sel = CoerceSelected(value);
_selectedValue = sel;
@ -195,7 +195,7 @@ namespace Avalonia.Controls.Primitives
set
{
if (value <= 0 || value > _range)
throw new ArgumentOutOfRangeException("Increment");
throw new ArgumentOutOfRangeException(nameof(value));
_increment = value;
UpdateHelperInfo();
var sel = CoerceSelected(SelectedValue);

4
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -1113,11 +1113,11 @@ namespace Avalonia.Controls
}
if (value < Minimum)
{
throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be greater than Minimum value of {0}", Minimum));
throw new ArgumentOutOfRangeException(nameof(value), $"Value must be greater than Minimum value of {Minimum}");
}
else if (value > Maximum)
{
throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be less than Maximum value of {0}", Maximum));
throw new ArgumentOutOfRangeException(nameof(value), $"Value must be less than Maximum value of {Maximum}");
}
}

19
src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs

@ -473,18 +473,31 @@ namespace Avalonia.Controls.Presenters
}
Viewport = finalSize;
Extent = ComputeExtent(finalSize);
_isAnchorElementDirty = true;
return finalSize;
}
private Size ComputeExtent(Size viewportSize)
{
var childMargin = Child!.Margin;
if (Child.UseLayoutRounding)
{
var scale = LayoutHelper.GetLayoutScale(Child);
childMargin = LayoutHelper.RoundLayoutThickness(childMargin, scale, scale);
}
Extent = Child!.Bounds.Size.Inflate(childMargin);
_isAnchorElementDirty = true;
var extent = Child!.Bounds.Size.Inflate(childMargin);
return finalSize;
if (MathUtilities.AreClose(extent.Width, viewportSize.Width, LayoutHelper.LayoutEpsilon))
extent = extent.WithWidth(viewportSize.Width);
if (MathUtilities.AreClose(extent.Height, viewportSize.Height, LayoutHelper.LayoutEpsilon))
extent = extent.WithHeight(viewportSize.Height);
return extent;
}
private void OnScrollGesture(object? sender, ScrollGestureEventArgs e)

4
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -1395,10 +1395,8 @@ namespace Avalonia.Controls.Primitives
public object Evaluate(object? dataContext)
{
dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
// Only update the DataContext if necessary
if (!dataContext.Equals(DataContext))
if (!Equals(dataContext, DataContext))
DataContext = dataContext;
return GetValue(ValueProperty);

10
src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs

@ -98,14 +98,14 @@ namespace Avalonia.Controls.PullToRefresh
if (_scrollViewer.Content == null)
{
throw new ArgumentException(nameof(adaptee), "Adaptee's content property cannot be null.");
throw new ArgumentException("Adaptee's content property cannot be null.", nameof(adaptee));
}
var content = adaptee.Content as Visual;
if (content == null)
{
throw new ArgumentException(nameof(adaptee), "Adaptee's content property must be a Visual");
throw new ArgumentException("Adaptee's content property must be a Visual", nameof(adaptee));
}
if (content.GetVisualParent() == null)
@ -118,7 +118,7 @@ namespace Avalonia.Controls.PullToRefresh
if (content.Parent is not InputElement)
{
throw new ArgumentException(nameof(adaptee), "Adaptee's content's parent must be a InputElement");
throw new ArgumentException("Adaptee's content's parent must be a InputElement", nameof(adaptee));
}
}
@ -194,12 +194,12 @@ namespace Avalonia.Controls.PullToRefresh
var content = _scrollViewer?.Content as Visual;
if (content == null)
{
throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content property must be a Visual");
throw new ArgumentException("Adaptee's content property must be a Visual", nameof(_scrollViewer));
}
if (content.Parent is not InputElement parent)
{
throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content parent must be an InputElement");
throw new ArgumentException("Adaptee's content parent must be an InputElement", nameof(_scrollViewer));
}
MakeInteractionSource(parent);

22
src/Avalonia.Controls/Utils/StringUtils.cs

@ -76,7 +76,7 @@ namespace Avalonia.Controls.Utils
}
var codepoint = new Codepoint(text[index]);
if (!codepoint.IsWhiteSpace)
{
return false;
@ -85,12 +85,20 @@ namespace Avalonia.Controls.Utils
// preceeded by lwsp.
if (index > 0)
{
var nextCodePoint = new Codepoint(text[index + 1]);
if (index + 1 < text.Length)
{
var nextCodePoint = new Codepoint(text[index + 1]);
if (nextCodePoint.IsBreakChar)
if (nextCodePoint.IsBreakChar)
{
return true;
}
}
else
{
return true;
}
}
switch (codepoint.GeneralCategory)
@ -125,7 +133,7 @@ namespace Avalonia.Controls.Utils
}
cursor = Math.Min(cursor, text.Length);
int begin;
int i;
int cr;
@ -181,7 +189,7 @@ namespace Avalonia.Controls.Utils
{
return cursor;
}
if (cr < text.Length && text[cr] == '\r' && cr + 1 < text.Length && text[cr + 1] == '\n')
{
lf = cr + 1;
@ -214,9 +222,9 @@ namespace Avalonia.Controls.Utils
{
return i;
}
var cc = GetCharClass(text[i]);
// skip over the word, punctuation, or run of whitespace
while (i < cr && GetCharClass(text[i]) == cc)
{

2
src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs

@ -39,7 +39,7 @@ namespace Avalonia.Controls.Utils
get
{
if(index < 0 || index >= Count)
throw new ArgumentOutOfRangeException("index");
throw new ArgumentOutOfRangeException(nameof(index));
index += _start;

7
src/Avalonia.Controls/Window.cs

@ -169,6 +169,7 @@ namespace Avalonia.Controls
private readonly Size _maxPlatformClientSize;
private bool _shown;
private bool _showingAsDialog;
private bool _wasShownBefore;
/// <summary>
/// Initializes static members of the <see cref="Window"/> class.
@ -718,6 +719,7 @@ namespace Avalonia.Controls
StartRendering();
PlatformImpl?.Show(ShowActivated, false);
OnOpened(EventArgs.Empty);
_wasShownBefore = true;
}
}
@ -871,6 +873,11 @@ namespace Avalonia.Controls
private void SetWindowStartupLocation(Window? owner = null)
{
if (_wasShownBefore == true)
{
return;
}
var startupLocation = WindowStartupLocation;
if (startupLocation == WindowStartupLocation.CenterOwner &&

3
src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs

@ -72,12 +72,13 @@ namespace Avalonia.Diagnostics.ViewModels
var s = sender!;
var handled = e.Handled;
var route = e.Route;
var triggerTime = DateTime.Now;
void handler()
{
if (_currentEvent == null || !_currentEvent.IsPartOfSameEventChain(e))
{
_currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route));
_currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route), triggerTime);
_parentViewModel.RecordedEvents.Add(_currentEvent);

5
src/Avalonia.Diagnostics/Diagnostics/ViewModels/FiredEvent.cs

@ -10,11 +10,12 @@ namespace Avalonia.Diagnostics.ViewModels
private readonly RoutedEventArgs _eventArgs;
private EventChainLink? _handledBy;
public FiredEvent(RoutedEventArgs eventArgs, EventChainLink originator)
public FiredEvent(RoutedEventArgs eventArgs, EventChainLink originator, DateTime triggerTime)
{
_eventArgs = eventArgs ?? throw new ArgumentNullException(nameof(eventArgs));
Originator = originator ?? throw new ArgumentNullException(nameof(originator));
AddToChain(originator);
TriggerTime = triggerTime;
}
public bool IsPartOfSameEventChain(RoutedEventArgs e)
@ -22,6 +23,8 @@ namespace Avalonia.Diagnostics.ViewModels
return e == _eventArgs;
}
public DateTime TriggerTime { get; }
public RoutedEvent Event => _eventArgs.RoutedEvent!;
public bool IsHandled => HandledBy?.Handled == true;

10
src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml

@ -77,21 +77,23 @@
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem Classes.handled="{Binding IsHandled}">
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
<Grid ColumnDefinitions="Auto,Auto,Auto,*,Auto">
<StackPanel Grid.Column="0" Spacing="2" Orientation="Horizontal" >
<TextBlock Grid.Column="0" Text="{Binding TriggerTime, StringFormat={}{0:HH:mm:ss.fff}}"/>
<StackPanel Margin="10,0,0,0" Grid.Column="1" Spacing="2" Orientation="Horizontal" >
<TextBlock Tag="{Binding Event}" DoubleTapped="NavigateTo" Text="{Binding Event.Name}" FontWeight="Bold" Classes="nav" />
<TextBlock Text="on" />
<TextBlock Tag="{Binding Originator}" DoubleTapped="NavigateTo" Text="{Binding Originator.HandlerName}" Classes="nav" />
</StackPanel>
<StackPanel Margin="2,0,0,0" Grid.Column="1" Spacing="2" Orientation="Horizontal" IsVisible="{Binding IsHandled}" >
<StackPanel Margin="2,0,0,0" Grid.Column="2" Spacing="2" Orientation="Horizontal" IsVisible="{Binding IsHandled}" >
<TextBlock Text="::" />
<TextBlock Text="Handled by" />
<TextBlock Tag="{Binding HandledBy}" DoubleTapped="NavigateTo" Text="{Binding HandledBy.HandlerName}" Classes="nav" />
</StackPanel>
<StackPanel Grid.Column="3" Orientation="Horizontal" HorizontalAlignment="Right">
<StackPanel Grid.Column="4" Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock Text="Routing (" />
<TextBlock Text="{Binding Event.RoutingStrategies}"/>
<TextBlock Text=")"/>

10
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -3,9 +3,7 @@ using System.Runtime.InteropServices;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.MicroCom;
using Avalonia.Native.Interop;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
@ -163,6 +161,14 @@ namespace Avalonia.Native
Compositor = new Compositor(_platformGraphics, true);
AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
}
private void OnProcessExit(object? sender, EventArgs e)
{
AppDomain.CurrentDomain.ProcessExit -= OnProcessExit;
_factory.Dispose();
}
public ITrayIconImpl CreateTrayIcon()

2
src/Avalonia.Native/NativePlatformSettings.cs

@ -23,7 +23,7 @@ internal class NativePlatformSettings : DefaultPlatformSettings
AvnPlatformThemeVariant.Dark => (PlatformThemeVariant.Dark, ColorContrastPreference.NoPreference),
AvnPlatformThemeVariant.Light => (PlatformThemeVariant.Light, ColorContrastPreference.NoPreference),
AvnPlatformThemeVariant.HighContrastDark => (PlatformThemeVariant.Dark, ColorContrastPreference.High),
AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Dark, ColorContrastPreference.High),
AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Light, ColorContrastPreference.High),
_ => throw new ArgumentOutOfRangeException()
};
var color = _platformSettings.AccentColor;

8
src/Avalonia.Remote.Protocol/MetsysBson.cs

@ -752,7 +752,7 @@ namespace Metsys.Bson
if (memberExpression.Expression.NodeType != ExpressionType.Parameter && memberExpression.Expression.NodeType != ExpressionType.Convert)
{
throw new ArgumentException(string.Format("Expression '{0}' must resolve to top-level member.", lambdaExpression), nameof(lambdaExpression));
throw new ArgumentException($"Expression '{lambdaExpression}' must resolve to top-level member.", nameof(lambdaExpression));
}
return memberExpression.Member.Name;
default:
@ -942,7 +942,7 @@ namespace Metsys.Bson
return new ListWrapper();
}
}
throw new BsonException(string.Format("Collection of type {0} cannot be deserialized", type.FullName));
throw new BsonException($"Collection of type {type.FullName} cannot be deserialized");
}
public abstract void Add(object value);
@ -1514,7 +1514,7 @@ namespace Metsys.Bson.Configuration
result = Visit((MemberExpression)expression.Left);
}
var index = Expression.Lambda(expression.Right).Compile().DynamicInvoke();
return result + string.Format("[{0}]", index);
return result + $"[{index}]";
}
private string Visit(MemberExpression expression)
@ -1540,7 +1540,7 @@ namespace Metsys.Bson.Configuration
if (expression.Method.Name == "get_Item" && expression.Arguments.Count == 1)
{
var index = Expression.Lambda(expression.Arguments[0]).Compile().DynamicInvoke();
name += string.Format("[{0}]", index);
name += $"[{index}]";
}
return name;
}

50
src/Avalonia.X11/X11Clipboard.cs

@ -14,6 +14,7 @@ namespace Avalonia.X11
private readonly X11Info _x11;
private IDataObject _storedDataObject;
private IntPtr _handle;
private TaskCompletionSource<bool> _storeAtomTcs;
private TaskCompletionSource<IntPtr[]> _requestedFormatsTcs;
private TaskCompletionSource<object> _requestedDataTcs;
private readonly IntPtr[] _textAtoms;
@ -52,6 +53,12 @@ namespace Avalonia.X11
private unsafe void OnEvent(ref XEvent ev)
{
if (ev.type == XEventName.SelectionClear)
{
_storeAtomTcs?.TrySetResult(true);
return;
}
if (ev.type == XEventName.SelectionRequest)
{
var sel = ev.SelectionRequestEvent;
@ -82,18 +89,9 @@ namespace Avalonia.X11
Encoding textEnc;
if (target == _x11.Atoms.TARGETS)
{
var atoms = new HashSet<IntPtr> { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE };
foreach (var fmt in _storedDataObject.GetDataFormats())
{
if (fmt == DataFormats.Text)
foreach (var ta in _textAtoms)
atoms.Add(ta);
else
atoms.Add(_x11.Atoms.GetAtom(fmt));
}
var atoms = ConvertDataObject(_storedDataObject);
XChangeProperty(_x11.Display, window, property,
_x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms.ToArray(), atoms.Count);
_x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms, atoms.Length);
return property;
}
else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
@ -252,20 +250,41 @@ namespace Avalonia.X11
return (string)await SendDataRequest(target);
}
private void StoreAtomsInClipboardManager(IntPtr[] atoms)
private IntPtr[] ConvertDataObject(IDataObject data)
{
var atoms = new HashSet<IntPtr> { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE };
foreach (var fmt in data.GetDataFormats())
{
if (fmt == DataFormats.Text)
foreach (var ta in _textAtoms)
atoms.Add(ta);
else
atoms.Add(_x11.Atoms.GetAtom(fmt));
}
return atoms.ToArray();
}
private Task StoreAtomsInClipboardManager(IDataObject data)
{
if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
{
var clipboardManager = XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER);
if (clipboardManager != IntPtr.Zero)
{
{
if (_storeAtomTcs == null || _storeAtomTcs.Task.IsCompleted)
_storeAtomTcs = new TaskCompletionSource<bool>();
var atoms = ConvertDataObject(data);
XChangeProperty(_x11.Display, _handle, _avaloniaSaveTargetsAtom, _x11.Atoms.XA_ATOM, 32,
PropertyMode.Replace,
atoms, atoms.Length);
XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER, _x11.Atoms.SAVE_TARGETS,
_avaloniaSaveTargetsAtom, _handle, IntPtr.Zero);
return _storeAtomTcs.Task;
}
}
return Task.CompletedTask;
}
public Task SetTextAsync(string text)
@ -283,9 +302,8 @@ namespace Avalonia.X11
public Task SetDataObjectAsync(IDataObject data)
{
_storedDataObject = data;
XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero);
StoreAtomsInClipboardManager(_textAtoms);
return Task.CompletedTask;
XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero);
return StoreAtomsInClipboardManager(data);
}
public async Task<string[]> GetFormatsAsync()

5
src/Avalonia.X11/X11Structs.cs

@ -1109,7 +1109,7 @@ namespace Avalonia.X11 {
public override string ToString ()
{
return string.Format("MotifWmHints <flags={0}, functions={1}, decorations={2}, input_mode={3}, status={4}", (MotifFlags) flags.ToInt32 (), (MotifFunctions) functions.ToInt32 (), (MotifDecorations) decorations.ToInt32 (), (MotifInputMode) input_mode.ToInt32 (), status.ToInt32 ());
return $"MotifWmHints <flags={(MotifFlags)flags.ToInt32()}, functions={(MotifFunctions)functions.ToInt32()}, decorations={(MotifDecorations)decorations.ToInt32()}, input_mode={(MotifInputMode)input_mode.ToInt32()}, status={status.ToInt32()}";
}
}
@ -1707,8 +1707,7 @@ namespace Avalonia.X11 {
public override string ToString ()
{
return string.Format ("XCursorImage (version: {0}, size: {1}, width: {2}, height: {3}, xhot: {4}, yhot: {5}, delay: {6}, pixels: {7}",
version, size, width, height, xhot, yhot, delay, pixels);
return $"XCursorImage (version: {version}, size: {size}, width: {width}, height: {height}, xhot: {xhot}, yhot: {yhot}, delay: {delay}, pixels: {pixels}";
}
} ;

12
src/Browser/Avalonia.Browser/webapp/package-lock.json

@ -3296,9 +3296,9 @@
}
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@ -5560,9 +5560,9 @@
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true
},
"wrappy": {

23
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@ -231,10 +232,19 @@ namespace Avalonia.Markup.Xaml.XamlIl
?? ((IXamlAstValueNode)parsed.Root).Type.GetClrType().Name;
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + xamlName);
var builder = _sreTypeSystem.CreateTypeBuilder(tb);
parsedDocuments.Add(new XamlDocumentResource(parsed, document.BaseUri?.ToString(),
null, null, true, builder,
compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true),
document.RootInstance is null ? compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) : null));
parsedDocuments.Add(new XamlDocumentResource(
parsed,
document.BaseUri?.ToString(),
null,
null,
true,
() => new XamlDocumentTypeBuilderProvider(
builder,
compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true),
document.RootInstance is null ?
compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) :
null)));
originalDocuments.Add(document);
}
@ -242,9 +252,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
var createdTypes = parsedDocuments.Select(document =>
{
compiler.Compile(document.XamlDocument, document.TypeBuilder, document.PopulateMethod,
document.BuildMethod, document.Uri, document.FileSource);
return _sreTypeSystem.GetType(document.TypeBuilder.CreateType());
compiler.Compile(document.XamlDocument, document.TypeBuilderProvider, document.Uri, document.FileSource);
return _sreTypeSystem.GetType(document.TypeBuilderProvider.TypeBuilder.CreateType());
}).ToArray();
clrPropertyBuilder.CreateTypeInfo();

6
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -179,9 +179,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return parsed;
}
public void Compile(XamlDocument document, IXamlTypeBuilder<IXamlILEmitter> tb, IXamlMethodBuilder<IXamlILEmitter> populateMethod, IXamlMethodBuilder<IXamlILEmitter> buildMethod, string baseUri, IFileSource fileSource)
public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string baseUri, IFileSource fileSource)
{
Compile(document, _contextType, populateMethod, buildMethod,
var tb = typeBuilderProvider.TypeBuilder;
Compile(document, _contextType, typeBuilderProvider.PopulateMethod, typeBuilderProvider.BuildMethod,
_configuration.TypeMappings.XmlNamespaceInfoProvider == null ?
null :
tb.DefineSubType(_configuration.WellKnownTypes.Object,

20
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX.Ast;
using XamlX.IL.Emitters;
using XamlX.Transform.Transformers;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers;
@ -24,7 +22,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
var mergeResourceIncludeType = context.GetAvaloniaTypes().MergeResourceInclude;
var mergeSourceNodes = new List<XamlPropertyAssignmentNode>();
var mergedResourceWasAdded = false;
foreach (var manipulationNode in resourceDictionaryManipulation.Children.ToArray())
{
void ProcessXamlPropertyAssignmentNode(XamlManipulationGroupNode parent, XamlPropertyAssignmentNode assignmentNode)
@ -39,7 +36,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
{
parent.Children.Remove(assignmentNode);
mergeSourceNodes.Add(sourceAssignmentNode);
mergedResourceWasAdded = true;
}
else
{
@ -85,25 +81,29 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
return context.ParseError(
$"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node);
}
var targetDocument = context.Documents.FirstOrDefault(d =>
string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase))
?.XamlDocument.Root as XamlValueWithManipulationNode;
if (targetDocument is null)
string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase));
if (targetDocument?.XamlDocument.Root is not XamlValueWithManipulationNode targetDocumentRoot)
{
return context.ParseError(
$"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node);
}
var singleRootObject = ((XamlManipulationGroupNode)targetDocument.Manipulation)
var singleRootObject = ((XamlManipulationGroupNode)targetDocumentRoot.Manipulation)
.Children.OfType<XamlObjectInitializationNode>().Single();
if (singleRootObject.Type != resourceDictionaryType)
{
return context.ParseError(
$"MergeResourceInclude can only include another ResourceDictionary", propertyNode, node);
"MergeResourceInclude can only include another ResourceDictionary", propertyNode, node);
}
manipulationGroup.Add(singleRootObject.Manipulation);
if (targetDocument.Usage == XamlDocumentUsage.Unknown)
{
targetDocument.Usage = XamlDocumentUsage.Merged;
}
}
// Order of resources is defined by ResourceDictionary.TryGetResource.

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs

@ -1,5 +1,4 @@
using System;
using XamlX.Ast;
using XamlX.Ast;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
@ -14,4 +13,5 @@ internal interface IXamlDocumentResource
IXamlMethod PopulateMethod { get; }
IFileSource? FileSource { get; }
XamlDocument XamlDocument { get; }
XamlDocumentUsage Usage { get; set; }
}

34
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs

@ -1,6 +1,5 @@
using System;
using XamlX.Ast;
using XamlX.IL;
using XamlX.TypeSystem;
#nullable enable
@ -8,24 +7,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
internal class XamlDocumentResource : IXamlDocumentResource
{
private readonly Func<XamlDocumentTypeBuilderProvider> _createTypeBuilderProvider;
private XamlDocumentTypeBuilderProvider? _typeBuilderProvider;
public XamlDocumentResource(
XamlDocument xamlDocument,
string? uri,
IFileSource? fileSource,
IXamlType? classType,
bool isPublic,
IXamlTypeBuilder<IXamlILEmitter> typeBuilder,
IXamlMethodBuilder<IXamlILEmitter> populateMethod,
IXamlMethodBuilder<IXamlILEmitter>? buildMethod)
Func<XamlDocumentTypeBuilderProvider> createTypeBuilderProvider)
{
_createTypeBuilderProvider = createTypeBuilderProvider;
XamlDocument = xamlDocument;
Uri = uri;
FileSource = fileSource;
ClassType = classType;
IsPublic = isPublic;
TypeBuilder = typeBuilder;
PopulateMethod = populateMethod;
BuildMethod = buildMethod;
}
public XamlDocument XamlDocument { get; }
@ -34,10 +32,22 @@ internal class XamlDocumentResource : IXamlDocumentResource
public IXamlType? ClassType { get; }
public bool IsPublic { get; }
public IXamlTypeBuilder<IXamlILEmitter> TypeBuilder { get; }
public IXamlMethodBuilder<IXamlILEmitter> PopulateMethod { get; }
public IXamlMethodBuilder<IXamlILEmitter>? BuildMethod { get; }
public XamlDocumentUsage Usage { get; set; }
public XamlDocumentTypeBuilderProvider TypeBuilderProvider
{
get
{
if (_typeBuilderProvider is null)
{
_typeBuilderProvider = _createTypeBuilderProvider();
Usage = XamlDocumentUsage.Used;
}
return _typeBuilderProvider;
}
}
IXamlMethod? IXamlDocumentResource.BuildMethod => BuildMethod;
IXamlMethod IXamlDocumentResource.PopulateMethod => PopulateMethod;
IXamlMethod? IXamlDocumentResource.BuildMethod => TypeBuilderProvider.BuildMethod;
IXamlMethod IXamlDocumentResource.PopulateMethod => TypeBuilderProvider.PopulateMethod;
}

23
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs

@ -0,0 +1,23 @@
#nullable enable
using XamlX.IL;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
internal sealed class XamlDocumentTypeBuilderProvider
{
public XamlDocumentTypeBuilderProvider(
IXamlTypeBuilder<IXamlILEmitter> typeBuilder,
IXamlMethodBuilder<IXamlILEmitter> populateMethod,
IXamlMethodBuilder<IXamlILEmitter>? buildMethod)
{
TypeBuilder = typeBuilder;
PopulateMethod = populateMethod;
BuildMethod = buildMethod;
}
public IXamlTypeBuilder<IXamlILEmitter> TypeBuilder { get; }
public IXamlMethodBuilder<IXamlILEmitter> PopulateMethod { get; }
public IXamlMethodBuilder<IXamlILEmitter>? BuildMethod { get; }
}

8
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs

@ -0,0 +1,8 @@
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
internal enum XamlDocumentUsage
{
Unknown,
Merged,
Used
}

3
src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs

@ -33,8 +33,7 @@ namespace Avalonia.Win32.Automation
return null;
var p = WindowImpl.PointToClient(new PixelPoint((int)x, (int)y));
var peer = (WindowBaseAutomationPeer)Peer;
var found = InvokeSync(() => peer.GetPeerFromPoint(p));
var found = InvokeSync(() => Peer.GetPeerFromPoint(p));
var result = GetOrCreate(found) as IRawElementProviderFragment;
return result;
}

16
src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs

@ -38,12 +38,10 @@ namespace Avalonia.Win32.OpenGl
[MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))]
[MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))]
[MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))]
private static bool Initialize() => _initialized ??= InitializeCore();
[MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))]
[MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))]
[MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))]
private static bool InitializeCore()
{
Dispatcher.UIThread.VerifyAccess();
@ -74,9 +72,9 @@ namespace Avalonia.Win32.OpenGl
Marshal.GetDelegateForFunctionPointer<WglChoosePixelFormatARBDelegate>(
wglGetProcAddress("wglChoosePixelFormatARB"));
s_glDebugMessageCallback =
Marshal.GetDelegateForFunctionPointer<GlDebugMessageCallbackDelegate>(
wglGetProcAddress("glDebugMessageCallback"));
s_glDebugMessageCallback = wglGetProcAddress("glDebugMessageCallback") is { } setDebugCallback && setDebugCallback != default ?
Marshal.GetDelegateForFunctionPointer<GlDebugMessageCallbackDelegate>(setDebugCallback) :
null;
var formats = new int[1];
@ -144,8 +142,12 @@ namespace Avalonia.Win32.OpenGl
});
}
using(new WglRestoreContext(dc, context, null))
s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero);
if (s_glDebugMessageCallback is not null)
{
using (new WglRestoreContext(dc, context, null))
s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero);
}
if (context != IntPtr.Zero)
return new WglContext(shareContext, version, context, window, dc,
_defaultPixelFormat, _defaultPfd);

4
src/Windows/Avalonia.Win32/Win32GlManager.cs

@ -20,6 +20,10 @@ static class Win32GlManager
{
AvaloniaLocator.CurrentMutable.Bind<IPlatformGraphics>().ToConstant(gl);
}
if (gl is IPlatformGraphicsOpenGlContextFactory openGlFactory)
{
AvaloniaLocator.CurrentMutable.Bind<IPlatformGraphicsOpenGlContextFactory>().ToConstant(openGlFactory);
}
return gl;
}

3
src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs

@ -28,6 +28,9 @@ namespace Avalonia.Win32.WinRT.Composition
public static readonly Guid CLSID_D2D1Border =
new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27);
public static readonly Guid CLSID_D2D1Opacity =
new Guid("811d79a4-de28-4454-8094-c64685f8bd4c");
public static readonly Guid CLSID_D2D1Brightness =
new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87);

104
src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs

@ -52,6 +52,110 @@ namespace Avalonia.Win32.WinRT.Composition
_sources = null;
}
}
class BorderEffect : WinUIEffectBase
{
private readonly int _x;
private readonly int _y;
public override Guid EffectId => D2DEffects.CLSID_D2D1Border;
public override uint PropertyCount => 2;
public BorderEffect(int x, int y, params IGraphicsEffectSource[] _sources):base(_sources)
{
_x = x;
_y = y;
}
public override IPropertyValue? GetProperty(uint index)
{
if (index == 0)
return new WinRTPropertyValue((uint)_x);
if (index == 1)
return new WinRTPropertyValue((uint)_y);
return null;
}
}
class BlendEffect : WinUIEffectBase
{
private readonly int _mode;
public BlendEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources)
{
_mode = mode;
}
public override Guid EffectId => D2DEffects.CLSID_D2D1Blend;
public override uint PropertyCount => 1;
public override IPropertyValue? GetProperty(uint index)
{
if (index == 0)
return new WinRTPropertyValue((uint)_mode);
return null;
}
}
class CompositeStepEffect : WinUIEffectBase
{
private readonly float _mode;
public CompositeStepEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources)
{
_mode = mode;
}
public override Guid EffectId => D2DEffects.CLSID_D2D1Composite;
public override uint PropertyCount => 1;
public override IPropertyValue? GetProperty(uint index)
{
if (index == 0)
return new WinRTPropertyValue((uint)_mode);
return null;
}
}
class OpacityEffect : WinUIEffectBase
{
private readonly float _opacity;
public OpacityEffect(float opacity, params IGraphicsEffectSource[] _sources) : base(_sources)
{
_opacity = opacity;
}
public override Guid EffectId => D2DEffects.CLSID_D2D1Opacity;
public override uint PropertyCount => 1;
public override IPropertyValue? GetProperty(uint index)
{
if (index == 0)
return new WinRTPropertyValue(_opacity);
return null;
}
}
class ColorSourceEffect : WinUIEffectBase
{
private readonly float[] _color;
public ColorSourceEffect(float[] color)
{
_color = color;
}
public override Guid EffectId => D2DEffects.CLSID_D2D1Flood;
public override uint PropertyCount => 1;
public override IPropertyValue? GetProperty(uint index)
{
if (index == 0)
return new WinRTPropertyValue(_color);
return null;
}
}
internal class WinUIGaussianBlurEffect : WinUIEffectBase
{

30
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs

@ -12,7 +12,8 @@ internal class WinUiCompositedWindow : IDisposable
public EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo WindowInfo { get; }
private readonly WinUiCompositionShared _shared;
private readonly ICompositionRoundedRectangleGeometry? _compositionRoundedRectangleGeometry;
private readonly IVisual? _mica;
private readonly IVisual? _micaLight;
private readonly IVisual? _micaDark;
private readonly IVisual _blur;
private readonly IVisual _visual;
private PixelSize _size;
@ -25,7 +26,8 @@ internal class WinUiCompositedWindow : IDisposable
{
_compositionRoundedRectangleGeometry?.Dispose();
_blur.Dispose();
_mica?.Dispose();
_micaLight?.Dispose();
_micaDark?.Dispose();
_visual.Dispose();
_surfaceBrush.Dispose();
_target.Dispose();
@ -50,14 +52,20 @@ internal class WinUiCompositedWindow : IDisposable
_target.SetRoot(containerVisual);
_blur = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.BlurBrush);
if (shared.MicaBrush != null)
if (shared.MicaBrushLight != null)
{
_mica = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrush);
containerChildren.InsertAtTop(_mica);
_micaLight = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushLight);
containerChildren.InsertAtTop(_micaLight);
}
if (shared.MicaBrushDark != null)
{
_micaDark = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushDark);
containerChildren.InsertAtTop(_micaDark);
}
_compositionRoundedRectangleGeometry =
WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _mica);
WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _micaLight, _micaDark);
containerChildren.InsertAtTop(_blur);
using var spriteVisual = shared.Compositor.CreateSpriteVisual();
@ -68,9 +76,6 @@ internal class WinUiCompositedWindow : IDisposable
using var compositionBrush = _surfaceBrush.QueryInterface<ICompositionBrush>();
spriteVisual.SetBrush(compositionBrush);
_target.SetRoot(containerVisual);
}
public void SetSurface(ICompositionSurface surface) => _surfaceBrush.SetSurface(surface);
@ -79,12 +84,13 @@ internal class WinUiCompositedWindow : IDisposable
{
lock (_shared.SyncRoot)
{
_blur.SetIsVisible(blurEffect == BlurEffect.Acrylic
|| blurEffect == BlurEffect.Mica && _mica == null ?
|| (blurEffect == BlurEffect.MicaLight && _micaLight == null) ||
(blurEffect == BlurEffect.MicaDark && _micaDark == null) ?
1 :
0);
_mica?.SetIsVisible(blurEffect == BlurEffect.Mica ? 1 : 0);
_micaLight?.SetIsVisible(blurEffect == BlurEffect.MicaLight ? 1 : 0);
_micaDark?.SetIsVisible(blurEffect == BlurEffect.MicaDark ? 1 : 0);
}
}

9
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs

@ -9,7 +9,8 @@ internal class WinUiCompositionShared : IDisposable
public ICompositor5 Compositor5 { get; }
public ICompositorDesktopInterop DesktopInterop { get; }
public ICompositionBrush BlurBrush { get; }
public ICompositionBrush? MicaBrush { get; }
public ICompositionBrush? MicaBrushLight { get; }
public ICompositionBrush? MicaBrushDark { get; }
public object SyncRoot { get; } = new();
public static readonly Version MinWinCompositionVersion = new(10, 0, 17134);
@ -21,14 +22,16 @@ internal class WinUiCompositionShared : IDisposable
Compositor = compositor.CloneReference();
Compositor5 = compositor.QueryInterface<ICompositor5>();
BlurBrush = WinUiCompositionUtils.CreateAcrylicBlurBackdropBrush(compositor);
MicaBrush = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor);
MicaBrushLight = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 242, 0.6f);
MicaBrushDark = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 32, 0.8f);
DesktopInterop = compositor.QueryInterface<ICompositorDesktopInterop>();
}
public void Dispose()
{
BlurBrush.Dispose();
MicaBrush?.Dispose();
MicaBrushLight?.Dispose();
MicaBrushDark?.Dispose();
DesktopInterop.Dispose();
Compositor.Dispose();
Compositor5.Dispose();

72
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs

@ -1,3 +1,4 @@
using System;
using System.Numerics;
using MicroCom.Runtime;
@ -5,16 +6,72 @@ namespace Avalonia.Win32.WinRT.Composition;
internal static class WinUiCompositionUtils
{
public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor)
public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor, float color, float opacity)
{
if (Win32Platform.WindowsVersion.Build < 22000)
return null;
using var backDropParameterFactory =
NativeWinRTMethods.CreateActivationFactory<ICompositionEffectSourceParameterFactory>(
"Windows.UI.Composition.CompositionEffectSourceParameter");
var tint = new[] { color / 255f, color / 255f, color / 255f, 255f / 255f };
using var tintColorEffect = new ColorSourceEffect(tint);
using var tintOpacityEffect = new OpacityEffect(1.0f, tintColorEffect);
using var tintOpacityEffectFactory = compositor.CreateEffectFactory(tintOpacityEffect);
using var tintOpacityEffectBrushEffect = tintOpacityEffectFactory.CreateBrush();
using var tintOpacityEffectBrush = tintOpacityEffectBrushEffect.QueryInterface<ICompositionBrush>();
using var luminosityColorEffect = new ColorSourceEffect(tint);
using var luminosityOpacityEffect = new OpacityEffect(opacity, luminosityColorEffect);
using var luminosityOpacityEffectFactory = compositor.CreateEffectFactory(luminosityOpacityEffect);
using var luminosityOpacityEffectBrushEffect = luminosityOpacityEffectFactory.CreateBrush();
using var luminosityOpacityEffectBrush =
luminosityOpacityEffectBrushEffect.QueryInterface<ICompositionBrush>();
using var compositorWithBlurredWallpaperBackdropBrush =
compositor.QueryInterface<ICompositorWithBlurredWallpaperBackdropBrush>();
using var blurredWallpaperBackdropBrush =
compositorWithBlurredWallpaperBackdropBrush?.TryCreateBlurredWallpaperBackdropBrush();
return blurredWallpaperBackdropBrush?.QueryInterface<ICompositionBrush>();
using var micaBackdropBrush = blurredWallpaperBackdropBrush?.QueryInterface<ICompositionBrush>();
using var backgroundParameterAsSource =
GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle);
using var foregroundParameterAsSource =
GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle);
using var luminosityBlendEffect =
new BlendEffect(23, backgroundParameterAsSource, foregroundParameterAsSource);
using var luminosityBlendEffectFactory = compositor.CreateEffectFactory(luminosityBlendEffect);
using var luminosityBlendEffectBrush = luminosityBlendEffectFactory.CreateBrush();
using var luminosityBlendEffectBrush1 = luminosityBlendEffectBrush.QueryInterface<ICompositionBrush>();
luminosityBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush);
luminosityBlendEffectBrush.SetSourceParameter(foregroundHandle, luminosityOpacityEffectBrush);
using var backgroundParameterAsSource1 =
GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle1);
using var foregroundParameterAsSource1 =
GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle1);
using var colorBlendEffect =
new BlendEffect(22, backgroundParameterAsSource1, foregroundParameterAsSource1);
using var colorBlendEffectFactory = compositor.CreateEffectFactory(colorBlendEffect);
using var colorBlendEffectBrush = colorBlendEffectFactory.CreateBrush();
colorBlendEffectBrush.SetSourceParameter(backgroundHandle1, luminosityBlendEffectBrush1);
colorBlendEffectBrush.SetSourceParameter(foregroundHandle1, tintOpacityEffectBrush);
// colorBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush);
using var micaBackdropBrush1 = colorBlendEffectBrush.QueryInterface<ICompositionBrush>();
return micaBackdropBrush1.CloneReference();
}
public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor)
@ -97,4 +154,15 @@ internal static class WinUiCompositionUtils
brush?.Dispose();
}
}
private static IGraphicsEffectSource GetParameterSource(string name,
ICompositionEffectSourceParameterFactory backDropParameterFactory, out IntPtr handle)
{
var backdropString = new HStringInterop(name);
var backDropParameter =
backDropParameterFactory.Create(backdropString.Handle);
var backDropParameterAsSource = backDropParameter.QueryInterface<IGraphicsEffectSource>();
handle = backdropString.Handle;
return backDropParameterAsSource;
}
}

3
src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs

@ -4,7 +4,8 @@
{
None,
Acrylic,
Mica
MicaLight,
MicaDark
}
internal interface IBlurHost

23
src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs

@ -1,4 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Avalonia.Win32.WinRT
@ -16,7 +17,15 @@ namespace Avalonia.Win32.WinRT
UInt32 = u;
Type = PropertyType.UInt32;
}
public WinRTPropertyValue(float[] uiColor)
{
Type = PropertyType.SingleArray;
_singleArray = uiColor;
}
private readonly float[]? _singleArray;
public PropertyType Type { get; }
public int IsNumericScalar { get; }
public byte UInt8 { get; }
@ -62,7 +71,17 @@ namespace Avalonia.Win32.WinRT
public unsafe ulong* GetUInt64Array(uint* __valueSize) => throw NotImplemented;
public unsafe float* GetSingleArray(uint* __valueSize) => throw NotImplemented;
public unsafe float* GetSingleArray(uint* __valueSize)
{
if (_singleArray == null)
throw NotImplemented;
*__valueSize = (uint)_singleArray.Length;
var allocCoTaskMem = Marshal.AllocCoTaskMem(_singleArray.Length * Unsafe.SizeOf<float>());
Marshal.Copy(_singleArray, 0, allocCoTaskMem, _singleArray.Length);
float* s = (float*)allocCoTaskMem;
return s;
}
public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented;

13
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -106,6 +106,7 @@ namespace Avalonia.Win32
private static POINTER_PEN_INFO[]? s_historyPenInfos;
private static POINTER_INFO[]? s_historyInfos;
private static MOUSEMOVEPOINT[]? s_mouseHistoryInfos;
private PlatformThemeVariant _currentThemeVariant;
public WindowImpl()
{
@ -474,7 +475,12 @@ namespace Avalonia.Win32
return;
SetUseHostBackdropBrush(false);
_blurHost?.SetBlur(BlurEffect.Mica);
_blurHost?.SetBlur(_currentThemeVariant switch
{
PlatformThemeVariant.Light => BlurEffect.MicaLight,
PlatformThemeVariant.Dark => BlurEffect.MicaDark,
_ => throw new ArgumentOutOfRangeException()
});
}
private void SetAccentState(AccentState state)
@ -778,6 +784,7 @@ namespace Avalonia.Win32
public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
_currentThemeVariant = themeVariant;
if (Win32Platform.WindowsVersion.Build >= 22000)
{
var pvUseBackdropBrush = themeVariant == PlatformThemeVariant.Dark ? 1 : 0;
@ -786,6 +793,10 @@ namespace Avalonia.Win32
(int)DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE,
&pvUseBackdropBrush,
sizeof(int));
if (TransparencyLevel == WindowTransparencyLevel.Mica)
{
SetTransparencyMica(Win32Platform.WindowsVersion);
}
}
}

1
src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj

@ -5,6 +5,7 @@
<PackageId>Avalonia.Analyzers</PackageId>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsPackable>true</IsPackable>
<IncludeSymbols>false</IncludeSymbols>
<IsRoslynComponent>true</IsRoslynComponent>
</PropertyGroup>

1
src/tools/Avalonia.Generators/Avalonia.Generators.csproj

@ -5,6 +5,7 @@
<PackageId>Avalonia.Generators</PackageId>
<DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants>
<IsPackable>true</IsPackable>
<IncludeSymbols>false</IncludeSymbols>
<IsRoslynComponent>true</IsRoslynComponent>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>

8
src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Avalonia.Generators.Common.Domain;
using Microsoft.CodeAnalysis;
@ -31,7 +32,7 @@ internal class AvaloniaNameGenerator : INameGenerator
_code = code;
}
public IReadOnlyList<GeneratedPartialClass> GenerateNameReferences(IEnumerable<AdditionalText> additionalFiles)
public IEnumerable<GeneratedPartialClass> GenerateNameReferences(IEnumerable<AdditionalText> additionalFiles, CancellationToken cancellationToken)
{
var resolveViews =
from file in additionalFiles
@ -39,7 +40,8 @@ internal class AvaloniaNameGenerator : INameGenerator
file.Path.EndsWith(".paml") ||
file.Path.EndsWith(".axaml")) &&
_pathPattern.Matches(file.Path)
let xaml = file.GetText()!.ToString()
let xaml = file.GetText(cancellationToken)?.ToString()
where xaml != null
let view = _classes.ResolveView(xaml)
where view != null && _namespacePattern.Matches(view.Namespace)
select view;
@ -51,7 +53,7 @@ internal class AvaloniaNameGenerator : INameGenerator
let fileName = ResolveViewFileName(view, _naming)
select new GeneratedPartialClass(fileName, code);
return query.ToList();
return query;
}
private static string ResolveViewFileName(ResolvedView view, ViewFileNamingStrategy strategy) => strategy switch

15
src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs

@ -22,8 +22,19 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator
return;
}
var partials = generator.GenerateNameReferences(context.AdditionalFiles);
foreach (var (fileName, content) in partials) context.AddSource(fileName, content);
var partials = generator.GenerateNameReferences(context.AdditionalFiles, context.CancellationToken);
foreach (var (fileName, content) in partials)
{
if(context.CancellationToken.IsCancellationRequested)
{
break;
}
context.AddSource(fileName, content);
}
}
catch (OperationCanceledException)
{
}
catch (Exception exception)
{

3
src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs

@ -1,11 +1,12 @@
using System.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis;
namespace Avalonia.Generators.NameGenerator;
internal interface INameGenerator
{
IReadOnlyList<GeneratedPartialClass> GenerateNameReferences(IEnumerable<AdditionalText> additionalFiles);
IEnumerable<GeneratedPartialClass> GenerateNameReferences(IEnumerable<AdditionalText> additionalFiles, CancellationToken cancellationToken);
}
internal record GeneratedPartialClass(string FileName, string Content);

2
tests/Avalonia.Base.UnitTests/Media/GlyphRunTests.cs

@ -111,7 +111,7 @@ namespace Avalonia.Base.UnitTests.Media
using(UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
using (var glyphRun = CreateGlyphRun(advances, clusters, bidiLevel))
{
var characterHit = glyphRun.GetPreviousCaretCharacterHit(new CharacterHit(currentIndex, currentLength));
var characterHit = glyphRun.GetPreviousCaretCharacterHit(new CharacterHit(currentIndex + currentLength));
Assert.Equal(previousIndex, characterHit.FirstCharacterIndex);

53
tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs

@ -0,0 +1,53 @@
#nullable enable
using System.Collections.Generic;
using Avalonia.Utilities;
using Xunit;
namespace Avalonia.Base.UnitTests.Utilities;
public class InlineDictionaryTests
{
[Fact]
public void Enumeration_After_Add_With_Internal_Array_Works()
{
var dic = new InlineDictionary<string, int>();
dic.Add("foo", 1);
dic.Add("bar", 2);
dic.Add("baz", 3);
Assert.Equal(
new[] {
new KeyValuePair<string, int>("foo", 1),
new KeyValuePair<string, int>("bar", 2),
new KeyValuePair<string, int>("baz", 3)
},
dic);
}
[Fact]
public void Enumeration_After_Remove_With_Internal_Array_Works()
{
var dic = new InlineDictionary<string, int>();
dic.Add("foo", 1);
dic.Add("bar", 2);
dic.Add("baz", 3);
Assert.Equal(
new[] {
new KeyValuePair<string, int>("foo", 1),
new KeyValuePair<string, int>("bar", 2),
new KeyValuePair<string, int>("baz", 3)
},
dic);
dic.Remove("bar");
Assert.Equal(
new[] {
new KeyValuePair<string, int>("foo", 1),
new KeyValuePair<string, int>("baz", 3)
},
dic);
}
}

37
tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs

@ -1,21 +1,15 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Markup.Data;
using Avalonia.Platform;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Moq;
using Xunit;
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Avalonia.Input;
namespace Avalonia.Controls.UnitTests
{
@ -439,6 +433,29 @@ namespace Avalonia.Controls.UnitTests
});
}
[Fact]
public void Explicit_Dropdown_Open_Request_MinimumPrefixLength_0()
{
RunTest((control, textbox) =>
{
control.Text = "";
control.MinimumPrefixLength = 0;
Dispatcher.UIThread.RunJobs();
Assert.False(control.IsDropDownOpen);
control.RaiseEvent(new KeyEventArgs
{
RoutedEvent = InputElement.KeyDownEvent,
Key = Key.Down
});
Dispatcher.UIThread.RunJobs();
Assert.True(control.IsDropDownOpen);
});
}
/// <summary>
/// Retrieves a defined predicate filter through a new AutoCompleteBox
/// control instance.
@ -1072,14 +1089,14 @@ namespace Avalonia.Controls.UnitTests
private AutoCompleteBox CreateControl()
{
var datePicker =
var autoCompleteBox =
new AutoCompleteBox
{
Template = CreateTemplate()
};
datePicker.ApplyTemplate();
return datePicker;
autoCompleteBox.ApplyTemplate();
return autoCompleteBox;
}
private TextBox GetTextBox(AutoCompleteBox control)
{

31
tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs

@ -275,6 +275,37 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.Equal(new Size(203.2, 203.2), target.Extent);
}
[Fact]
public void Extent_Should_Be_Rounded_To_Viewport_When_Close()
{
var root = new TestRoot
{
LayoutScaling = 1.75,
UseLayoutRounding = true
};
var target = new ScrollContentPresenter
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Content = new Border
{
Width = 164.57142857142858,
Height = 164.57142857142858,
Margin = new Thickness(6)
}
};
root.Child = target;
target.UpdateChild();
target.Measure(new Size(1000, 1000));
target.Arrange(new Rect(0, 0, 1000, 1000));
Assert.Equal(new Size(176.00000000000003, 176.00000000000003), target.Child!.DesiredSize);
Assert.Equal(new Size(176, 176), target.Viewport);
Assert.Equal(new Size(176, 176), target.Extent);
}
[Fact]
public void Extent_Width_Should_Be_Arrange_Width_When_CanScrollHorizontally_False()
{

16
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs

@ -268,6 +268,22 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.True(called);
}
[Fact]
public void Handles_Null_SelectedItem_When_SelectedValueBinding_Assigned()
{
// Issue #11220
var items = new object[] { null };
var sic = new SelectingItemsControl
{
ItemsSource = items,
SelectedIndex = 0,
SelectedValueBinding = new Binding("Name"),
Template = Template()
};
Assert.Null(sic.SelectedValue);
}
private static FuncControlTemplate Template()
{
return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>

35
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -513,6 +513,41 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Window_Should_Not_Be_Centered_When_WindowStartupLocation_Is_CenterScreen_And_Window_Is_Hidden_And_Shown()
{
var screen1 = new Mock<Screen>(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true);
var screens = new Mock<IScreenImpl>();
screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object });
screens.Setup(x => x.ScreenFromPoint(It.IsAny<PixelPoint>())).Returns(screen1.Object);
var windowImpl = MockWindowingPlatform.CreateWindowMock();
windowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480));
windowImpl.Setup(x => x.DesktopScaling).Returns(1);
windowImpl.Setup(x => x.RenderScaling).Returns(1);
windowImpl.Setup(x => x.Screen).Returns(screens.Object);
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window(windowImpl.Object)
{
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
window.Show();
var expected = new PixelPoint(150, 400);
window.Position = expected;
window.IsVisible = false;
window.IsVisible = true;
Assert.Equal(expected, window.Position);
}
}
[Fact]
public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen()
{

116
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -194,7 +194,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
for (var i = 0; i < clusters.Count; i++)
{
var expectedCluster = clusters[i];
var actualCluster = nextCharacterHit.FirstCharacterIndex;
var actualCluster = nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength;
Assert.Equal(expectedCluster, actualCluster);
@ -278,16 +278,6 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
Assert.Equal(clusters[i],
previousCharacterHit.FirstCharacterIndex + previousCharacterHit.TrailingLength);
}
firstCharacterHit = previousCharacterHit;
firstCharacterHit = textLine.GetPreviousCaretCharacterHit(firstCharacterHit);
previousCharacterHit = textLine.GetPreviousCaretCharacterHit(firstCharacterHit);
Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex);
Assert.Equal(0, previousCharacterHit.TrailingLength);
}
}
@ -728,6 +718,110 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
}
}
[Fact]
public void Should_GetNextCaretCharacterHit_From_Mixed_TextBuffer()
{
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new MixedTextBufferTextSource();
var formatter = new TextFormatterImpl();
var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
var characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(9, 1));
Assert.Equal(10, characterHit.FirstCharacterIndex);
Assert.Equal(1, characterHit.TrailingLength);
characterHit = textLine.GetNextCaretCharacterHit(characterHit);
Assert.Equal(11, characterHit.FirstCharacterIndex);
Assert.Equal(1, characterHit.TrailingLength);
characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(19, 1));
Assert.Equal(20, characterHit.FirstCharacterIndex);
Assert.Equal(1, characterHit.TrailingLength);
characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(10));
Assert.Equal(11, characterHit.FirstCharacterIndex);
Assert.Equal(0, characterHit.TrailingLength);
characterHit = textLine.GetNextCaretCharacterHit(characterHit);
Assert.Equal(12, characterHit.FirstCharacterIndex);
Assert.Equal(0, characterHit.TrailingLength);
characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(20));
Assert.Equal(21, characterHit.FirstCharacterIndex);
Assert.Equal(0, characterHit.TrailingLength);
}
}
[Fact]
public void Should_GetPreviousCaretCharacterHit_From_Mixed_TextBuffer()
{
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new MixedTextBufferTextSource();
var formatter = new TextFormatterImpl();
var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
var characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(20, 1));
Assert.Equal(19, characterHit.FirstCharacterIndex);
Assert.Equal(1, characterHit.TrailingLength);
characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(10, 1));
Assert.Equal(9, characterHit.FirstCharacterIndex);
Assert.Equal(1, characterHit.TrailingLength);
characterHit = textLine.GetPreviousCaretCharacterHit(characterHit);
Assert.Equal(8, characterHit.FirstCharacterIndex);
Assert.Equal(1, characterHit.TrailingLength);
characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(21));
Assert.Equal(20, characterHit.FirstCharacterIndex);
Assert.Equal(0, characterHit.TrailingLength);
characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(11));
Assert.Equal(10, characterHit.FirstCharacterIndex);
Assert.Equal(0, characterHit.TrailingLength);
characterHit = textLine.GetPreviousCaretCharacterHit(characterHit);
Assert.Equal(9, characterHit.FirstCharacterIndex);
Assert.Equal(0, characterHit.TrailingLength);
}
}
private class MixedTextBufferTextSource : ITextSource
{
public TextRun? GetTextRun(int textSourceIndex)

1
tests/Avalonia.UnitTests/TestRoot.cs

@ -35,7 +35,6 @@ namespace Avalonia.UnitTests
public TestRoot(Control child)
: this(false, child)
{
Child = child;
}
public TestRoot(bool useGlobalStyles, Control child)

Loading…
Cancel
Save