Browse Source

Merge branch 'master' into fix-20173

pull/20303/head
Javier Suárez 2 days ago
committed by GitHub
parent
commit
46eeb31b81
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 28
      api/Avalonia.Skia.nupkg.xml
  2. 420
      api/Avalonia.nupkg.xml
  3. 40
      samples/ControlCatalog.Desktop/Program.cs
  4. 20
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  5. 2
      samples/IntegrationTestApp/MainWindow.axaml.cs
  6. 2
      samples/IntegrationTestApp/Pages/EmbeddingPage.axaml
  7. 69
      samples/IntegrationTestApp/Pages/EmbeddingPage.axaml.cs
  8. 44
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  9. 19
      src/Android/Avalonia.Android/Platform/AndroidScreens.cs
  10. 8
      src/Avalonia.Base/Controls/IResourceHost.cs
  11. 4
      src/Avalonia.Base/Controls/ResourceDictionary.cs
  12. 22
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  13. 6
      src/Avalonia.Base/Controls/ResourceProvider.cs
  14. 28
      src/Avalonia.Base/Controls/ResourcesChangedEventArgs.cs
  15. 45
      src/Avalonia.Base/Controls/ResourcesChangedHelper.cs
  16. 11
      src/Avalonia.Base/Controls/ResourcesChangedToken.cs
  17. 2
      src/Avalonia.Base/Data/CompiledBinding.cs
  18. 13
      src/Avalonia.Base/Data/ReflectionBinding.cs
  19. 1
      src/Avalonia.Base/Data/TemplateBinding.cs
  20. 12
      src/Avalonia.Base/Diagnostics/ObsoletionMessages.cs
  21. 3
      src/Avalonia.Base/IOptionalFeatureProvider.cs
  22. 2
      src/Avalonia.Base/Input/MouseDevice.cs
  23. 4
      src/Avalonia.Base/Input/Pointer.cs
  24. 4
      src/Avalonia.Base/Media/Imaging/Bitmap.cs
  25. 17
      src/Avalonia.Base/Metadata/ConstructorArgumentAttribute.cs
  26. 6
      src/Avalonia.Base/Platform/ISurfaceOrientation.cs
  27. 9
      src/Avalonia.Base/Platform/SurfaceOrientation.cs
  28. 39
      src/Avalonia.Base/StyledElement.cs
  29. 2
      src/Avalonia.Base/Styling/StyleBase.cs
  30. 6
      src/Avalonia.Base/Utilities/Ref.cs
  31. 16
      src/Avalonia.Controls/Application.cs
  32. 26
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs
  33. 153
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  34. 27
      src/Avalonia.Controls/NativeMenuBar.cs
  35. 4
      src/Avalonia.Controls/NativeMenuBarPresenter.cs
  36. 14
      src/Avalonia.Controls/NativeMenuItem.cs
  37. 5
      src/Avalonia.Controls/Primitives/IPopupHost.cs
  38. 18
      src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
  39. 1
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
  40. 1
      src/Avalonia.Controls/Primitives/PopupPositioning/PopupPositionRequest.cs
  41. 11
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  42. 6
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  43. 6
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  44. 23
      src/Avalonia.Controls/TopLevel.cs
  45. 6
      src/Avalonia.FreeDesktop/DBusMenuExporter.cs
  46. 2
      src/Avalonia.Native/IAvnMenuItem.cs
  47. 16
      src/Avalonia.Native/TopLevelImpl.cs
  48. 2
      src/Avalonia.OpenGL/GlConsts.cs
  49. 2
      src/Avalonia.OpenGL/GlInterface.cs
  50. 2
      src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs
  51. 2
      src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs
  52. 9
      src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs
  53. 4
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  54. 19
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs
  55. 3
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs
  56. 5
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  57. 196
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  58. 6
      src/Markup/Avalonia.Markup.Xaml/Data/DynamicResourceExpression.cs
  59. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
  60. 7
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs
  61. 1
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs
  62. 10
      src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs
  63. 2
      src/Markup/Avalonia.Markup/Data/Binding.cs
  64. 8
      src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
  65. 46
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
  66. 3
      tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs
  67. 2
      tests/Avalonia.Benchmarks/Data/Binding_Setup.cs
  68. 2
      tests/Avalonia.Benchmarks/Data/Binding_Values.cs
  69. 8
      tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs
  70. 3
      tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj
  71. 3
      tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj
  72. 8
      tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs
  73. 19
      tests/Avalonia.Markup.UnitTests/Data/BindingTests_Delay.cs
  74. 3
      tests/Avalonia.Markup.UnitTests/Data/BindingTests_Self.cs

28
api/Avalonia.Skia.nupkg.xml

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

420
api/Avalonia.nupkg.xml

@ -19,24 +19,54 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IOptionalFeatureProvider</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IReadableBitmapWithAlphaImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.OptionalFeatureProviderExtensions</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Utilities.StringTokenizer</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AutoCompleteBox.BindingEvaluator`1</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.NativeMenuItemToggleType</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.Primitives.IScrollable</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Markup.Xaml.ConstructorArgumentAttribute</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.Fonts.FontFamilyLoader</Target>
@ -61,30 +91,66 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IOptionalFeatureProvider</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IReadableBitmapWithAlphaImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.OptionalFeatureProviderExtensions</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Utilities.StringTokenizer</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AutoCompleteBox.BindingEvaluator`1</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.NativeMenuItemToggleType</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.Primitives.IScrollable</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Markup.Xaml.ConstructorArgumentAttribute</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.Fonts.FontFamilyLoader</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.ResourcesChangedEventArgs.Empty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.DrawingImage.ViewboxProperty</Target>
@ -97,6 +163,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.ResourcesChangedEventArgs.#ctor</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Data.ReflectionBinding.#ctor(System.String,Avalonia.Data.BindingMode)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers)</Target>
@ -283,6 +361,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NativeMenuBar.EnableMenuItemClickForwardingProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NativeMenuItem.ToggleTypeProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.TextBlock.LetterSpacingProperty</Target>
@ -367,6 +457,36 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NativeMenuBar.SetEnableMenuItemClickForwarding(Avalonia.Controls.MenuItem,System.Boolean)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NativeMenuItem.get_ToggleType</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.OverlayPopupHost.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.OverlayPopupHost.CreatePopupHost(Avalonia.Visual,Avalonia.IAvaloniaDependencyResolver)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.PopupRoot.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control)</Target>
@ -421,6 +541,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Data.Binding.#ctor(System.String,Avalonia.Data.BindingMode)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Markup.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Markup.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension.#ctor(System.String,Avalonia.Data.BindingMode)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
@ -451,6 +583,12 @@
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Dialogs.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Dialogs.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.ResourcesChangedEventArgs.Empty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.DrawingImage.ViewboxProperty</Target>
@ -463,6 +601,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.ResourcesChangedEventArgs.#ctor</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Data.ReflectionBinding.#ctor(System.String,Avalonia.Data.BindingMode)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers)</Target>
@ -649,6 +799,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NativeMenuBar.EnableMenuItemClickForwardingProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NativeMenuItem.ToggleTypeProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.TextBlock.LetterSpacingProperty</Target>
@ -733,6 +895,36 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NativeMenuBar.SetEnableMenuItemClickForwarding(Avalonia.Controls.MenuItem,System.Boolean)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NativeMenuItem.get_ToggleType</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.OverlayPopupHost.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.OverlayPopupHost.CreatePopupHost(Avalonia.Visual,Avalonia.IAvaloniaDependencyResolver)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.PopupRoot.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control)</Target>
@ -793,6 +985,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Dialogs.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Dialogs.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Data.Binding.#ctor(System.String,Avalonia.Data.BindingMode)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Markup.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Markup.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension.#ctor(System.String,Avalonia.Data.BindingMode)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
@ -1141,36 +1345,252 @@
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0007</DiagnosticId>
<Target>T:Avalonia.Controls.ResourcesChangedEventArgs</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0007</DiagnosticId>
<Target>T:Avalonia.Controls.ResourcesChangedEventArgs</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Media.ImmediateDrawingContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Media.StreamGeometryContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPlatformGraphicsContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPlatformGraphicsWithFeatures</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPlatformRenderInterfaceContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWriteableBitmapImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Application</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Controls.Platform.IWin32OptionsTopLevelImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPopupImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.ITopLevelImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWindowBaseImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWindowImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Metal.IMetalDevice</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Metal.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Metal.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.OpenGL.Egl.EglContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.OpenGL.IGlContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Vulkan.IVulkanDevice</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Vulkan.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Vulkan.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Vulkan.IVulkanPlatformGraphicsContext</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Vulkan.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Vulkan.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Media.ImmediateDrawingContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Media.StreamGeometryContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPlatformGraphicsContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPlatformGraphicsWithFeatures</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPlatformRenderInterfaceContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWriteableBitmapImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Application</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Controls.Platform.IWin32OptionsTopLevelImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IPopupImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.ITopLevelImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWindowBaseImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWindowImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Metal.IMetalDevice</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Metal.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Metal.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.OpenGL.Egl.EglContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.OpenGL.IGlContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Vulkan.IVulkanDevice</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Vulkan.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Vulkan.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Vulkan.IVulkanPlatformGraphicsContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Vulkan.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Vulkan.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0009</DiagnosticId>
<Target>T:Avalonia.Controls.ResourcesChangedEventArgs</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0009</DiagnosticId>
<Target>T:Avalonia.Platform.Screen</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0009</DiagnosticId>
<Target>T:Avalonia.Controls.ResourcesChangedEventArgs</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0009</DiagnosticId>
<Target>T:Avalonia.Platform.Screen</Target>

40
samples/ControlCatalog.Desktop/Program.cs

@ -8,8 +8,10 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Headless;
using Avalonia.LinuxFramebuffer;
using Avalonia.LinuxFramebuffer.Output;
using Avalonia.LogicalTree;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
using Avalonia.Vulkan;
@ -19,16 +21,9 @@ namespace ControlCatalog.Desktop
{
static class Program
{
private static bool s_useFramebuffer;
[STAThread]
static int Main(string[] args)
{
if (args.Contains("--fbdev"))
{
s_useFramebuffer = true;
}
if (args.Contains("--wait-for-attach"))
{
Console.WriteLine("Attach debugger and use 'Set next statement'");
@ -45,12 +40,27 @@ namespace ControlCatalog.Desktop
double GetScaling()
{
var idx = Array.IndexOf(args, "--scaling");
if (idx != 0 && args.Length > idx + 1 &&
if (idx >= 0 && args.Length > idx + 1 &&
double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling))
return scaling;
return 1;
}
if (s_useFramebuffer)
SurfaceOrientation GetOrientation()
{
var idx = Array.IndexOf(args, "--orientation");
if (idx >= 0 && args.Length > idx + 1 &&
Enum.TryParse<SurfaceOrientation>(args[idx + 1], true, out var orientation))
return orientation;
return SurfaceOrientation.Rotation0;
}
string? GetCard()
{
var idx = Array.IndexOf(args, "--card");
if (idx >= 0 && args.Length > idx + 1)
return args[idx + 1];
return null;
}
if (args.Contains("--fbdev"))
{
SilenceConsole();
return builder.StartLinuxFbDev(args, new FbDevOutputOptions()
@ -108,13 +118,17 @@ namespace ControlCatalog.Desktop
else if (args.Contains("--drm"))
{
SilenceConsole();
return builder.StartLinuxDrm(args, scaling: GetScaling());
return builder.StartLinuxDrm(args, card: GetCard(), options: new DrmOutputOptions()
{
Scaling = GetScaling(),
Orientation = GetOrientation(),
});
}
else if (args.Contains("--dxgi"))
{
builder.With(new Win32PlatformOptions()
{
CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain }
CompositionMode = [Win32CompositionMode.LowLatencyDxgiSwapChain]
});
return builder.StartWithClassicDesktopLifetime(args);
}
@ -151,14 +165,14 @@ namespace ControlCatalog.Desktop
.WithDeveloperTools()
.AfterSetup(builder =>
{
EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin()
EmbedSample.Implementation = OperatingSystem.IsWindows() ? new EmbedSampleWin()
: OperatingSystem.IsMacOS() ? new EmbedSampleMac()
: OperatingSystem.IsLinux() ? new EmbedSampleGtk()
: null;
})
.LogToTrace();
static void SilenceConsole()
private static void SilenceConsole()
{
new Thread(() =>
{

20
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -7,30 +7,12 @@ using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.LogicalTree;
using ControlCatalog.Models;
namespace ControlCatalog.Pages
{
public partial class AutoCompleteBoxPage : UserControl
{
public class StateData
{
public string Name { get; private set; }
public string Abbreviation { get; private set; }
public string Capital { get; private set; }
public StateData(string name, string abbreviatoin, string capital)
{
Name = name;
Abbreviation = abbreviatoin;
Capital = capital;
}
public override string ToString()
{
return Name;
}
}
private static StateData[] BuildAllStates()
{
return new StateData[]

2
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -37,7 +37,7 @@ namespace IntegrationTestApp
{
Header = (string?)page.Name,
ToolTip = $"Tip:{(string?)page.Name}",
ToggleType = NativeMenuItemToggleType.Radio,
ToggleType = MenuItemToggleType.Radio
};
menuItem.Click += (_, _) =>

2
samples/IntegrationTestApp/Pages/EmbeddingPage.axaml

@ -16,5 +16,7 @@
</Popup>
</StackPanel>
<Button Name="Reset" Click="Reset_Click">Reset</Button>
<Button Name="RunNativeModalSession" Click="RunNativeModalSession_OnClick">Open Native Modal</Button>
<TextBox Name="ModalResultTextBox" />
</StackPanel>
</UserControl>

69
samples/IntegrationTestApp/Pages/EmbeddingPage.axaml.cs

@ -1,10 +1,19 @@
using System;
using Avalonia.Automation;
using Avalonia.Controls;
using Avalonia.Controls.Embedding;
using Avalonia.Interactivity;
using IntegrationTestApp.Embedding;
using MonoMac.AppKit;
using MonoMac.CoreGraphics;
using MonoMac.ObjCRuntime;
namespace IntegrationTestApp;
public partial class EmbeddingPage : UserControl
{
private const long NSModalResponseContinue = -1002;
public EmbeddingPage()
{
InitializeComponent();
@ -19,5 +28,65 @@ public partial class EmbeddingPage : UserControl
private void Reset_Click(object? sender, RoutedEventArgs e)
{
ResetText();
ModalResultTextBox.Text = "";
}
private void RunNativeModalSession_OnClick(object? sender, RoutedEventArgs e)
{
MacHelper.EnsureInitialized();
var app = NSApplication.SharedApplication;
var modalWindow = CreateNativeWindow();
var session = app.BeginModalSession(modalWindow);
while (true)
{
if (app.RunModalSession(session) != NSModalResponseContinue)
break;
}
app.EndModalSession(session);
}
private NSWindow CreateNativeWindow()
{
var button = new Button
{
Name = "ButtonInModal",
Content = "Button"
};
AutomationProperties.SetAutomationId(button, "ButtonInModal");
var root = new EmbeddableControlRoot
{
Width = 200,
Height = 200,
Content = button
};
root.Prepare();
var window = new NSWindow(
new CGRect(0, 0, root.Width, root.Height),
NSWindowStyle.Titled | NSWindowStyle.Closable,
NSBackingStore.Buffered,
false);
window.Identifier = "ModalNativeWindow";
window.WillClose += (_, _) => NSApplication.SharedApplication.StopModal();
button.Click += (_, _) =>
{
ModalResultTextBox.Text = "Clicked";
window.Close();
};
if (root.TryGetPlatformHandle() is not { } handle)
throw new InvalidOperationException("Could not get platform handle");
window.ContentView = (NSView)Runtime.GetNSObject(handle.Handle)!;
root.StartRendering();
return window;
}
}

44
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -119,22 +119,14 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity
activatableLifetime.CurrentIntendActivity = this;
}
if (Intent?.Data is { } androidUri
&& androidUri.IsAbsolute
&& Uri.TryCreate(androidUri.ToString(), UriKind.Absolute, out var uri))
{
if (uri.Scheme == Uri.UriSchemeFile)
{
if (AndroidStorageItem.CreateItem(this, androidUri) is { } item)
{
_onActivated?.Invoke(this, new FileActivatedEventArgs(new [] { item }));
}
}
else
{
_onActivated?.Invoke(this, new ProtocolActivatedEventArgs(uri));
}
}
HandleIntent(Intent);
}
protected override void OnNewIntent(Intent? intent)
{
base.OnNewIntent(intent);
HandleIntent(intent);
}
protected override void OnStop()
@ -218,6 +210,26 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity
_view = new AvaloniaView(this) { Content = initialContent };
}
private void HandleIntent(Intent? intent)
{
if (intent?.Data is { } androidUri
&& androidUri.IsAbsolute
&& Uri.TryCreate(androidUri.ToString(), UriKind.Absolute, out var uri))
{
if (uri.Scheme == Uri.UriSchemeFile || uri.Scheme == "content")
{
if (AndroidStorageItem.CreateItem(this, androidUri) is { } item)
{
_onActivated?.Invoke(this, new FileActivatedEventArgs(new[] { item }));
}
}
else
{
_onActivated?.Invoke(this, new ProtocolActivatedEventArgs(uri));
}
}
}
public void OnBackInvoked()
{
var eventArgs = new AndroidBackRequestedEventArgs();

19
src/Android/Avalonia.Android/Platform/AndroidScreens.cs

@ -10,6 +10,7 @@ using AndroidX.Window.Layout;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Platform;
using AndroidOrientation = global::Android.Content.Res.Orientation;
using AndroidRotation = global::Android.Views.SurfaceOrientation;
namespace Avalonia.Android.Platform;
@ -53,7 +54,7 @@ internal class AndroidScreen(Display display) : PlatformScreen(new PlatformHandl
var orientation = displayContext.Resources?.Configuration?.Orientation;
if (orientation == AndroidOrientation.Square)
naturalOrientation = ScreenOrientation.None;
else if (rotation is SurfaceOrientation.Rotation0 or SurfaceOrientation.Rotation180)
else if (rotation is AndroidRotation.Rotation0 or AndroidRotation.Rotation180)
naturalOrientation = orientation == AndroidOrientation.Landscape ?
ScreenOrientation.Landscape :
ScreenOrientation.Portrait;
@ -73,14 +74,14 @@ internal class AndroidScreen(Display display) : PlatformScreen(new PlatformHandl
CurrentOrientation = (display.Rotation, naturalOrientation) switch
{
(_, ScreenOrientation.None) => ScreenOrientation.None,
(SurfaceOrientation.Rotation0, ScreenOrientation.Landscape) => ScreenOrientation.Landscape,
(SurfaceOrientation.Rotation90, ScreenOrientation.Landscape) => ScreenOrientation.Portrait,
(SurfaceOrientation.Rotation180, ScreenOrientation.Landscape) => ScreenOrientation.LandscapeFlipped,
(SurfaceOrientation.Rotation270, ScreenOrientation.Landscape) => ScreenOrientation.PortraitFlipped,
(SurfaceOrientation.Rotation0, _) => ScreenOrientation.Portrait,
(SurfaceOrientation.Rotation90, _) => ScreenOrientation.Landscape,
(SurfaceOrientation.Rotation180, _) => ScreenOrientation.PortraitFlipped,
(SurfaceOrientation.Rotation270, _) => ScreenOrientation.LandscapeFlipped,
(AndroidRotation.Rotation0, ScreenOrientation.Landscape) => ScreenOrientation.Landscape,
(AndroidRotation.Rotation90, ScreenOrientation.Landscape) => ScreenOrientation.Portrait,
(AndroidRotation.Rotation180, ScreenOrientation.Landscape) => ScreenOrientation.LandscapeFlipped,
(AndroidRotation.Rotation270, ScreenOrientation.Landscape) => ScreenOrientation.PortraitFlipped,
(AndroidRotation.Rotation0, _) => ScreenOrientation.Portrait,
(AndroidRotation.Rotation90, _) => ScreenOrientation.Landscape,
(AndroidRotation.Rotation180, _) => ScreenOrientation.PortraitFlipped,
(AndroidRotation.Rotation270, _) => ScreenOrientation.LandscapeFlipped,
_ => ScreenOrientation.Portrait
};
}

8
src/Avalonia.Base/Controls/IResourceHost.cs

@ -29,12 +29,4 @@ namespace Avalonia.Controls
/// </remarks>
void NotifyHostedResourcesChanged(ResourcesChangedEventArgs e);
}
// TODO12: merge with IResourceHost
internal interface IResourceHost2 : IResourceHost
{
event EventHandler<ResourcesChangedToken> ResourcesChanged2;
void NotifyHostedResourcesChanged(ResourcesChangedToken token);
}
}

4
src/Avalonia.Base/Controls/ResourceDictionary.cs

@ -358,7 +358,7 @@ namespace Avalonia.Controls
if (hasResources)
{
owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create());
owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}
@ -385,7 +385,7 @@ namespace Avalonia.Controls
if (hasResources)
{
owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create());
owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}

22
src/Avalonia.Base/Controls/ResourceNodeExtensions.cs

@ -158,7 +158,7 @@ namespace Avalonia.Controls
protected override void Initialize()
{
_target.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2);
_target.ResourcesChanged += ResourcesChanged;
if (_target is IThemeVariantHost themeVariantHost)
{
@ -168,7 +168,7 @@ namespace Avalonia.Controls
protected override void Deinitialize()
{
_target.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2);
_target.ResourcesChanged -= ResourcesChanged;
if (_target is IThemeVariantHost themeVariantHost)
{
@ -186,11 +186,6 @@ namespace Avalonia.Controls
PublishNext(GetValue());
}
private void ResourcesChanged2(object? sender, ResourcesChangedToken token)
{
PublishNext(GetValue());
}
private void ActualThemeVariantChanged(object? sender, EventArgs e)
{
PublishNext(GetValue());
@ -230,7 +225,7 @@ namespace Avalonia.Controls
_target.OwnerChanged += OwnerChanged;
_owner = _target.Owner;
_owner?.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2);
_owner?.ResourcesChanged += ResourcesChanged;
if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
{
@ -242,7 +237,7 @@ namespace Avalonia.Controls
{
_target.OwnerChanged -= OwnerChanged;
_owner?.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2);
_owner?.ResourcesChanged -= ResourcesChanged;
if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
{
@ -270,7 +265,7 @@ namespace Avalonia.Controls
private void OwnerChanged(object? sender, EventArgs e)
{
_owner?.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2);
_owner?.ResourcesChanged -= ResourcesChanged;
if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
{
@ -279,7 +274,7 @@ namespace Avalonia.Controls
_owner = _target.Owner;
_owner?.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2);
_owner?.ResourcesChanged += ResourcesChanged;
if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost2)
{
@ -299,11 +294,6 @@ namespace Avalonia.Controls
PublishNext();
}
private void ResourcesChanged2(object? sender, ResourcesChangedToken token)
{
PublishNext();
}
private object? GetValue()
{
var theme = _overrideThemeVariant ?? (_target.Owner as IThemeVariantHost)?.ActualThemeVariant;

6
src/Avalonia.Base/Controls/ResourceProvider.cs

@ -45,7 +45,7 @@ public abstract class ResourceProvider : AvaloniaObject, IResourceProvider
protected void RaiseResourcesChanged()
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedToken.Create());
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
/// <summary>
@ -57,7 +57,7 @@ public abstract class ResourceProvider : AvaloniaObject, IResourceProvider
{
if (HasResources)
{
owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create());
owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}
@ -70,7 +70,7 @@ public abstract class ResourceProvider : AvaloniaObject, IResourceProvider
{
if (HasResources)
{
owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create());
owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}

28
src/Avalonia.Base/Controls/ResourcesChangedEventArgs.cs

@ -1,10 +1,24 @@
using System;
using System.Threading;
namespace Avalonia.Controls
namespace Avalonia.Controls;
/// <summary>
/// Represents the event arguments of <see cref="IResourceHost.ResourcesChanged"/>.
/// The <see cref="SequenceNumber"/> identifies the changes.
/// </summary>
/// <param name="SequenceNumber">The sequence number used to identify the changes.</param>
/// <remarks>
/// For performance reasons, this type is a struct.
/// Avoid using a default instance of this type or its default constructor, call <see cref="Create"/> instead.
/// </remarks>
public readonly record struct ResourcesChangedEventArgs(int SequenceNumber)
{
// TODO12: change this to be a struct, remove ResourcesChangedToken
public class ResourcesChangedEventArgs : EventArgs
{
public static new readonly ResourcesChangedEventArgs Empty = new ResourcesChangedEventArgs();
}
private static int s_lastSequenceNumber;
/// <summary>
/// Creates a new instance of <see cref="ResourcesChangedEventArgs"/> with an auto-incremented sequence number.
/// </summary>
/// <returns></returns>
public static ResourcesChangedEventArgs Create()
=> new(Interlocked.Increment(ref s_lastSequenceNumber));
}

45
src/Avalonia.Base/Controls/ResourcesChangedHelper.cs

@ -1,45 +0,0 @@
using System;
using Avalonia.LogicalTree;
namespace Avalonia.Controls;
internal static class ResourcesChangedHelper
{
internal static void NotifyHostedResourcesChanged(this IResourceHost host, ResourcesChangedToken token)
{
if (host is IResourceHost2 host2)
host2.NotifyHostedResourcesChanged(token);
else
host.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
internal static void NotifyResourcesChanged(this ILogical logical, ResourcesChangedToken token)
{
if (logical is StyledElement styledElement)
styledElement.NotifyResourcesChanged(token);
else
logical.NotifyResourcesChanged(ResourcesChangedEventArgs.Empty);
}
internal static void SubscribeToResourcesChanged(
this IResourceHost host,
EventHandler<ResourcesChangedEventArgs> handler,
EventHandler<ResourcesChangedToken> handler2)
{
if (host is IResourceHost2 host2)
host2.ResourcesChanged2 += handler2;
else
host.ResourcesChanged += handler;
}
internal static void UnsubscribeFromResourcesChanged(
this IResourceHost host,
EventHandler<ResourcesChangedEventArgs> handler,
EventHandler<ResourcesChangedToken> handler2)
{
if (host is IResourceHost2 host2)
host2.ResourcesChanged2 -= handler2;
else
host.ResourcesChanged -= handler;
}
}

11
src/Avalonia.Base/Controls/ResourcesChangedToken.cs

@ -1,11 +0,0 @@
using System.Threading;
namespace Avalonia.Controls;
internal record struct ResourcesChangedToken(int SequenceNumber)
{
private static int s_lastSequenceNumber;
public static ResourcesChangedToken Create()
=> new(Interlocked.Increment(ref s_lastSequenceNumber));
}

2
src/Avalonia.Base/Data/CompiledBinding.cs

@ -7,6 +7,7 @@ using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Data.Core.ExpressionNodes;
using Avalonia.Data.Core.Parsers;
using Avalonia.Metadata;
namespace Avalonia.Data;
@ -70,6 +71,7 @@ public class CompiledBinding : BindingBase
/// <summary>
/// Gets or sets the binding path.
/// </summary>
[ConstructorArgument("path")]
public CompiledBindingPath? Path { get; set; }
/// <summary>

13
src/Avalonia.Base/Data/ReflectionBinding.cs

@ -8,6 +8,7 @@ using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Data.Core.ExpressionNodes;
using Avalonia.Data.Core.Parsers;
using Avalonia.Metadata;
using Avalonia.Utilities;
namespace Avalonia.Data
@ -34,17 +35,6 @@ namespace Avalonia.Data
{
Path = path;
}
/// <summary>
/// Initializes a new instance of the <see cref="ReflectionBinding"/> class.
/// </summary>
/// <param name="path">The binding path.</param>
/// <param name="mode">The binding mode.</param>
public ReflectionBinding(string path, BindingMode mode)
{
Path = path;
Mode = mode;
}
/// <summary>
/// Gets or sets the amount of time, in milliseconds, to wait before updating the binding
@ -95,6 +85,7 @@ namespace Avalonia.Data
/// <summary>
/// Gets or sets the binding path.
/// </summary>
[ConstructorArgument("path")]
public string Path { get; set; } = "";
/// <summary>

1
src/Avalonia.Base/Data/TemplateBinding.cs

@ -48,6 +48,7 @@ namespace Avalonia.Data
/// <summary>
/// Gets or sets the name of the source property on the templated parent.
/// </summary>
[ConstructorArgument("property")]
[InheritDataTypeFrom(InheritDataTypeFromScopeKind.ControlTemplate)]
public AvaloniaProperty? Property { get; set; }

12
src/Avalonia.Base/Diagnostics/ObsoletionMessages.cs

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Diagnostics;
internal static class ObsoletionMessages
{
public const string MayBeRemovedInAvalonia12 = "This API may be removed in Avalonia 12. If you depend on this API, please open an issue with details of your use-case.";
}

3
src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs → src/Avalonia.Base/IOptionalFeatureProvider.cs

@ -1,8 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
// TODO12: move to Avalonia namespace.
namespace Avalonia.Platform;
namespace Avalonia;
public interface IOptionalFeatureProvider
{

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

@ -34,6 +34,8 @@ namespace Avalonia.Input
_pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
}
internal Pointer Pointer => _pointer;
internal static TMouseDevice GetOrCreatePrimary<TMouseDevice>() where TMouseDevice : MouseDevice, new()
{
if (_primary is TMouseDevice device)

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

@ -77,6 +77,7 @@ namespace Avalonia.Input
if (oldVisual != null)
oldVisual.DetachedFromVisualTree -= OnCaptureDetached;
Captured = control;
CaptureSource = source;
if (source != CaptureSource.Platform)
PlatformCapture(control);
@ -115,6 +116,7 @@ namespace Avalonia.Input
public IInputElement? Captured { get; private set; }
public PointerType Type { get; }
public bool IsPrimary { get; }
/// <summary>
@ -124,6 +126,8 @@ namespace Avalonia.Input
public bool IsGestureRecognitionSkipped { get; set; }
internal CaptureSource CaptureSource { get; private set; } = CaptureSource.Platform;
public void Dispose()
{
if (Captured != null)

4
src/Avalonia.Base/Media/Imaging/Bitmap.cs

@ -291,9 +291,7 @@ namespace Avalonia.Media.Imaging
{
get
{
// TODO12: We should probably make PlatformImpl to be nullable or make it possible to check
// and fix IRef<T> in general (right now Item is not nullable while it internally is)
if (PlatformImpl.Item == null!)
if (!PlatformImpl.IsAlive)
return null;
return PlatformImpl;
}

17
src/Avalonia.Base/Metadata/ConstructorArgumentAttribute.cs

@ -0,0 +1,17 @@
using System;
namespace Avalonia.Metadata;
/// <summary>
/// Indicates that a property corresponds to a named parameter in the constructor.
/// </summary>
/// <param name="name">The name of the parameter in the constructor.</param>
/// <remarks>This attribute is used for XAML.</remarks>
[AttributeUsage(AttributeTargets.Property)]
public sealed class ConstructorArgumentAttribute(string name) : Attribute
{
/// <summary>
/// Gets the name of the parameter in the constructor.
/// </summary>
public string Name { get; } = name;
}

6
src/Avalonia.Base/Platform/ISurfaceOrientation.cs

@ -0,0 +1,6 @@
namespace Avalonia.Platform;
internal interface ISurfaceOrientation
{
SurfaceOrientation Orientation { get; }
}

9
src/Avalonia.Base/Platform/SurfaceOrientation.cs

@ -0,0 +1,9 @@
namespace Avalonia.Platform;
public enum SurfaceOrientation
{
Rotation0,
Rotation90,
Rotation180,
Rotation270,
}

39
src/Avalonia.Base/StyledElement.cs

@ -29,7 +29,7 @@ namespace Avalonia
IDataContextProvider,
ILogical,
IThemeVariantHost,
IResourceHost2,
IResourceHost,
IStyleHost,
ISetLogicalParent,
ISetInheritanceParent,
@ -94,8 +94,7 @@ namespace Avalonia
private AvaloniaObject? _templatedParent;
private bool _dataContextUpdating;
private ControlTheme? _implicitTheme;
private EventHandler<ResourcesChangedToken>? _resourcesChanged2;
private ResourcesChangedToken _lastResourcesChangedToken;
private ResourcesChangedEventArgs _lastResourcesChangedEventArgs;
/// <summary>
/// Initializes static members of the <see cref="StyledElement"/> class.
@ -150,12 +149,6 @@ namespace Avalonia
/// </summary>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;
event EventHandler<ResourcesChangedToken>? IResourceHost2.ResourcesChanged2
{
add => _resourcesChanged2 += value;
remove => _resourcesChanged2 -= value;
}
/// <inheritdoc />
public event EventHandler? ActualThemeVariantChanged;
@ -437,14 +430,11 @@ namespace Avalonia
/// <inheritdoc/>
void ILogical.NotifyResourcesChanged(ResourcesChangedEventArgs e)
=> NotifyResourcesChanged(ResourcesChangedToken.Create());
=> NotifyResourcesChanged(e);
/// <inheritdoc/>
void IResourceHost.NotifyHostedResourcesChanged(ResourcesChangedEventArgs e)
=> NotifyResourcesChanged(ResourcesChangedToken.Create());
void IResourceHost2.NotifyHostedResourcesChanged(ResourcesChangedToken token)
=> NotifyResourcesChanged(token);
=> NotifyResourcesChanged(e);
/// <inheritdoc/>
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
@ -499,7 +489,7 @@ namespace Avalonia
// non-rooted control beacuse it's unlikely that dynamic resources need to be
// correct until the control is added to the tree, and it causes a *lot* of
// notifications.
NotifyResourcesChanged(ResourcesChangedToken.Create());
NotifyResourcesChanged(ResourcesChangedEventArgs.Create());
}
RaisePropertyChanged(ParentProperty, old, Parent);
@ -552,8 +542,8 @@ namespace Avalonia
/// <summary>
/// Notifies child controls that a change has been made to resources that apply to them.
/// </summary>
/// <param name="token">The change token.</param>
internal virtual void NotifyChildResourcesChanged(ResourcesChangedToken token)
/// <param name="e">The change token.</param>
internal virtual void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
if (_logicalChildren is object)
{
@ -563,7 +553,7 @@ namespace Avalonia
{
for (var i = 0; i < count; ++i)
{
_logicalChildren[i].NotifyResourcesChanged(token);
_logicalChildren[i].NotifyResourcesChanged(e);
}
}
}
@ -895,7 +885,7 @@ namespace Avalonia
ReevaluateImplicitTheme();
ApplyStyling();
NotifyResourcesChanged(ResourcesChangedToken.Create(), propagate: false);
NotifyResourcesChanged(ResourcesChangedEventArgs.Create(), propagate: false);
OnAttachedToLogicalTree(e);
AttachedToLogicalTree?.Invoke(this, e);
@ -999,23 +989,22 @@ namespace Avalonia
}
internal void NotifyResourcesChanged(
ResourcesChangedToken token,
ResourcesChangedEventArgs e,
bool propagate = true)
{
// We already got a notification for this element, ignore.
if (token.Equals(_lastResourcesChangedToken))
if (e.Equals(_lastResourcesChangedEventArgs))
{
return;
}
_lastResourcesChangedToken = token;
_lastResourcesChangedEventArgs = e;
_resourcesChanged2?.Invoke(this, token);
ResourcesChanged?.Invoke(this, ResourcesChangedEventArgs.Empty);
ResourcesChanged?.Invoke(this, e);
if (propagate)
{
NotifyChildResourcesChanged(token);
NotifyChildResourcesChanged(e);
}
}

2
src/Avalonia.Base/Styling/StyleBase.cs

@ -54,7 +54,7 @@ namespace Avalonia.Styling
if (hadResources || _resources.HasResources)
{
Owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create());
Owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}
}

6
src/Avalonia.Base/Utilities/Ref.cs

@ -28,6 +28,10 @@ namespace Avalonia.Utilities
/// <returns>A reference to the value as the new type but sharing the refcount.</returns>
IRef<TResult> CloneAs<TResult>() where TResult : class;
/// <summary>
/// Gets whether the reference still tracks a valid item.
/// </summary>
bool IsAlive { get; }
/// <summary>
/// The current refcount of the object tracked in this reference. For debugging/unit test use only.
@ -172,6 +176,8 @@ namespace Avalonia.Utilities
return new Ref<TResult>(item, counter);
}
public bool IsAlive => _item is not null;
public int RefCount => _counter?.RefCount ?? throw new ObjectDisposedException("Ref<" + typeof(T) + ">");
}
}

16
src/Avalonia.Controls/Application.cs

@ -30,7 +30,7 @@ namespace Avalonia
/// method.
/// - Tracks the lifetime of the application.
/// </remarks>
public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IResourceHost2, IApplicationPlatformEvents, IOptionalFeatureProvider
public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IResourceHost, IApplicationPlatformEvents, IOptionalFeatureProvider
{
/// <summary>
/// The application-global data templates.
@ -43,7 +43,6 @@ namespace Avalonia
private Action<IReadOnlyList<IStyle>>? _stylesRemoved;
private IApplicationLifetime? _applicationLifetime;
private bool _setupCompleted;
private EventHandler<ResourcesChangedToken>? _resourcesChanged2;
/// <summary>
/// Defines the <see cref="DataContext"/> property.
@ -62,12 +61,6 @@ namespace Avalonia
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;
event EventHandler<ResourcesChangedToken>? IResourceHost2.ResourcesChanged2
{
add => _resourcesChanged2 += value;
remove => _resourcesChanged2 -= value;
}
[Obsolete("Use Application.Current.TryGetFeature<IActivatableLifetime>() instead.")]
public event EventHandler<UrlOpenedEventArgs>? UrlsOpened;
@ -239,16 +232,9 @@ namespace Avalonia
void IResourceHost.NotifyHostedResourcesChanged(ResourcesChangedEventArgs e)
{
_resourcesChanged2?.Invoke(this, ResourcesChangedToken.Create());
ResourcesChanged?.Invoke(this, e);
}
void IResourceHost2.NotifyHostedResourcesChanged(ResourcesChangedToken token)
{
_resourcesChanged2?.Invoke(this, token);
ResourcesChanged?.Invoke(this, ResourcesChangedEventArgs.Empty);
}
void IStyleHost.StylesAdded(IReadOnlyList<IStyle> styles)
{
_stylesAdded?.Invoke(styles);

26
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs

@ -212,6 +212,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<object?> InnerRightContentProperty =
TextBox.InnerRightContentProperty.AddOwner<AutoCompleteBox>();
/// <summary>
/// Defines the <see cref="ValueMemberBinding" /> property.
/// </summary>
public static readonly StyledProperty<BindingBase?> ValueMemberBindingProperty =
AvaloniaProperty.Register<AutoCompleteBox, BindingBase?>(nameof(ValueMemberBinding));
/// <summary>
/// Gets or sets the caret index
/// </summary>
@ -332,26 +338,16 @@ namespace Avalonia.Controls
}
/// <summary>
/// Gets or sets the <see cref="T:Avalonia.Data.Binding" /> that
/// is used to get the values for display in the text portion of
/// the <see cref="AutoCompleteBox" />
/// control.
/// Gets or sets the <see cref="BindingBase" /> that is used to get the values for display in the text portion
/// of the <see cref="AutoCompleteBox" /> control.
/// </summary>
/// <value>The <see cref="T:Avalonia.Data.IBinding" /> object used
/// when binding to a collection property.</value>
/// <value>The <see cref="T:Avalonia.Data.BindingBase" /> object used when binding to a collection property.</value>
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public BindingBase? ValueMemberBinding
{
get => _valueBindingEvaluator?.ValueBinding;
set
{
if (ValueMemberBinding != value)
{
_valueBindingEvaluator = new BindingEvaluator<string>(value);
OnValueMemberBindingChanged(value);
}
}
get => GetValue(ValueMemberBindingProperty);
set => SetValue(ValueMemberBindingProperty, value);
}
/// <summary>

153
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -189,7 +189,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control that can provide updated string values from a binding.
/// </summary>
private BindingEvaluator<string>? _valueBindingEvaluator;
private BindingEvaluator<string?>? _valueMemberBindingEvaluator;
/// <summary>
/// A weak subscription for the collection changed event.
@ -439,6 +439,7 @@ namespace Avalonia.Controls
if (!_settingItemTemplateFromValueMemberBinding)
_itemTemplateIsFromValueMemberBinding = false;
}
private void OnValueMemberBindingChanged(BindingBase? value)
{
if (_itemTemplateIsFromValueMemberBinding)
@ -460,6 +461,16 @@ namespace Avalonia.Controls
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ValueMemberBindingProperty)
{
OnValueMemberBindingChanged(change.GetNewValue<BindingBase?>());
}
}
static AutoCompleteBox()
{
FocusableProperty.OverrideDefaultValue<AutoCompleteBox>(true);
@ -1181,25 +1192,6 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Formats an Item for text comparisons based on Converter
/// and ConverterCulture properties.
/// </summary>
/// <param name="value">The object to format.</param>
/// <param name="clearDataContext">A value indicating whether to clear
/// the data context after the lookup is performed.</param>
/// <returns>Formatted Value.</returns>
private string? FormatValue(object? value, bool clearDataContext)
{
string? result = FormatValue(value);
if (clearDataContext && _valueBindingEvaluator != null)
{
_valueBindingEvaluator.ClearDataContext();
}
return result;
}
/// <summary>
/// Converts the specified object to a string by using the
/// <see cref="P:Avalonia.Data.Binding.Converter" /> and
@ -1215,9 +1207,13 @@ namespace Avalonia.Controls
/// </remarks>
protected virtual string? FormatValue(object? value)
{
if (_valueBindingEvaluator != null)
if (ValueMemberBinding is { } valueMemberBinding)
{
return _valueBindingEvaluator.GetDynamicValue(value) ?? String.Empty;
_valueMemberBindingEvaluator ??= new();
_valueMemberBindingEvaluator.UpdateBinding(valueMemberBinding);
var result = _valueMemberBindingEvaluator.Evaluate(value) ?? string.Empty;
_valueMemberBindingEvaluator.ClearDataContext();
return result;
}
return value == null ? String.Empty : value.ToString();
@ -1451,9 +1447,6 @@ namespace Avalonia.Controls
_view?.Clear();
_view?.AddRange(_newViewItems);
// Clear the evaluator to discard a reference to the last item
_valueBindingEvaluator?.ClearDataContext();
}
finally
{
@ -1638,7 +1631,7 @@ namespace Avalonia.Controls
if (top != null)
{
newSelectedItem = top;
string? topString = FormatValue(top, true);
string? topString = FormatValue(top);
// Only replace partially when the two words being the same
int minLength = Math.Min(topString?.Length ?? 0, Text?.Length ?? 0);
@ -1744,7 +1737,7 @@ namespace Avalonia.Controls
}
else if (TextSelector != null)
{
text = TextSelector(SearchText, FormatValue(newItem, true));
text = TextSelector(SearchText, FormatValue(newItem));
}
else if (ItemSelector != null)
{
@ -1752,7 +1745,7 @@ namespace Avalonia.Controls
}
else
{
text = FormatValue(newItem, true);
text = FormatValue(newItem);
}
// Update the Text property and the TextBox values
@ -2020,109 +2013,5 @@ namespace Avalonia.Controls
return string.Equals(value, text, StringComparison.Ordinal);
}
}
// TODO12: Remove, this shouldn't be part of the public API. Use our internal BindingEvaluator instead.
/// <summary>
/// A framework element that permits a binding to be evaluated in a new data
/// context leaf node.
/// </summary>
/// <typeparam name="T">The type of dynamic binding to return.</typeparam>
public class BindingEvaluator<T> : Control
{
/// <summary>
/// Gets or sets the string value binding used by the control.
/// </summary>
private BindingBase? _binding;
/// <summary>
/// Identifies the Value dependency property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002:AvaloniaProperty objects should not be owned by a generic type",
Justification = "This property is not supposed to be used from XAML.")]
public static readonly StyledProperty<T> ValueProperty =
AvaloniaProperty.Register<BindingEvaluator<T>, T>(nameof(Value));
/// <summary>
/// Gets or sets the data item value.
/// </summary>
public T Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
/// <summary>
/// Gets or sets the value binding.
/// </summary>
public BindingBase? ValueBinding
{
get => _binding;
set
{
_binding = value;
if (value is not null)
Bind(ValueProperty, value);
}
}
/// <summary>
/// Initializes a new instance of the BindingEvaluator class.
/// </summary>
public BindingEvaluator()
{ }
/// <summary>
/// Initializes a new instance of the BindingEvaluator class,
/// setting the initial binding to the provided parameter.
/// </summary>
/// <param name="binding">The initial string value binding.</param>
public BindingEvaluator(BindingBase? binding)
: this()
{
ValueBinding = binding;
}
/// <summary>
/// Clears the data context so that the control does not keep a
/// reference to the last-looked up item.
/// </summary>
public void ClearDataContext()
{
DataContext = null;
}
/// <summary>
/// Updates the data context of the framework element and returns the
/// updated binding value.
/// </summary>
/// <param name="o">The object to use as the data context.</param>
/// <param name="clearDataContext">If set to true, this parameter will
/// clear the data context immediately after retrieving the value.</param>
/// <returns>Returns the evaluated T value of the bound dependency
/// property.</returns>
public T GetDynamicValue(object o, bool clearDataContext)
{
DataContext = o;
T value = Value;
if (clearDataContext)
{
DataContext = null;
}
return value;
}
/// <summary>
/// Updates the data context of the framework element and returns the
/// updated binding value.
/// </summary>
/// <param name="o">The object to use as the data context.</param>
/// <returns>Returns the evaluated T value of the bound dependency
/// property.</returns>
public T GetDynamicValue(object? o)
{
DataContext = o;
return Value;
}
}
}
}

27
src/Avalonia.Controls/NativeMenuBar.cs

@ -3,8 +3,6 @@ using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using Avalonia.Reactive;
using Avalonia.VisualTree;
@ -13,25 +11,11 @@ namespace Avalonia.Controls
[TemplatePart("PART_NativeMenuPresenter", typeof(MenuBase))]
public class NativeMenuBar : TemplatedControl
{
[Unstable("To be removed in 12.0, NativeMenuBar now has a default template")] // TODO12
public static readonly AttachedProperty<bool> EnableMenuItemClickForwardingProperty =
AvaloniaProperty.RegisterAttached<NativeMenuBar, MenuItem, bool>(
"EnableMenuItemClickForwarding");
private MenuBase? _menu;
private IDisposable? _subscriptions;
static NativeMenuBar()
{
EnableMenuItemClickForwardingProperty.Changed.Subscribe(args =>
{
var item = (MenuItem)args.Sender;
if (args.NewValue.GetValueOrDefault<bool>())
item.Click += OnMenuItemClick;
else
item.Click -= OnMenuItemClick;
});
// TODO12 Ideally we should make NativeMenuBar inherit MenuBase directly, but it would be a breaking change for 11.x.
// Changing default template while keeping old StyleKeyOverride => Menu isn't a breaking change.
TemplateProperty.OverrideDefaultValue<NativeMenuBar>(new FuncControlTemplate((_, ns) => new NativeMenuBarPresenter
@ -77,17 +61,6 @@ namespace Avalonia.Controls
_subscriptions = null;
}
[Unstable("To be removed in 12.0, NativeMenuBar now has a default template.")] // TODO12
public static void SetEnableMenuItemClickForwarding(MenuItem menuItem, bool enable)
{
menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable);
}
private static void OnMenuItemClick(object? sender, RoutedEventArgs e)
{
(((MenuItem)sender!).DataContext as INativeMenuItemExporterEventsImplBridge)?.RaiseClicked();
}
private void SubscribeToToplevel(TopLevel topLevel, MenuBase menu)
{
_subscriptions?.Dispose();

4
src/Avalonia.Controls/NativeMenuBarPresenter.cs

@ -32,9 +32,7 @@ internal class NativeMenuBarPresenter : Menu
[!MenuItem.CommandParameterProperty] =
nativeItem.GetObservable(NativeMenuItem.CommandParameterProperty).ToBinding(),
[!MenuItem.InputGestureProperty] = nativeItem.GetObservable(NativeMenuItem.GestureProperty).ToBinding(),
[!MenuItem.ToggleTypeProperty] = nativeItem.GetObservable(NativeMenuItem.ToggleTypeProperty)
// TODO12 remove NativeMenuItemToggleType
.Select(v => (MenuItemToggleType)v).ToBinding(),
[!MenuItem.ToggleTypeProperty] = nativeItem.GetObservable(NativeMenuItem.ToggleTypeProperty).ToBinding(),
[!ToolTip.TipProperty] =
nativeItem.GetObservable(NativeMenuItem.ToolTipProperty).ToBinding(),
};

14
src/Avalonia.Controls/NativeMenuItem.cs

@ -119,11 +119,11 @@ namespace Avalonia.Controls
}
/// <inheritdoc cref="MenuItem.ToggleTypeProperty"/>
public static readonly StyledProperty<NativeMenuItemToggleType> ToggleTypeProperty =
AvaloniaProperty.Register<NativeMenuItem, NativeMenuItemToggleType>(nameof(ToggleType));
public static readonly StyledProperty<MenuItemToggleType> ToggleTypeProperty =
AvaloniaProperty.Register<NativeMenuItem, MenuItemToggleType>(nameof(ToggleType));
/// <inheritdoc cref="MenuItem.ToggleType"/>
public NativeMenuItemToggleType ToggleType
public MenuItemToggleType ToggleType
{
get => GetValue(ToggleTypeProperty);
set => SetValue(ToggleTypeProperty, value);
@ -232,12 +232,4 @@ namespace Avalonia.Controls
}
}
}
// TODO12: remove this enum and use MenuItemToggleType only
public enum NativeMenuItemToggleType
{
None = MenuItemToggleType.None,
CheckBox = MenuItemToggleType.CheckBox,
Radio = MenuItemToggleType.Radio
}
}

5
src/Avalonia.Controls/Primitives/IPopupHost.cs

@ -1,11 +1,9 @@
using System;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Diagnostics;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
{
@ -17,8 +15,7 @@ namespace Avalonia.Controls.Primitives
/// (<see cref="PopupRoot"/>) or an <see cref="OverlayPopupHost"/> which is created
/// on an <see cref="OverlayLayer"/>.
/// </remarks>
[NotClientImplementable]
[Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)]
[PrivateApi]
public interface IPopupHost : IDisposable, IFocusScope
{
/// <summary>

18
src/Avalonia.Controls/Primitives/OverlayPopupHost.cs

@ -121,16 +121,6 @@ namespace Avalonia.Controls.Primitives
// Nothing to do here: overlay popups are implemented inside the window.
}
[Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)]
public void ConfigurePosition(Visual target, PlacementMode placement, Point offset,
PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null)
{
((IPopupHost)this).ConfigurePosition(new PopupPositionRequest(target, placement, offset, anchor, gravity,
constraintAdjustment, rect, null));
}
/// <inheritdoc />
void IPopupHost.ConfigurePosition(PopupPositionRequest positionRequest)
{
@ -191,12 +181,8 @@ namespace Avalonia.Controls.Primitives
double IManagedPopupPositionerPopup.Scaling => 1;
// TODO12: mark PrivateAPI or internal.
[Unstable("PopupHost is considered an internal API. Use Popup or any Popup-based controls (Flyout, Tooltip) instead.")]
public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver)
=> CreatePopupHost(target, dependencyResolver, false);
internal static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver, bool shouldUseOverlayLayer)
[PrivateApi]
public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver, bool shouldUseOverlayLayer)
{
if (!shouldUseOverlayLayer)
{

1
src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs

@ -66,7 +66,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
/// requirement that a popup must intersect with or be at least partially adjacent to its parent
/// surface.
/// </remarks>
[Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)]
public record struct PopupPositionerParameters
{
private PopupGravity _gravity;

1
src/Avalonia.Controls/Primitives/PopupPositioning/PopupPositionRequest.cs

@ -4,7 +4,6 @@ using Avalonia.Metadata;
namespace Avalonia.Controls.Primitives.PopupPositioning;
[PrivateApi]
[Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)]
public class PopupPositionRequest
{
internal PopupPositionRequest(Visual target, PlacementMode placement)

11
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -136,17 +136,6 @@ namespace Avalonia.Controls.Primitives
}
}
[Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)]
public void ConfigurePosition(Visual target, PlacementMode placement, Point offset,
PopupAnchor anchor = PopupAnchor.None,
PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null)
{
((IPopupHost)this).ConfigurePosition(new PopupPositionRequest(target, placement, offset, anchor, gravity,
constraintAdjustment, rect, null));
}
void IPopupHost.ConfigurePosition(PopupPositionRequest request)
{
_popupPositionRequest = request;

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

@ -362,7 +362,7 @@ namespace Avalonia.Controls.Primitives
}
/// <inheritdoc />
internal sealed override void NotifyChildResourcesChanged(ResourcesChangedToken token)
internal sealed override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
var count = VisualChildren.Count;
@ -370,11 +370,11 @@ namespace Avalonia.Controls.Primitives
{
if (VisualChildren[i] is ILogical logical)
{
logical.NotifyResourcesChanged(token);
logical.NotifyResourcesChanged(e);
}
}
base.NotifyChildResourcesChanged(token);
base.NotifyChildResourcesChanged(e);
}
/// <inheritdoc/>

6
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -118,12 +118,12 @@ namespace Avalonia.Controls.Primitives
}
/// <inheritdoc />
internal override void NotifyChildResourcesChanged(ResourcesChangedToken token)
internal override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
foreach (var l in _layers)
l.NotifyResourcesChanged(token);
l.NotifyResourcesChanged(e);
base.NotifyChildResourcesChanged(token);
base.NotifyChildResourcesChanged(e);
}
/// <inheritdoc />

23
src/Avalonia.Controls/TopLevel.cs

@ -121,12 +121,6 @@ namespace Avalonia.Controls
(s, h) => s.ResourcesChanged -= h
);
private static readonly WeakEvent<IResourceHost2, ResourcesChangedToken>
ResourcesChanged2WeakEvent = WeakEvent.Register<IResourceHost2, ResourcesChangedToken>(
(s, h) => s.ResourcesChanged2 += h,
(s, h) => s.ResourcesChanged2 -= h
);
private readonly IInputManager? _inputManager;
private readonly IToolTipService? _tooltipService;
private readonly IAccessKeyHandler? _accessKeyHandler;
@ -144,7 +138,6 @@ namespace Avalonia.Controls
private ILayoutManager? _layoutManager;
private Border? _transparencyFallbackBorder;
private TargetWeakEventSubscriber<TopLevel, ResourcesChangedEventArgs>? _resourcesChangesSubscriber;
private TargetWeakEventSubscriber<TopLevel, ResourcesChangedToken>? _resourcesChangesSubscriber2;
private IStorageProvider? _storageProvider;
private Screens? _screens;
private LayoutDiagnosticBridge? _layoutDiagnosticBridge;
@ -270,25 +263,15 @@ namespace Avalonia.Controls
var stylingParent = ((IStyleHost)this).StylingParent;
if (stylingParent is IResourceHost2 applicationResources2)
if (stylingParent is IResourceHost applicationResources2)
{
_resourcesChangesSubscriber2 = new TargetWeakEventSubscriber<TopLevel, ResourcesChangedToken>(
_resourcesChangesSubscriber = new TargetWeakEventSubscriber<TopLevel, ResourcesChangedEventArgs>(
this, static (target, _, _, token) =>
{
target.NotifyResourcesChanged(token);
});
ResourcesChanged2WeakEvent.Subscribe(applicationResources2, _resourcesChangesSubscriber2);
}
else if (stylingParent is IResourceHost applicationResources)
{
_resourcesChangesSubscriber = new TargetWeakEventSubscriber<TopLevel, ResourcesChangedEventArgs>(
this, static (target, _, _, _) =>
{
target.NotifyResourcesChanged(ResourcesChangedToken.Create());
});
ResourcesChangedWeakEvent.Subscribe(applicationResources, _resourcesChangesSubscriber);
ResourcesChangedWeakEvent.Subscribe(applicationResources2, _resourcesChangesSubscriber);
}
impl.LostFocus += PlatformImpl_LostFocus;

6
src/Avalonia.FreeDesktop/DBusMenuExporter.cs

@ -260,13 +260,13 @@ namespace Avalonia.FreeDesktop
if (name == "toggle-type")
{
if (item.ToggleType == NativeMenuItemToggleType.CheckBox)
if (item.ToggleType == MenuItemToggleType.CheckBox)
return VariantValue.String("checkmark");
if (item.ToggleType == NativeMenuItemToggleType.Radio)
if (item.ToggleType == MenuItemToggleType.Radio)
return VariantValue.String("radio");
}
if (name == "toggle-state" && item.ToggleType != NativeMenuItemToggleType.None)
if (name == "toggle-state" && item.ToggleType != MenuItemToggleType.None)
return VariantValue.Int32(item.IsChecked ? 1 : 0);
if (name == "icon-data")

2
src/Avalonia.Native/IAvnMenuItem.cs

@ -43,7 +43,7 @@ namespace Avalonia.Native.Interop.Impl
private void UpdateIsVisible(bool isVisible) => SetIsVisible(isVisible.AsComBool());
private void UpdateIsChecked(bool isChecked) => SetIsChecked(isChecked.AsComBool());
private void UpdateToggleType(NativeMenuItemToggleType toggleType)
private void UpdateToggleType(MenuItemToggleType toggleType)
{
SetToggleType((AvnMenuItemToggleType)toggleType);
}

16
src/Avalonia.Native/TopLevelImpl.cs

@ -65,8 +65,8 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
private NativeControlHostImpl? _nativeControlHost;
private PlatformBehaviorInhibition? _platformBehaviorInhibition;
private readonly MouseDevice? _mouse;
private readonly PenDevice? _pen;
private readonly MouseDevice _mouse;
private readonly PenDevice _pen;
private readonly IKeyboardDevice? _keyboard;
private readonly ICursorFactory? _cursorFactory;
@ -480,6 +480,18 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
void IAvnTopLevelEvents.LostFocus()
{
_parent.LostFocus?.Invoke();
// macOS doesn't have the concept of mouse capture. If we're losing the focus during an implicit capture
// (standard mouse down), we should release it to avoid mouse events going to an old window.
var mouse = _parent._mouse;
var captured = mouse.Pointer.Captured;
if (captured is not null &&
mouse.Pointer.CaptureSource == CaptureSource.Implicit &&
TopLevel.GetTopLevel(captured as Visual)?.PlatformImpl == _parent)
{
mouse.PlatformCaptureLost();
}
}
AvnDragDropEffects IAvnTopLevelEvents.DragEvent(AvnDragEventType type, AvnPoint position,

2
src/Avalonia.OpenGL/GlConsts.cs

@ -20,7 +20,7 @@ namespace Avalonia.OpenGL
// public const int GL_LINE_STRIP = 0x0003;
public const int GL_TRIANGLES = 0x0004;
// public const int GL_TRIANGLE_STRIP = 0x0005;
// public const int GL_TRIANGLE_FAN = 0x0006;
public const int GL_TRIANGLE_FAN = 0x0006;
// public const int GL_QUADS = 0x0007;
// public const int GL_QUAD_STRIP = 0x0008;
// public const int GL_POLYGON = 0x0009;

2
src/Avalonia.OpenGL/GlInterface.cs

@ -343,6 +343,8 @@ namespace Avalonia.OpenGL
[GetProcAddress("glUniform1f")]
public partial void Uniform1f(int location, float falue);
[GetProcAddress("glUniform1i")]
public partial void Uniform1i(int location, int value);
[GetProcAddress("glUniformMatrix4fv")]
public partial void UniformMatrix4fv(int location, int count, bool transpose, void* value);

2
src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs

@ -154,6 +154,6 @@ internal sealed class SystemAccentColors : ResourceProvider
private void PlatformSettingsOnColorValuesChanged(object? sender, PlatformColorValues e)
{
_invalidateColors = true;
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}

2
src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs

@ -63,7 +63,7 @@ namespace Avalonia.Themes.Fluent
if (change.Property == DensityStyleProperty)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create());
}
}

9
src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs

@ -1,4 +1,5 @@
using Avalonia.Media;
using Avalonia.Platform;
namespace Avalonia.LinuxFramebuffer
{
@ -12,7 +13,13 @@ namespace Avalonia.LinuxFramebuffer
/// Default: 1.0
/// </summary>
public double Scaling { get; set; } = 1.0;
/// <summary>
/// The orientation of the screen relative to the frame buffer memory orientation
/// Default: Normal
/// </summary>
public SurfaceOrientation Orientation { get; set; } = SurfaceOrientation.Rotation0;
/// <summary>
/// If true an two cycle buffer swapping is processed at init.
/// Default: True

4
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@ -11,7 +11,7 @@ using Avalonia.Rendering.Composition;
namespace Avalonia.LinuxFramebuffer
{
class FramebufferToplevelImpl : ITopLevelImpl, IScreenInfoProvider
class FramebufferToplevelImpl : ITopLevelImpl, IScreenInfoProvider, ISurfaceOrientation
{
private readonly IOutputBackend _outputBackend;
private readonly IInputBackend _inputBackend;
@ -81,5 +81,7 @@ using Avalonia.Rendering.Composition;
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object? TryGetFeature(Type featureType) => null;
SurfaceOrientation ISurfaceOrientation.Orientation => _outputBackend is ISurfaceOrientation surfaceOrientation ? surfaceOrientation.Orientation : SurfaceOrientation.Rotation0;
}
}

19
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs

@ -1,8 +1,10 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
namespace Avalonia.LinuxFramebuffer.Input.LibInput
{
@ -30,9 +32,22 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
private unsafe void InputThread(IntPtr ctx, LibInputBackendOptions options)
{
var fd = libinput_get_fd(ctx);
IntPtr[] devices = [.. options.Events!.Select(f => libinput_path_add_device(ctx, f)).Where(d => d != IntPtr.Zero)];
var screenOrientation = _screen is ISurfaceOrientation surfaceOrientation ? surfaceOrientation.Orientation : SurfaceOrientation.Rotation0;
float[] matrix = screenOrientation switch
{
SurfaceOrientation.Rotation90 => [0, 1, 0, -1, 0, 1],
SurfaceOrientation.Rotation180 => [-1, 0, 1, 0, -1, 1],
SurfaceOrientation.Rotation270 => [0, -1, 1, 1, 0, 0],
_ => [1, 0, 0, 0, 1, 0], // Normal
};
foreach (var device in devices)
{
libinput_device_config_calibration_set_matrix(device, matrix);
}
foreach (var f in options.Events!)
libinput_path_add_device(ctx, f);
while (true)
{
IntPtr ev;

3
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs

@ -55,6 +55,9 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
[DllImport(LibInput)]
public extern static IntPtr libinput_path_remove_device(IntPtr device);
[DllImport(LibInput)]
public extern static int libinput_device_config_calibration_set_matrix(IntPtr device, float[] matrix);
[DllImport(LibInput)]
public extern static int libinput_get_fd(IntPtr ctx);

5
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -142,7 +142,10 @@ namespace Avalonia.LinuxFramebuffer
{
get
{
EnsureTopLevel();
if (_topLevel == null)
{
EnsureTopLevel();
}
return _topLevel;
}
}

196
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@ -13,11 +13,13 @@ using static Avalonia.LinuxFramebuffer.Output.LibDrm;
namespace Avalonia.LinuxFramebuffer.Output
{
public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface
public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface, ISurfaceOrientation
{
private DrmOutputOptions _outputOptions = new();
private DrmCard _card;
public PixelSize PixelSize => _mode.Resolution;
public PixelSize PixelSize => Orientation == SurfaceOrientation.Rotation0 || Orientation == SurfaceOrientation.Rotation180
? new PixelSize(_mode.Resolution.Width, _mode.Resolution.Height)
: new PixelSize(_mode.Resolution.Height, _mode.Resolution.Width);
public double Scaling
{
@ -25,6 +27,12 @@ namespace Avalonia.LinuxFramebuffer.Output
set => _outputOptions.Scaling = value;
}
public SurfaceOrientation Orientation
{
get => _outputOptions.Orientation;
set => _outputOptions.Orientation = value;
}
class SharedContextGraphics : IPlatformGraphics
{
private readonly IPlatformGraphicsContext _context;
@ -113,6 +121,12 @@ namespace Avalonia.LinuxFramebuffer.Output
private IntPtr _currentBo;
private IntPtr _gbmTargetSurface;
private uint _crtcId;
private int _rotationFbo;
private int _rotationTexture;
private PixelSize _rotatedSize;
private int _rotationProgram;
private int _rotationVbo;
private int _rotationVao;
void FbDestroyCallback(IntPtr bo, IntPtr userData)
{
@ -157,7 +171,6 @@ namespace Avalonia.LinuxFramebuffer.Output
return fbHandle;
}
[MemberNotNull(nameof(_card))]
[MemberNotNull(nameof(PlatformGraphics))]
[MemberNotNull(nameof(FbDestroyDelegate))]
@ -236,6 +249,129 @@ namespace Avalonia.LinuxFramebuffer.Output
_mode = mode;
_currentBo = bo;
// Initialize FBO for rotation if needed
var needsRotation = _outputOptions.Orientation != SurfaceOrientation.Rotation0;
if (needsRotation)
{
// For 90/270 rotation, swap width and height
_rotatedSize = (_outputOptions.Orientation == SurfaceOrientation.Rotation90 ||
_outputOptions.Orientation == SurfaceOrientation.Rotation270)
? new PixelSize(modeInfo.Resolution.Height, modeInfo.Resolution.Width)
: modeInfo.Resolution;
using (_deferredContext.MakeCurrent(_eglSurface))
{
var gl = _deferredContext.GlInterface;
_rotationFbo = gl.GenFramebuffer();
_rotationTexture = gl.GenTexture();
gl.BindTexture(GlConsts.GL_TEXTURE_2D, _rotationTexture);
gl.TexImage2D(GlConsts.GL_TEXTURE_2D, 0, GlConsts.GL_RGBA, _rotatedSize.Width, _rotatedSize.Height, 0,
GlConsts.GL_RGBA, GlConsts.GL_UNSIGNED_BYTE, IntPtr.Zero);
gl.TexParameteri(GlConsts.GL_TEXTURE_2D, GlConsts.GL_TEXTURE_MIN_FILTER, GlConsts.GL_LINEAR);
gl.TexParameteri(GlConsts.GL_TEXTURE_2D, GlConsts.GL_TEXTURE_MAG_FILTER, GlConsts.GL_LINEAR);
gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, _rotationFbo);
gl.FramebufferTexture2D(GlConsts.GL_FRAMEBUFFER, GlConsts.GL_COLOR_ATTACHMENT0,
GlConsts.GL_TEXTURE_2D, _rotationTexture, 0);
gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
// Create shader program for textured quad
const string vertexShader = @"
attribute vec2 aPos;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
gl_Position = vec4(aPos, 0.0, 1.0);
vTexCoord = aTexCoord;
}";
const string fragmentShader = @"
precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D uTexture;
void main() {
gl_FragColor = texture2D(uTexture, vTexCoord);
}";
var vs = gl.CreateShader(GlConsts.GL_VERTEX_SHADER);
gl.ShaderSourceString(vs, vertexShader);
gl.CompileShader(vs);
var fs = gl.CreateShader(GlConsts.GL_FRAGMENT_SHADER);
gl.ShaderSourceString(fs, fragmentShader);
gl.CompileShader(fs);
_rotationProgram = gl.CreateProgram();
gl.AttachShader(_rotationProgram, vs);
gl.AttachShader(_rotationProgram, fs);
gl.LinkProgram(_rotationProgram);
gl.DeleteShader(vs);
gl.DeleteShader(fs);
// Create VBO with quad vertices - texture coords depend on rotation
// Format: x, y, u, v
float[] vertices = _outputOptions.Orientation switch
{
SurfaceOrientation.Rotation90 => new float[] {
// 90° clockwise rotation
-1.0f, -1.0f, 1.0f, 0.0f, // Bottom-left -> Bottom-right of texture
1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right -> Top-right of texture
1.0f, 1.0f, 0.0f, 1.0f, // Top-right -> Top-left of texture
-1.0f, 1.0f, 0.0f, 0.0f // Top-left -> Bottom-left of texture
},
SurfaceOrientation.Rotation180 => new float[] {
// 180° rotation
-1.0f, -1.0f, 1.0f, 1.0f, // Bottom-left -> Top-right of texture
1.0f, -1.0f, 0.0f, 1.0f, // Bottom-right -> Top-left of texture
1.0f, 1.0f, 0.0f, 0.0f, // Top-right -> Bottom-left of texture
-1.0f, 1.0f, 1.0f, 0.0f // Top-left -> Bottom-right of texture
},
SurfaceOrientation.Rotation270 => new float[] {
// 270° clockwise (90° counter-clockwise) rotation
-1.0f, -1.0f, 0.0f, 1.0f, // Bottom-left -> Top-left of texture
1.0f, -1.0f, 0.0f, 0.0f, // Bottom-right -> Bottom-left of texture
1.0f, 1.0f, 1.0f, 0.0f, // Top-right -> Bottom-right of texture
-1.0f, 1.0f, 1.0f, 1.0f // Top-left -> Top-right of texture
},
_ => new float[] {
// No rotation (shouldn't reach here but fallback)
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f
}
};
_rotationVbo = gl.GenBuffer();
_rotationVao = gl.GenVertexArray();
gl.BindVertexArray(_rotationVao);
gl.BindBuffer(GlConsts.GL_ARRAY_BUFFER, _rotationVbo);
fixed (float* ptr = vertices)
{
gl.BufferData(GlConsts.GL_ARRAY_BUFFER, new IntPtr(vertices.Length * sizeof(float)),
new IntPtr(ptr), GlConsts.GL_STATIC_DRAW);
}
var posAttrib = gl.GetAttribLocationString(_rotationProgram, "aPos");
gl.EnableVertexAttribArray(posAttrib);
gl.VertexAttribPointer(posAttrib, 2, GlConsts.GL_FLOAT, 0, 4 * sizeof(float), IntPtr.Zero);
var texAttrib = gl.GetAttribLocationString(_rotationProgram, "aTexCoord");
gl.EnableVertexAttribArray(texAttrib);
gl.VertexAttribPointer(texAttrib, 2, GlConsts.GL_FLOAT, 0, 4 * sizeof(float), new IntPtr(2 * sizeof(float)));
gl.BindVertexArray(0);
}
}
else
{
// No rotation needed
_rotatedSize = modeInfo.Resolution;
}
if (_outputOptions.EnableInitialBufferSwapping)
{
@ -288,7 +424,39 @@ namespace Avalonia.LinuxFramebuffer.Output
public void Dispose()
{
_parent._deferredContext.GlInterface.Flush();
var gl = _parent._deferredContext.GlInterface;
if (_parent._outputOptions.Orientation != SurfaceOrientation.Rotation0)
{
// Rotation enabled - blit from FBO to screen
// Unbind FBO to render to default framebuffer
gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
gl.Viewport(0, 0, _parent._mode.Resolution.Width, _parent._mode.Resolution.Height);
// Clear the screen
gl.ClearColor(0, 0, 0, 1);
gl.Clear(GlConsts.GL_COLOR_BUFFER_BIT);
// Use the shader program
gl.UseProgram(_parent._rotationProgram);
// Bind the FBO texture
gl.ActiveTexture(GlConsts.GL_TEXTURE0);
gl.BindTexture(GlConsts.GL_TEXTURE_2D, _parent._rotationTexture);
// Set texture uniform (texture unit 0)
var texLoc = gl.GetUniformLocationString(_parent._rotationProgram, "uTexture");
gl.Uniform1i(texLoc, 0);
// Draw the rotated quad
gl.BindVertexArray(_parent._rotationVao);
gl.DrawArrays(GlConsts.GL_TRIANGLE_FAN, 0, 4);
gl.BindVertexArray(0);
gl.UseProgram(0);
}
gl.Flush();
_parent._eglSurface.SwapBuffers();
var nextBo = gbm_surface_lock_front_buffer(_parent._gbmTargetSurface);
@ -333,7 +501,7 @@ namespace Avalonia.LinuxFramebuffer.Output
public IGlContext Context => _parent._deferredContext;
public PixelSize Size => _parent._mode.Resolution;
public PixelSize Size => _parent._rotatedSize;
public double Scaling => _parent.Scaling;
@ -342,7 +510,23 @@ namespace Avalonia.LinuxFramebuffer.Output
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
return new RenderSession(_parent, _parent._deferredContext.MakeCurrent(_parent._eglSurface));
var clearContext = _parent._deferredContext.MakeCurrent(_parent._eglSurface);
var gl = _parent._deferredContext.GlInterface;
if (_parent._outputOptions.Orientation != SurfaceOrientation.Rotation0)
{
// Bind FBO for rendering when rotation is enabled
gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, _parent._rotationFbo);
gl.Viewport(0, 0, _parent._rotatedSize.Width, _parent._rotatedSize.Height);
}
else
{
// Render directly to screen when no rotation
gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
gl.Viewport(0, 0, _parent._mode.Resolution.Width, _parent._mode.Resolution.Height);
}
return new RenderSession(_parent, clearContext);
}
}

6
src/Markup/Avalonia.Markup.Xaml/Data/DynamicResourceExpression.cs

@ -84,8 +84,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e) => PublishValue();
private void ResourcesChanged2(object? sender, ResourcesChangedToken token) => PublishValue();
private void ActualThemeVariantChanged(object? sender, EventArgs e)
{
if (!IsRunning)
@ -134,7 +132,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
if (host is not null)
{
host.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2);
host.ResourcesChanged += ResourcesChanged;
if (!_overrideThemeVariant && _host is IThemeVariantHost themeVariantHost)
{
@ -148,7 +146,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
if (host is not null)
{
host.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2);
host.ResourcesChanged -= ResourcesChanged;
if (!_overrideThemeVariant && _host is IThemeVariantHost themeVariantHost)
themeVariantHost.ActualThemeVariantChanged -= ActualThemeVariantChanged;

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs

@ -3,6 +3,7 @@ using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Markup.Xaml.XamlIl.Runtime;
using Avalonia.Metadata;
using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.MarkupExtensions
@ -22,6 +23,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
ResourceKey = resourceKey;
}
[ConstructorArgument("resourceKey")]
public object? ResourceKey { get; set; }
public BindingBase ProvideValue(IServiceProvider serviceProvider)

7
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs

@ -22,13 +22,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
/// <param name="path">The binding path.</param>
public ReflectionBindingExtension(string path) : base(path) { }
/// <summary>
/// Initializes a new instance of the <see cref="ReflectionBinding"/> class.
/// </summary>
/// <param name="path">The binding path.</param>
/// <param name="mode">The binding mode.</param>
public ReflectionBindingExtension(string path, BindingMode mode) : base(path, mode) { }
public ReflectionBinding ProvideValue(IServiceProvider serviceProvider)
{
return new ReflectionBinding

1
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Data;
using Avalonia.Metadata;
namespace Avalonia.Markup.Xaml.MarkupExtensions
{

10
src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs

@ -32,14 +32,4 @@ namespace Avalonia.Markup.Xaml
[RequiresUnreferencedCode(TrimmingMessages.XamlTypeResolvedRequiresUnreferenceCodeMessage)]
Type Resolve (string qualifiedTypeName);
}
// TODO12: Move to Avalonia.Base
[AttributeUsage(AttributeTargets.Property)]
public sealed class ConstructorArgumentAttribute : Attribute
{
public ConstructorArgumentAttribute(string name)
{
}
}
}

2
src/Markup/Avalonia.Markup/Data/Binding.cs

@ -16,6 +16,4 @@ public class Binding : ReflectionBinding
public Binding() { }
public Binding(string path) : base(path) { }
public Binding(string path, BindingMode mode) : base(path, mode) { }
}

8
src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs

@ -125,6 +125,14 @@ namespace Avalonia.Skia
_currentFramebufferAddress = framebuffer.Address;
// A surface with a width/height of 0 is invalid and can't be created
if (desiredImageInfo.Width <= 0 || desiredImageInfo.Height <= 0)
{
throw new ArgumentException(
$"Unable to create a surface with size {desiredImageInfo.Width}x{desiredImageInfo.Height}",
nameof(desiredImageInfo));
}
var surface = SKSurface.Create(desiredImageInfo, _currentFramebufferAddress,
framebuffer.RowBytes, new SKSurfaceProperties(SKPixelGeometry.RgbHorizontal));

46
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

@ -1091,7 +1091,11 @@ namespace Avalonia.Base.UnitTests
var target = new Class1();
var source = new TestTwoWayBindingViewModel();
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source });
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value))
{
Mode = BindingMode.TwoWay,
Source = source
});
target.DoubleValue = 123.4;
@ -1105,7 +1109,11 @@ namespace Avalonia.Base.UnitTests
var target = new Class1();
var source = new TestTwoWayBindingViewModel();
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source });
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value))
{
Mode = BindingMode.TwoWay,
Source = source
});
Assert.False(source.SetterCalled);
}
@ -1116,7 +1124,11 @@ namespace Avalonia.Base.UnitTests
var target = new Class1();
var source = new TestTwoWayBindingViewModel();
target.Bind(Class1.DoubleValueProperty, new Binding("[0]", BindingMode.TwoWay) { Source = source });
target.Bind(Class1.DoubleValueProperty, new Binding("[0]")
{
Mode = BindingMode.TwoWay,
Source = source
});
Assert.False(source.SetterCalled);
}
@ -1127,7 +1139,7 @@ namespace Avalonia.Base.UnitTests
var target = new TextBlock();
target.DataContext = null;
target.Bind(TextBlock.TextProperty, new Binding("Missing", BindingMode.TwoWay));
target.Bind(TextBlock.TextProperty, new Binding("Missing") { Mode = BindingMode.TwoWay });
}
[Fact]
@ -1136,7 +1148,7 @@ namespace Avalonia.Base.UnitTests
var target = new TextBlock();
target.DataContext = null;
target.Bind(TextBlock.TextProperty, new Binding("[0]", BindingMode.TwoWay));
target.Bind(TextBlock.TextProperty, new Binding("[0]") { Mode = BindingMode.TwoWay });
}
[Theory(Skip = "Will need changes to binding internals in order to pass")]
@ -1147,7 +1159,11 @@ namespace Avalonia.Base.UnitTests
{
var target = new Class1();
var source = new TestTwoWayBindingViewModel();
var binding = new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source };
var binding = new Binding(nameof(source.Value))
{
Mode = BindingMode.TwoWay,
Source = source
};
target.Bind(Class1.DoubleValueProperty, binding, priority);
target.SetValue(Class1.DoubleValueProperty, 123.4, priority - 1);
@ -1165,7 +1181,11 @@ namespace Avalonia.Base.UnitTests
{
var target = new Class1();
var source = new TestTwoWayBindingViewModel();
var binding1 = new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source };
var binding1 = new Binding(nameof(source.Value))
{
Mode = BindingMode.TwoWay,
Source = source
};
var binding2 = new BehaviorSubject<double>(123.4);
target.Bind(Class1.DoubleValueProperty, binding1, priority);
@ -1182,7 +1202,11 @@ namespace Avalonia.Base.UnitTests
var target = new Class1();
var source = new TestTwoWayBindingViewModel();
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source });
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value))
{
Mode = BindingMode.TwoWay,
Source = source
});
target.SetValue(Class1.DoubleValueProperty, 123.4, BindingPriority.Animation);
// Setter should not be called because the TwoWay binding with Style priority
@ -1197,7 +1221,11 @@ namespace Avalonia.Base.UnitTests
var source1 = new TestTwoWayBindingViewModel();
var source2 = new BehaviorSubject<double>(123.4);
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source1.Value), BindingMode.TwoWay) { Source = source1 });
target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source1.Value))
{
Mode = BindingMode.TwoWay,
Source = source1
});
target.Bind(Class1.DoubleValueProperty, source2, BindingPriority.Animation);
// Setter should not be called because the TwoWay binding with Style priority

3
tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs

@ -143,8 +143,9 @@ namespace Avalonia.Base.UnitTests.Styling
Classes = { "foo" },
};
var binding = new Binding("Name", BindingMode.OneWay)
var binding = new Binding("Name")
{
Mode = BindingMode.OneWay,
Converter = new TestConverter(),
RelativeSource = new RelativeSource(RelativeSourceMode.Self),
};

2
tests/Avalonia.Benchmarks/Data/Binding_Setup.cs

@ -31,7 +31,7 @@ public class Binding_Setup
public void Setup_DataContext_Property_Binding_TwoWay()
{
var target = _target;
var binding = new Binding(nameof(_data.IntValue), mode: BindingMode.TwoWay);
var binding = new Binding(nameof(_data.IntValue)) { Mode = BindingMode.TwoWay };
for (var i = 0; i < 100; ++i)
{

2
tests/Avalonia.Benchmarks/Data/Binding_Values.cs

@ -36,7 +36,7 @@ public class Binding_Values
_data.IntValue = -1;
var target = _target;
var binding = new Binding(nameof(_data.IntValue), mode: BindingMode.TwoWay);
var binding = new Binding(nameof(_data.IntValue)) { Mode = BindingMode.TwoWay };
using var d = target.Bind(TestControl.IntValueProperty, binding);
for (var i = 0; i < 100; ++i)

8
tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs

@ -29,7 +29,7 @@ namespace Avalonia.Controls.UnitTests
var target = new TextBox
{
DataContext = new ExceptionTest(),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay },
Template = CreateTemplate(),
};
@ -51,7 +51,7 @@ namespace Avalonia.Controls.UnitTests
var target = new TextBox
{
DataContext = new ExceptionTest(),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay },
Template = CreateTemplate(),
};
@ -77,7 +77,7 @@ namespace Avalonia.Controls.UnitTests
var target = new TextBox
{
DataContext = new ExceptionTest(),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay },
Template = CreateTemplate()
};
DataValidationErrors.SetErrorConverter(target, err => "Error: " + err);
@ -101,7 +101,7 @@ namespace Avalonia.Controls.UnitTests
var target = new TextBox
{
DataContext = new ExceptionTest(),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
[!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay },
Template = CreateTemplate(),
};

3
tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj

@ -15,7 +15,8 @@
<ItemGroup>
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
</ItemGroup>
<ItemGroup>

3
tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj

@ -15,7 +15,8 @@
<ItemGroup>
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
</ItemGroup>
<ItemGroup>

8
tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs

@ -544,8 +544,8 @@ namespace Avalonia.Markup.UnitTests.Data
var root = new Panel { Children = { target1, target2 } };
var source = new Source { Foo = "foo" };
using (target1.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.OneTime)))
using (target2.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.OneWayToSource)))
using (target1.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.OneTime }))
using (target2.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.OneWayToSource }))
{
root.DataContext = source;
}
@ -643,8 +643,8 @@ namespace Avalonia.Markup.UnitTests.Data
Children = { target1, target2 }
};
target1.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.TwoWay));
target2.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.OneWayToSource));
target1.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.TwoWay });
target2.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.OneWayToSource });
Assert.Equal("OneWayToSource", source.Foo);

19
tests/Avalonia.Markup.UnitTests/Data/BindingTests_Delay.cs

@ -29,7 +29,11 @@ public class BindingTests_Delay : ScopedTestBase, IDisposable
_source = new BindingTests.Source { Foo = InitialFooValue };
_target = new TextBox { DataContext = _source };
_binding = new Binding(nameof(_source.Foo), BindingMode.TwoWay) { Delay = DelayMilliseconds };
_binding = new Binding(nameof(_source.Foo))
{
Mode = BindingMode.TwoWay,
Delay = DelayMilliseconds
};
_bindingExpr = _target.Bind(TextBox.TextProperty, _binding);
@ -120,7 +124,12 @@ public class BindingTests_Delay : ScopedTestBase, IDisposable
new TestRoot() { Child = new Panel() { Children = { _target, secondBox } } };
_target.Bind(TextBox.TextProperty, new Binding(nameof(_source.Foo), BindingMode.TwoWay) { Delay = DelayMilliseconds, UpdateSourceTrigger = UpdateSourceTrigger.LostFocus });
_target.Bind(TextBox.TextProperty, new Binding(nameof(_source.Foo))
{
Mode = BindingMode.TwoWay,
Delay = DelayMilliseconds,
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus
});
Assert.True(_target.Focus());
_target.Text = "bar";
@ -134,7 +143,11 @@ public class BindingTests_Delay : ScopedTestBase, IDisposable
[Fact]
public void Delayed_Binding_OneWayToSource_DataContext_Change_Should_Update_Source_Immediately()
{
_target.Bind(TextBlock.TextProperty, new Binding(nameof(_source.Foo), BindingMode.OneWayToSource) { Delay = DelayMilliseconds });
_target.Bind(TextBlock.TextProperty, new Binding(nameof(_source.Foo))
{
Mode = BindingMode.OneWayToSource,
Delay = DelayMilliseconds
});
_target.Text = "bar";

3
tests/Avalonia.Markup.UnitTests/Data/BindingTests_Self.cs

@ -34,8 +34,9 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new TextBlock
{
Tag = "Hello World!",
[!TextBlock.TextProperty] = new Binding("Tag", BindingMode.TwoWay)
[!TextBlock.TextProperty] = new Binding("Tag")
{
Mode = BindingMode.TwoWay,
RelativeSource = new RelativeSource(RelativeSourceMode.Self)
},
};

Loading…
Cancel
Save