Browse Source

Merge branch 'master' into fixes/DevTools/WithoutApplicationLifetime

pull/10510/head
Max Katz 3 years ago
committed by GitHub
parent
commit
506d05bac2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      .editorconfig
  2. 6
      Avalonia.Desktop.slnf
  3. 24
      Avalonia.sln
  4. 2
      build/DevAnalyzers.props
  5. 32
      build/ExternalConsumers.props
  6. 6
      native/Avalonia.Native/src/OSX/AvnView.mm
  7. 2
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  8. 1
      nukebuild/Build.cs
  9. 24
      nukebuild/RefAssemblyGenerator.cs
  10. 5
      nukebuild/numerge.config
  11. 21
      packages/Avalonia/Avalonia.csproj
  12. 2
      packages/Avalonia/Avalonia.props
  13. 63
      readme.md
  14. 2
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  15. 6
      samples/ControlCatalog.NetCore/Properties/launchSettings.json
  16. 2
      samples/ControlCatalog/App.xaml
  17. 48
      samples/ControlCatalog/MainView.xaml.cs
  18. 11
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  19. 1
      samples/IntegrationTestApp/IntegrationTestApp.csproj
  20. 2
      samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj
  21. 4
      samples/RenderDemo/Pages/CustomSkiaPage.cs
  22. 2
      samples/RenderDemo/Pages/WriteableBitmapPage.cs
  23. 10
      samples/Sandbox/MainWindow.axaml.cs
  24. 2
      samples/Sandbox/Sandbox.csproj
  25. 6
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  26. 12
      src/Avalonia.Base/Animation/Animation.cs
  27. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  28. 2
      src/Avalonia.Base/ClassBindingManager.cs
  29. 2
      src/Avalonia.Base/Collections/AvaloniaDictionaryExtensions.cs
  30. 2
      src/Avalonia.Base/Controls/IResourceDictionary.cs
  31. 21
      src/Avalonia.Base/Controls/IThemeVariantProvider.cs
  32. 12
      src/Avalonia.Base/Controls/ResourceDictionary.cs
  33. 46
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  34. 3
      src/Avalonia.Base/Data/BindingPriority.cs
  35. 3
      src/Avalonia.Base/Data/InstancedBinding.cs
  36. 2
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  37. 13
      src/Avalonia.Base/Input/Cursor.cs
  38. 3
      src/Avalonia.Base/Input/DataFormats.cs
  39. 3
      src/Avalonia.Base/Input/DataObjectExtensions.cs
  40. 3
      src/Avalonia.Base/Input/DragEventArgs.cs
  41. 3
      src/Avalonia.Base/Input/PointerDeltaEventArgs.cs
  42. 16
      src/Avalonia.Base/Input/PointerEventArgs.cs
  43. 3
      src/Avalonia.Base/Input/PointerWheelEventArgs.cs
  44. 10
      src/Avalonia.Base/Layout/LayoutManager.cs
  45. 18
      src/Avalonia.Base/Layout/LayoutQueue.cs
  46. 40
      src/Avalonia.Base/Layout/Layoutable.cs
  47. 14
      src/Avalonia.Base/Media/Color.cs
  48. 2
      src/Avalonia.Base/Media/DashStyle.cs
  49. 7
      src/Avalonia.Base/Media/DrawingContext.cs
  50. 2
      src/Avalonia.Base/Media/GeometryDrawing.cs
  51. 2
      src/Avalonia.Base/Media/GradientBrush.cs
  52. 36
      src/Avalonia.Base/Media/HslColor.cs
  53. 1
      src/Avalonia.Base/Media/ImmediateDrawingContext.cs
  54. 16
      src/Avalonia.Base/Media/PlatformDrawingContext.cs
  55. 2
      src/Avalonia.Base/Media/PolyLineSegment.cs
  56. 4
      src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
  57. 33
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  58. 2
      src/Avalonia.Base/Media/TransformGroup.cs
  59. 23
      src/Avalonia.Base/Metadata/AvaloniaListAttribute.cs
  60. 22
      src/Avalonia.Base/Metadata/UnstableAttribute.cs
  61. 295
      src/Avalonia.Base/Platform/AssetLoader.cs
  62. 2
      src/Avalonia.Base/Platform/IAssetLoader.cs
  63. 7
      src/Avalonia.Base/Platform/IDrawingContextImpl.cs
  64. 255
      src/Avalonia.Base/Platform/StandardAssetLoader.cs
  65. 2
      src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs
  66. 27
      src/Avalonia.Base/Platform/Storage/NoopStorageProvider.cs
  67. 5
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
  68. 14
      src/Avalonia.Base/Rendering/SceneGraph/CustomDrawOperation.cs
  69. 1
      src/Avalonia.Base/StyledElement.cs
  70. 1
      src/Avalonia.Base/Styling/IThemeVariantHost.cs
  71. 4
      src/Avalonia.Base/Styling/ThemeVariant.cs
  72. 89
      src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
  73. 57
      src/Avalonia.Base/Threading/DispatcherFrame.cs
  74. 3
      src/Avalonia.Base/Threading/DispatcherPriority.cs
  75. 5
      src/Avalonia.Base/Utilities/SpanHelpers.cs
  76. 1
      src/Avalonia.Base/Visual.cs
  77. 5
      src/Avalonia.Base/VisualTree/IVisualWithRoundRectClip.cs
  78. 1
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  79. 26
      src/Avalonia.Build.Tasks/SpanCompat.cs
  80. 39
      src/Avalonia.Controls/AppBuilder.cs
  81. 2
      src/Avalonia.Controls/Application.cs
  82. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  83. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteFilterMode.cs
  84. 6
      src/Avalonia.Controls/Avalonia.Controls.csproj
  85. 2
      src/Avalonia.Controls/ColumnDefinition.cs
  86. 6
      src/Avalonia.Controls/ContextMenu.cs
  87. 12
      src/Avalonia.Controls/DefinitionBase.cs
  88. 2
      src/Avalonia.Controls/DefinitionList.cs
  89. 2
      src/Avalonia.Controls/Documents/Span.cs
  90. 4
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  91. 2
      src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs
  92. 48
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  93. 7
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  94. 3
      src/Avalonia.Controls/ItemsControl.cs
  95. 4
      src/Avalonia.Controls/LayoutTransformControl.cs
  96. 8
      src/Avalonia.Controls/ListBox.cs
  97. 6
      src/Avalonia.Controls/MenuItem.cs
  98. 3
      src/Avalonia.Controls/Platform/Dialogs/ISystemDialogImpl.cs
  99. 3
      src/Avalonia.Controls/Platform/Dialogs/SystemDialogImpl.cs
  100. 36
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs

17
.editorconfig

@ -186,6 +186,23 @@ csharp_wrap_before_ternary_opsigns = false
# Avalonia DevAnalyzer preferences
dotnet_diagnostic.AVADEV2001.severity = error
# Avalonia PublicAnalyzer preferences
dotnet_diagnostic.AVP1000.severity = error
dotnet_diagnostic.AVP1001.severity = error
dotnet_diagnostic.AVP1002.severity = error
dotnet_diagnostic.AVP1010.severity = error
dotnet_diagnostic.AVP1011.severity = error
dotnet_diagnostic.AVP1012.severity = warning
dotnet_diagnostic.AVP1013.severity = error
dotnet_diagnostic.AVP1020.severity = error
dotnet_diagnostic.AVP1021.severity = error
dotnet_diagnostic.AVP1022.severity = error
dotnet_diagnostic.AVP1030.severity = error
dotnet_diagnostic.AVP1031.severity = error
dotnet_diagnostic.AVP1032.severity = error
dotnet_diagnostic.AVP1040.severity = error
dotnet_diagnostic.AVA2001.severity = error
# Xaml files
[*.{xaml,axaml}]
indent_size = 2

6
Avalonia.Desktop.slnf

@ -24,8 +24,6 @@
"src\\Avalonia.Dialogs\\Avalonia.Dialogs.csproj",
"src\\Avalonia.Fonts.Inter\\Avalonia.Fonts.Inter.csproj",
"src\\Avalonia.FreeDesktop\\Avalonia.FreeDesktop.csproj",
"src\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
"src\\Avalonia.Headless\\Avalonia.Headless.csproj",
"src\\Avalonia.MicroCom\\Avalonia.MicroCom.csproj",
"src\\Avalonia.Native\\Avalonia.Native.csproj",
"src\\Avalonia.OpenGL\\Avalonia.OpenGL.csproj",
@ -34,6 +32,8 @@
"src\\Avalonia.Themes.Fluent\\Avalonia.Themes.Fluent.csproj",
"src\\Avalonia.Themes.Simple\\Avalonia.Themes.Simple.csproj",
"src\\Avalonia.X11\\Avalonia.X11.csproj",
"src\\Headless\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
"src\\Headless\\Avalonia.Headless\\Avalonia.Headless.csproj",
"src\\Linux\\Avalonia.LinuxFramebuffer\\Avalonia.LinuxFramebuffer.csproj",
"src\\Markup\\Avalonia.Markup.Xaml.Loader\\Avalonia.Markup.Xaml.Loader.csproj",
"src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
@ -66,4 +66,4 @@
"tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj"
]
}
}
}

24
Avalonia.sln

@ -181,9 +181,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Fluent", "src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj", "{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Headless\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.Vnc", "src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj", "{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.Vnc", "src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj", "{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.Loader", "src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj", "{909A8CBD-7D0E-42FD-B841-022AD8925820}"
EndProject
@ -233,7 +233,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\R
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
ProjectSection(SolutionItems) = preProject
@ -261,6 +261,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Desktop", "sam
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples\SafeAreaDemo.iOS\SafeAreaDemo.iOS.csproj", "{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.UnitTests", "tests\Avalonia.Headless.UnitTests\Avalonia.Headless.UnitTests.csproj", "{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -600,6 +606,14 @@ Global
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.Build.0 = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.Build.0 = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -695,6 +709,10 @@ Global
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}

2
build/DevAnalyzers.props

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

32
build/ExternalConsumers.props

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

6
native/Avalonia.Native/src/OSX/AvnView.mm

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

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

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

1
nukebuild/Build.cs

@ -212,6 +212,7 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests");
RunCoreTest("Avalonia.Headless.UnitTests");
});
Target RunRenderTests => _ => _

24
nukebuild/RefAssemblyGenerator.cs

@ -96,7 +96,7 @@ public class RefAssemblyGenerator
| MethodAttributes.HideBySig, type.Module.TypeSystem.Void));
}
var forceUnstable = type.CustomAttributes.Any(a =>
var forceUnstable = type.CustomAttributes.FirstOrDefault(a =>
a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute");
foreach (var m in type.Methods)
@ -109,22 +109,28 @@ public class RefAssemblyGenerator
}
}
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, bool force)
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute)
{
if (!force && (
def.HasCustomAttributes == false
|| def.CustomAttributes.All(a => a.AttributeType.FullName != "Avalonia.Metadata.UnstableAttribute")))
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
return;
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
unstableAttribute = def.CustomAttributes.FirstOrDefault(a =>
a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute") ?? unstableAttribute;
if (unstableAttribute is null)
return;
var message = unstableAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString();
if (string.IsNullOrEmpty(message))
{
message = "This is a part of unstable API and can be changed in minor releases. Consider replacing it with alternatives or reach out developers on GitHub.";
}
def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
{
ConstructorArguments =
{
new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String,
"This is a part of unstable API and can be changed in minor releases. You have been warned")
new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String, message)
}
});
}
@ -168,4 +174,4 @@ public class RefAssemblyGenerator
}
}
}
}
}

5
nukebuild/numerge.config

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

21
packages/Avalonia/Avalonia.csproj

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

2
packages/Avalonia/Avalonia.props

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

63
readme.md

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

2
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -26,7 +26,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />

6
samples/ControlCatalog.NetCore/Properties/launchSettings.json

@ -6,6 +6,10 @@
"Dxgi": {
"commandName": "Project",
"commandLineArgs": "--dxgi"
},
"VNC": {
"commandName": "Project",
"commandLineArgs": "--vnc"
}
}
}
}

2
samples/ControlCatalog/App.xaml

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

48
samples/ControlCatalog/MainView.xaml.cs

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

11
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

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

1
samples/IntegrationTestApp/IntegrationTestApp.csproj

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

2
samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj

@ -19,7 +19,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\MobileSandbox\MobileSandbox.csproj" />

4
samples/RenderDemo/Pages/CustomSkiaPage.cs

@ -44,9 +44,9 @@ namespace RenderDemo.Pages
public bool HitTest(Point p) => false;
public bool Equals(ICustomDrawOperation other) => false;
static Stopwatch St = Stopwatch.StartNew();
public void Render(IDrawingContextImpl context)
public void Render(ImmediateDrawingContext context)
{
var leaseFeature = context.GetFeature<ISkiaSharpApiLeaseFeature>();
var leaseFeature = context.TryGetFeature<ISkiaSharpApiLeaseFeature>();
if (leaseFeature == null)
context.DrawGlyphRun(Brushes.Black, _noSkia.PlatformImpl);
else

2
samples/RenderDemo/Pages/WriteableBitmapPage.cs

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

10
samples/Sandbox/MainWindow.axaml.cs

@ -6,17 +6,11 @@ using Avalonia.Win32.WinRT.Composition;
namespace Sandbox
{
public class MainWindow : Window
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.AttachDevTools();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
InitializeComponent();
}
}
}

2
samples/Sandbox/Sandbox.csproj

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

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

@ -91,7 +91,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Action<Rect> Paint { get; set; }
public Action<Size, PlatformResizeReason> Resized { get; set; }
public Action<Size, WindowResizeReason> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
@ -156,12 +156,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform
protected virtual void OnResized(Size size)
{
Resized?.Invoke(size, PlatformResizeReason.Unspecified);
Resized?.Invoke(size, WindowResizeReason.Unspecified);
}
internal void Resize(Size size)
{
Resized?.Invoke(size, PlatformResizeReason.Layout);
Resized?.Invoke(size, WindowResizeReason.Layout);
}
class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo

12
src/Avalonia.Base/Animation/Animation.cs

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

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -22,6 +22,7 @@
<Import Project="..\..\build\SourceGenerators.props" />
<ItemGroup>
<Compile Include="..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" />
<Compile Include="..\Shared\ModuleInitializer.cs" Link="ModuleInitializer.cs" />
<Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" />
</ItemGroup>

2
src/Avalonia.Base/ClassBindingManager.cs

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

2
src/Avalonia.Base/Collections/AvaloniaDictionaryExtensions.cs

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

2
src/Avalonia.Base/Controls/IResourceDictionary.cs

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

21
src/Avalonia.Base/Controls/IThemeVariantProvider.cs

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

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

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

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

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

3
src/Avalonia.Base/Data/BindingPriority.cs

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

3
src/Avalonia.Base/Data/InstancedBinding.cs

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

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

@ -176,7 +176,7 @@ namespace Avalonia.Input
{
bool menuIsOpen = MainMenu?.IsOpen == true;
if (e.KeyModifiers.HasAllFlags(KeyModifiers.Alt) || menuIsOpen)
if (e.KeyModifiers.HasAllFlags(KeyModifiers.Alt) && !e.KeyModifiers.HasAllFlags(KeyModifiers.Control) || menuIsOpen)
{
// If any other key is pressed with the Alt key held down, or the main menu is open,
// find all controls who have registered that access key.

13
src/Avalonia.Base/Input/Cursor.cs

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

3
src/Avalonia.Base/Input/DataFormats.cs

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

3
src/Avalonia.Base/Input/DataObjectExtensions.cs

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

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

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

3
src/Avalonia.Base/Input/PointerDeltaEventArgs.cs

@ -9,8 +9,7 @@ namespace Avalonia.Input
{
public Vector Delta { get; }
[Unstable]
[Obsolete("This constructor might be removed in 12.0.")]
[Unstable("This constructor might be removed in 12.0.")]
public PointerDeltaEventArgs(RoutedEvent routedEvent, object? source,
IPointer pointer, Visual rootVisual, Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, KeyModifiers modifiers, Vector delta)

16
src/Avalonia.Base/Input/PointerEventArgs.cs

@ -14,8 +14,7 @@ namespace Avalonia.Input
private readonly PointerPointProperties _properties;
private readonly Lazy<IReadOnlyList<RawPointerPoint>?>? _previousPoints;
[Unstable]
[Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
public PointerEventArgs(RoutedEvent routedEvent,
object? source,
IPointer pointer,
@ -77,14 +76,14 @@ namespace Avalonia.Input
/// <summary>
/// Gets the pointer position relative to a control.
/// </summary>
/// <param name="relativeTo">The control.</param>
/// <param name="relativeTo">The visual whose coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns>The pointer position in the control's coordinates.</returns>
public Point GetPosition(Visual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
/// <summary>
/// Returns the PointerPoint associated with the current event
/// </summary>
/// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param>
/// <param name="relativeTo">The visual whose coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns></returns>
public PointerPoint GetCurrentPoint(Visual? relativeTo)
=> new PointerPoint(Pointer, GetPosition(relativeTo), _properties);
@ -129,8 +128,7 @@ namespace Avalonia.Input
public class PointerPressedEventArgs : PointerEventArgs
{
[Unstable]
[Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
public PointerPressedEventArgs(
object source,
IPointer pointer,
@ -150,8 +148,7 @@ namespace Avalonia.Input
public class PointerReleasedEventArgs : PointerEventArgs
{
[Unstable]
[Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
public PointerReleasedEventArgs(
object source, IPointer pointer,
Visual rootVisual, Point rootVisualPosition, ulong timestamp,
@ -173,8 +170,7 @@ namespace Avalonia.Input
{
public IPointer Pointer { get; }
[Unstable]
[Obsolete("This constructor might be removed in 12.0. If you need to remove capture, use stable methods on the IPointer instance.,")]
[Unstable("This constructor might be removed in 12.0. If you need to remove capture, use stable methods on the IPointer instance.,")]
public PointerCaptureLostEventArgs(object source, IPointer pointer) : base(InputElement.PointerCaptureLostEvent)
{
Pointer = pointer;

3
src/Avalonia.Base/Input/PointerWheelEventArgs.cs

@ -9,8 +9,7 @@ namespace Avalonia.Input
{
public Vector Delta { get; }
[Unstable]
[Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow.MouseWheel.")]
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow.MouseWheel.")]
public PointerWheelEventArgs(object source, IPointer pointer, Visual rootVisual,
Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, KeyModifiers modifiers, Vector delta)

10
src/Avalonia.Base/Layout/LayoutManager.cs

@ -17,7 +17,7 @@ namespace Avalonia.Layout
/// </summary>
public class LayoutManager : ILayoutManager, IDisposable
{
private const int MaxPasses = 3;
private const int MaxPasses = 10;
private readonly Layoutable _owner;
private readonly LayoutQueue<Layoutable> _toMeasure = new LayoutQueue<Layoutable>(v => !v.IsMeasureValid);
private readonly LayoutQueue<Layoutable> _toArrange = new LayoutQueue<Layoutable>(v => !v.IsArrangeValid);
@ -249,10 +249,12 @@ namespace Avalonia.Layout
{
var control = _toMeasure.Dequeue();
if (!control.IsMeasureValid && control.IsAttachedToVisualTree)
if (!control.IsMeasureValid)
{
Measure(control);
}
_toArrange.Enqueue(control);
}
}
@ -262,7 +264,7 @@ namespace Avalonia.Layout
{
var control = _toArrange.Dequeue();
if (!control.IsArrangeValid && control.IsAttachedToVisualTree)
if (!control.IsArrangeValid)
{
Arrange(control);
}
@ -297,8 +299,6 @@ namespace Avalonia.Layout
{
control.Measure(control.PreviousMeasure.Value);
}
_toArrange.Enqueue(control);
}
return true;

18
src/Avalonia.Base/Layout/LayoutQueue.cs

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Avalonia.Logging;
namespace Avalonia.Layout
{
@ -48,10 +49,21 @@ namespace Avalonia.Layout
{
_loopQueueInfo.TryGetValue(item, out var info);
if (!info.Active && info.Count < _maxEnqueueCountPerLoop)
if (!info.Active)
{
_inner.Enqueue(item);
_loopQueueInfo[item] = new Info() { Active = true, Count = info.Count + 1 };
if (info.Count < _maxEnqueueCountPerLoop)
{
_inner.Enqueue(item);
_loopQueueInfo[item] = new Info() { Active = true, Count = info.Count + 1 };
}
else
{
Logger.TryGet(LogEventLevel.Warning, LogArea.Layout)?.Log(
this,
"Layout cycle detected. Item {Item} was enqueued {Count} times.",
item,
info.Count);
}
}
}

40
src/Avalonia.Base/Layout/Layoutable.cs

@ -776,10 +776,24 @@ namespace Avalonia.Layout
// All changes to visibility cause the parent element to be notified.
this.GetVisualParent<Layoutable>()?.ChildDesiredSizeChanged(this);
// We only invalidate outselves when visibility is changed to true.
if (change.GetNewValue<bool>())
{
// We only invalidate ourselves when visibility is changed to true.
InvalidateMeasure();
// If any descendant had its measure/arrange invalidated while we were hidden,
// they will need to to be registered with the layout manager now that they
// are again effectively visible. If IsEffectivelyVisible becomes an observable
// property then we can piggy-pack on that; for the moment we do this manually.
if (VisualRoot is ILayoutRoot layoutRoot)
{
var count = VisualChildren.Count;
for (var i = 0; i < count; ++i)
{
(VisualChildren[i] as Layoutable)?.AncestorBecameVisible(layoutRoot.LayoutManager);
}
}
}
}
}
@ -804,6 +818,30 @@ namespace Avalonia.Layout
InvalidateMeasure();
}
private void AncestorBecameVisible(ILayoutManager layoutManager)
{
if (!IsVisible)
return;
if (!IsMeasureValid)
{
layoutManager.InvalidateMeasure(this);
InvalidateVisual();
}
else if (!IsArrangeValid)
{
layoutManager.InvalidateArrange(this);
InvalidateVisual();
}
var count = VisualChildren.Count;
for (var i = 0; i < count; ++i)
{
(VisualChildren[i] as Layoutable)?.AncestorBecameVisible(layoutManager);
}
}
/// <summary>
/// Called when the layout manager raises a LayoutUpdated event.
/// </summary>

14
src/Avalonia.Base/Media/Color.cs

@ -6,11 +6,12 @@
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.ComponentModel;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
using static Avalonia.Utilities.SpanHelpers;
#endif
using static Avalonia.Utilities.SpanHelpers;
namespace Avalonia.Media
{
@ -449,7 +450,7 @@ namespace Avalonia.Media
/// </returns>
public override string ToString()
{
uint rgb = ToUint32();
uint rgb = ToUInt32();
return KnownColors.GetKnownColorName(rgb) ?? $"#{rgb.ToString("x8", CultureInfo.InvariantCulture)}";
}
@ -459,11 +460,18 @@ namespace Avalonia.Media
/// <returns>
/// The integer representation of the color.
/// </returns>
public uint ToUint32()
public uint ToUInt32()
{
return ((uint)A << 24) | ((uint)R << 16) | ((uint)G << 8) | (uint)B;
}
/// <inheritdoc cref="Color.ToUInt32"/>
[Obsolete("Use Color.ToUInt32() instead."), EditorBrowsable(EditorBrowsableState.Never)]
public uint ToUint32()
{
return ToUInt32();
}
/// <summary>
/// Returns the HSL color model equivalent of this RGB color.
/// </summary>

2
src/Avalonia.Base/Media/DashStyle.cs

@ -44,6 +44,8 @@ namespace Avalonia.Media
/// </summary>
/// <param name="dashes">The dashes collection.</param>
/// <param name="offset">The dash sequence offset.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public DashStyle(IEnumerable<double>? dashes, double offset)
{
Dashes = (dashes as AvaloniaList<double>) ?? new AvaloniaList<double>(dashes ?? Array.Empty<double>());

7
src/Avalonia.Base/Media/DrawingContext.cs

@ -5,6 +5,7 @@ using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Media.Imaging;
using System.ComponentModel;
namespace Avalonia.Media
{
@ -417,11 +418,11 @@ namespace Avalonia.Media
return new PushedState(this);
}
[Obsolete("Use PushTransform")]
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushPreTransform(Matrix matrix) => PushTransform(matrix);
[Obsolete("Use PushTransform")]
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushPostTransform(Matrix matrix) => PushTransform(matrix);
[Obsolete("Use PushTransform")]
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushTransformContainer() => PushTransform(Matrix.Identity);

2
src/Avalonia.Base/Media/GeometryDrawing.cs

@ -10,7 +10,7 @@ namespace Avalonia.Media
public class GeometryDrawing : Drawing
{
// Adding the Pen's stroke thickness here could yield wrong results due to transforms.
private static readonly IPen s_boundsPen = new ImmutablePen(Colors.Black.ToUint32(), 0);
private static readonly IPen s_boundsPen = new ImmutablePen(Colors.Black.ToUInt32(), 0);
/// <summary>
/// Defines the <see cref="Geometry"/> property.

2
src/Avalonia.Base/Media/GradientBrush.cs

@ -38,6 +38,8 @@ namespace Avalonia.Media
/// <summary>
/// Initializes a new instance of the <see cref="GradientBrush"/> class.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public GradientBrush()
{
this.GradientStops = new GradientStops();

36
src/Avalonia.Base/Media/HslColor.cs

@ -98,43 +98,13 @@ namespace Avalonia.Media
L = hsl.L;
}
/// <summary>
/// Gets the Alpha (transparency) component in the range from 0..1 (percentage).
/// </summary>
/// <remarks>
/// <list type="bullet">
/// <item>0 is fully transparent.</item>
/// <item>1 is fully opaque.</item>
/// </list>
/// </remarks>
/// <inheritdoc cref="HsvColor.A"/>
public double A { get; }
/// <summary>
/// Gets the Hue component in the range from 0..360 (degrees).
/// This is the color's location, in degrees, on a color wheel/circle from 0 to 360.
/// Note that 360 is equivalent to 0 and will be adjusted automatically.
/// </summary>
/// <remarks>
/// <list type="bullet">
/// <item>0/360 degrees is Red.</item>
/// <item>60 degrees is Yellow.</item>
/// <item>120 degrees is Green.</item>
/// <item>180 degrees is Cyan.</item>
/// <item>240 degrees is Blue.</item>
/// <item>300 degrees is Magenta.</item>
/// </list>
/// </remarks>
/// <inheritdoc cref="HsvColor.H"/>
public double H { get; }
/// <summary>
/// Gets the Saturation component in the range from 0..1 (percentage).
/// </summary>
/// <remarks>
/// <list type="bullet">
/// <item>0 is a shade of gray (no color).</item>
/// <item>1 is the full color.</item>
/// </list>
/// </remarks>
/// <inheritdoc cref="HsvColor.S"/>
public double S { get; }
/// <summary>

1
src/Avalonia.Base/Media/ImmediateDrawingContext.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Media.Imaging;

16
src/Avalonia.Base/Media/PlatformDrawingContext.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Avalonia.Logging;
using Avalonia.Media.Imaging;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
@ -41,8 +42,19 @@ internal sealed class PlatformDrawingContext : DrawingContext, IDrawingContextWi
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default) =>
_impl.DrawBitmap(source, opacity, sourceRect, destRect, bitmapInterpolationMode);
public override void Custom(ICustomDrawOperation custom) =>
custom.Render(_impl);
public override void Custom(ICustomDrawOperation custom)
{
using var immediateDrawingContext = new ImmediateDrawingContext(_impl, false);
try
{
custom.Render(immediateDrawingContext);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, LogArea.Visual)
?.Log(custom, $"Exception in {custom.GetType().Name}.{nameof(ICustomDrawOperation.Render)} {{0}}", e);
}
}
public override void DrawGlyphRun(IBrush? foreground, GlyphRun glyphRun)
{

2
src/Avalonia.Base/Media/PolyLineSegment.cs

@ -28,6 +28,8 @@ namespace Avalonia.Media
/// <summary>
/// Initializes a new instance of the <see cref="PolyLineSegment"/> class.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public PolyLineSegment()
{
Points = new Points();

4
src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs

@ -185,7 +185,9 @@ namespace Avalonia.Media.TextFormatting
}
//Stop at the first missing glyph
if (!currentCodepoint.IsBreakChar && !glyphTypeface.TryGetGlyph(currentCodepoint, out _))
if (!currentCodepoint.IsBreakChar &&
currentCodepoint.GeneralCategory != GeneralCategory.Control &&
!glyphTypeface.TryGetGlyph(currentCodepoint, out _))
{
break;
}

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

@ -83,7 +83,7 @@ namespace Avalonia.Media.TextFormatting
/// <inheritdoc/>
public override void Draw(DrawingContext drawingContext, Point lineOrigin)
{
var (currentX, currentY) = lineOrigin;
var (currentX, currentY) = lineOrigin + new Point(Start, 0);
foreach (var textRun in _textRuns)
{
@ -698,7 +698,7 @@ namespace Avalonia.Media.TextFormatting
i = lastRunIndex;
//Possible overlap at runs of different direction
if (directionalWidth == 0)
if (directionalWidth == 0 && i < _textRuns.Length - 1)
{
//In case a run only contains a linebreak we don't want to skip it.
if (currentRun is ShapedTextRun shaped)
@ -844,7 +844,7 @@ namespace Avalonia.Media.TextFormatting
i = firstRunIndex;
//Possible overlap at runs of different direction
if (directionalWidth == 0)
if (directionalWidth == 0 && i > 0)
{
//In case a run only contains a linebreak we don't want to skip it.
if (currentRun is ShapedTextRun shaped)
@ -860,8 +860,8 @@ namespace Avalonia.Media.TextFormatting
}
}
TextBounds? textBounds = null;
int coveredLength;
TextBounds? textBounds;
switch (currentDirection)
{
@ -942,6 +942,13 @@ namespace Avalonia.Media.TextFormatting
new TextRunBounds(
new Rect(startX, 0, drawableTextRun.Size.Width, Height), currentPosition, currentRun.Length, currentRun));
}
else
{
//Add potential TextEndOfParagraph
textRunBounds.Add(
new TextRunBounds(
new Rect(endX, 0, 0, Height), currentPosition, currentRun.Length, currentRun));
}
currentPosition += currentRun.Length;
@ -1007,6 +1014,13 @@ namespace Avalonia.Media.TextFormatting
endX += drawableTextRun.Size.Width;
}
else
{
//Add potential TextEndOfParagraph
textRunBounds.Add(
new TextRunBounds(
new Rect(endX, 0, 0, Height), currentPosition, currentRun.Length, currentRun));
}
currentPosition += currentRun.Length;
@ -1409,8 +1423,6 @@ namespace Avalonia.Media.TextFormatting
var fontMetrics = _paragraphProperties.DefaultTextRunProperties.CachedGlyphTypeface.Metrics;
var fontRenderingEmSize = _paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize;
var scale = fontRenderingEmSize / fontMetrics.DesignEmHeight;
var width = 0d;
var widthIncludingWhitespace = 0d;
var trailingWhitespaceLength = 0;
var newLineLength = 0;
@ -1422,13 +1434,6 @@ namespace Avalonia.Media.TextFormatting
var lineHeight = _paragraphProperties.LineHeight;
var lastRunIndex = _textRuns.Length - 1;
if (lastRunIndex > 0 && _textRuns[lastRunIndex] is TextEndOfLine)
{
lastRunIndex--;
}
for (var index = 0; index < _textRuns.Length; index++)
{
switch (_textRuns[index])
@ -1486,7 +1491,7 @@ namespace Avalonia.Media.TextFormatting
}
}
width = widthIncludingWhitespace;
var width = widthIncludingWhitespace;
for (var i = _textRuns.Length - 1; i >= 0; i--)
{

2
src/Avalonia.Base/Media/TransformGroup.cs

@ -11,6 +11,8 @@ namespace Avalonia.Media
public static readonly StyledProperty<Transforms> ChildrenProperty =
AvaloniaProperty.Register<TransformGroup, Transforms>(nameof(Children));
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public TransformGroup()
{
Children = new Transforms();

23
src/Avalonia.Base/Metadata/AvaloniaListAttribute.cs

@ -0,0 +1,23 @@
using System;
namespace Avalonia.Metadata;
/// <summary>
/// Defines how compiler should split avalonia list string value before parsing individual items.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class AvaloniaListAttribute : Attribute
{
/// <summary>
/// Separator used to split input string.
/// Default value is ','.
/// </summary>
public string[]? Separators { get; init; }
/// <summary>
/// Split options used to split input string.
/// Default value is RemoveEmptyEntries with TrimEntries.
/// </summary>
// StringSplitOptions.TrimEntries = 2, but only on net6 target.
public StringSplitOptions SplitOptions { get; init; } = StringSplitOptions.RemoveEmptyEntries | (StringSplitOptions)2;
}

22
src/Avalonia.Base/Metadata/UnstableAttribute.cs

@ -1,4 +1,4 @@
using System;
using System;
namespace Avalonia.Metadata
{
@ -9,5 +9,25 @@ namespace Avalonia.Metadata
[AttributeUsage(AttributeTargets.All)]
public sealed class UnstableAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="UnstableAttribute"/> class.
/// </summary>
public UnstableAttribute()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="UnstableAttribute"/> class.
/// </summary>
/// <param name="message">The text string that describes alternative workarounds.</param>
public UnstableAttribute(string? message)
{
Message = message;
}
/// <summary>
/// Gets a value that indicates whether the compiler will treat usage of the obsolete program element as an error.
/// </summary>
public string? Message { get; }
}
}

295
src/Avalonia.Base/Platform/AssetLoader.cs

@ -1,281 +1,48 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
#if !BUILDTASK
using Avalonia.Platform.Internal;
using Avalonia.Utilities;
#endif
namespace Avalonia.Platform
{
/// <summary>
/// Loads assets compiled into the application binary.
/// </summary>
public class AssetLoader
namespace Avalonia.Platform;
#if !BUILDTASK
: IAssetLoader
/// <inheritdoc cref="IAssetLoader"/>
#endif
{
public static class AssetLoader
{
#if !BUILDTASK
private static IAssemblyDescriptorResolver s_assemblyDescriptorResolver = new AssemblyDescriptorResolver();
private AssemblyDescriptor? _defaultResmAssembly;
/// <remarks>
/// Introduced for tests.
/// </remarks>
internal static void SetAssemblyDescriptorResolver(IAssemblyDescriptorResolver resolver) =>
s_assemblyDescriptorResolver = resolver;
/// <summary>
/// Initializes a new instance of the <see cref="AssetLoader"/> class.
/// </summary>
/// <param name="assembly">
/// The default assembly from which to load resm: assets for which no assembly is specified.
/// </param>
public AssetLoader(Assembly? assembly = null)
{
if (assembly == null)
assembly = Assembly.GetEntryAssembly();
if (assembly != null)
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
/// Sets the default assembly from which to load assets for which no assembly is specified.
/// </summary>
/// <param name="assembly">The default assembly.</param>
public void SetDefaultAssembly(Assembly assembly)
{
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
/// Checks if an asset with the specified URI exists.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>True if the asset could be found; otherwise false.</returns>
public bool Exists(Uri uri, Uri? baseUri = null)
{
return TryGetAsset(uri, baseUri, out _);
}
/// <summary>
/// Opens the asset with the requested URI.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>A stream containing the asset contents.</returns>
/// <exception cref="FileNotFoundException">
/// The asset could not be found.
/// </exception>
public Stream Open(Uri uri, Uri? baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1;
/// <summary>
/// Opens the asset with the requested URI and returns the asset stream and the
/// assembly containing the asset.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>
/// The stream containing the resource contents together with the assembly.
/// </returns>
/// <exception cref="FileNotFoundException">
/// The asset could not be found.
/// </exception>
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri? baseUri = null)
{
if (TryGetAsset(uri, baseUri, out var assetDescriptor))
{
return (assetDescriptor.GetStream(), assetDescriptor.Assembly);
}
throw new FileNotFoundException($"The resource {uri} could not be found.");
}
public Assembly? GetAssembly(Uri uri, Uri? baseUri)
{
if (!uri.IsAbsoluteUri && baseUri != null)
{
uri = new Uri(baseUri, uri);
}
if (TryGetAssembly(uri, out var assemblyDescriptor))
{
return assemblyDescriptor.Assembly;
}
return null;
}
/// <summary>
/// Gets all assets of a folder and subfolders that match specified uri.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">Base URI that is used if <paramref name="uri"/> is relative.</param>
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
public IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri)
{
if (uri.IsAbsoluteResm())
{
if (!TryGetAssembly(uri, out var assembly))
{
assembly = _defaultResmAssembly;
}
return assembly?.Resources?
.Where(x => x.Key.Contains(uri.GetUnescapeAbsolutePath()))
.Select(x => new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ??
Enumerable.Empty<Uri>();
}
uri = uri.EnsureAbsolute(baseUri);
if (uri.IsAvares())
{
if (!TryGetResAsmAndPath(uri, out var assembly, out var path))
{
return Enumerable.Empty<Uri>();
}
private static IAssetLoader GetAssetLoader() => AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
if (assembly?.AvaloniaResources == null)
{
return Enumerable.Empty<Uri>();
}
/// <inheritdoc cref="IAssetLoader.SetDefaultAssembly"/>
public static void SetDefaultAssembly(Assembly assembly) => GetAssetLoader().SetDefaultAssembly(assembly);
if (path.Length > 0 && path[path.Length - 1] != '/')
{
path += '/';
}
/// <inheritdoc cref="IAssetLoader.Exists"/>
public static bool Exists(Uri uri, Uri? baseUri = null) => GetAssetLoader().Exists(uri, baseUri);
return assembly.AvaloniaResources
.Where(r => r.Key.StartsWith(path, StringComparison.Ordinal))
.Select(x => new Uri($"avares://{assembly.Name}{x.Key}"));
}
/// <inheritdoc cref="IAssetLoader.Open"/>
public static Stream Open(Uri uri, Uri? baseUri = null) => GetAssetLoader().Open(uri, baseUri);
return Enumerable.Empty<Uri>();
}
/// <inheritdoc cref="IAssetLoader.OpenAndGetAssembly"/>
public static (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri? baseUri = null)
=> GetAssetLoader().OpenAndGetAssembly(uri, baseUri);
private bool TryGetAsset(Uri uri, Uri? baseUri, [NotNullWhen(true)] out IAssetDescriptor? assetDescriptor)
{
assetDescriptor = null;
/// <inheritdoc cref="IAssetLoader.GetAssembly"/>
public static Assembly? GetAssembly(Uri uri, Uri? baseUri = null)
=> GetAssetLoader().GetAssembly(uri, baseUri);
if (uri.IsAbsoluteResm())
{
if (!TryGetAssembly(uri, out var assembly) && !TryGetAssembly(baseUri, out assembly))
{
assembly = _defaultResmAssembly;
}
if (assembly?.Resources != null)
{
var resourceKey = uri.AbsolutePath;
if (assembly.Resources.TryGetValue(resourceKey, out assetDescriptor))
{
return true;
}
}
}
uri = uri.EnsureAbsolute(baseUri);
if (uri.IsAvares())
{
if (TryGetResAsmAndPath(uri, out var assembly, out var path))
{
if (assembly.AvaloniaResources == null)
{
return false;
}
if (assembly.AvaloniaResources.TryGetValue(path, out assetDescriptor))
{
return true;
}
}
}
return false;
}
private static bool TryGetResAsmAndPath(Uri uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly, out string path)
{
path = uri.GetUnescapeAbsolutePath();
if (TryLoadAssembly(uri.Authority, out assembly))
{
return true;
}
return false;
}
private static bool TryGetAssembly(Uri? uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly)
{
assembly = null;
if (uri != null)
{
if (!uri.IsAbsoluteUri)
{
return false;
}
if (uri.IsAvares() && TryGetResAsmAndPath(uri, out assembly, out _))
{
return true;
}
if (uri.IsResm())
{
var assemblyName = uri.GetAssemblyNameFromQuery();
if (assemblyName.Length > 0 && TryLoadAssembly(assemblyName, out assembly))
{
return true;
}
}
}
return false;
}
private static bool TryLoadAssembly(string assemblyName, [NotNullWhen(true)] out IAssemblyDescriptor? assembly)
{
assembly = null;
try
{
assembly = s_assemblyDescriptorResolver.GetAssembly(assemblyName);
return true;
}
catch (Exception) { }
return false;
}
/// <inheritdoc cref="IAssetLoader.GetAssets"/>
public static IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri)
=> GetAssetLoader().GetAssets(uri, baseUri);
#endif
public static void RegisterResUriParsers()
{
if (!UriParser.IsKnownScheme("avares"))
UriParser.Register(new GenericUriParser(
GenericUriParserOptions.GenericAuthority |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoPort |
GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoFragment), "avares", -1);
}
internal static void RegisterResUriParsers()
{
if (!UriParser.IsKnownScheme("avares"))
UriParser.Register(new GenericUriParser(
GenericUriParserOptions.GenericAuthority |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoPort |
GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoFragment), "avares", -1);
}
}

2
src/Avalonia.Base/Platform/IAssetLoader.cs

@ -9,7 +9,7 @@ namespace Avalonia.Platform
/// <summary>
/// Loads assets compiled into the application binary.
/// </summary>
[Unstable]
[Unstable("IAssetLoader interface and AvaloniaLocator usage is considered unstable. Please use AssetLoader static class instead.")]
public interface IAssetLoader
{
/// <summary>

7
src/Avalonia.Base/Platform/IDrawingContextImpl.cs

@ -1,6 +1,5 @@
using System;
using Avalonia.Media;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities;
using Avalonia.Media.Imaging;
using Avalonia.Metadata;
@ -168,12 +167,6 @@ namespace Avalonia.Platform
/// </summary>
void PopBitmapBlendMode();
/// <summary>
/// Adds a custom draw operation
/// </summary>
/// <param name="custom">Custom draw operation</param>
void Custom(ICustomDrawOperation custom);
/// <summary>
/// Attempts to get an optional feature from the drawing context implementation
/// </summary>

255
src/Avalonia.Base/Platform/StandardAssetLoader.cs

@ -0,0 +1,255 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using Avalonia.Platform.Internal;
using Avalonia.Utilities;
namespace Avalonia.Platform;
/// <summary>
/// Loads assets compiled into the application binary.
/// </summary>
internal class StandardAssetLoader : IAssetLoader
{
private readonly IAssemblyDescriptorResolver _assemblyDescriptorResolver;
private AssemblyDescriptor? _defaultResmAssembly;
public StandardAssetLoader(IAssemblyDescriptorResolver resolver, Assembly? assembly = null)
{
if (assembly == null)
assembly = Assembly.GetEntryAssembly();
if (assembly != null)
_defaultResmAssembly = new AssemblyDescriptor(assembly);
_assemblyDescriptorResolver = resolver;
}
public StandardAssetLoader(Assembly? assembly = null) : this(new AssemblyDescriptorResolver(), assembly)
{
}
/// <summary>
/// Sets the default assembly from which to load assets for which no assembly is specified.
/// </summary>
/// <param name="assembly">The default assembly.</param>
public void SetDefaultAssembly(Assembly assembly)
{
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
/// Checks if an asset with the specified URI exists.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>True if the asset could be found; otherwise false.</returns>
public bool Exists(Uri uri, Uri? baseUri = null)
{
return TryGetAsset(uri, baseUri, out _);
}
/// <summary>
/// Opens the asset with the requested URI.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>A stream containing the asset contents.</returns>
/// <exception cref="FileNotFoundException">
/// The asset could not be found.
/// </exception>
public Stream Open(Uri uri, Uri? baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1;
/// <summary>
/// Opens the asset with the requested URI and returns the asset stream and the
/// assembly containing the asset.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>
/// The stream containing the resource contents together with the assembly.
/// </returns>
/// <exception cref="FileNotFoundException">
/// The asset could not be found.
/// </exception>
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri? baseUri = null)
{
if (TryGetAsset(uri, baseUri, out var assetDescriptor))
{
return (assetDescriptor.GetStream(), assetDescriptor.Assembly);
}
throw new FileNotFoundException($"The resource {uri} could not be found.");
}
public Assembly? GetAssembly(Uri uri, Uri? baseUri)
{
if (!uri.IsAbsoluteUri && baseUri != null)
{
uri = new Uri(baseUri, uri);
}
if (TryGetAssembly(uri, out var assemblyDescriptor))
{
return assemblyDescriptor.Assembly;
}
return null;
}
/// <summary>
/// Gets all assets of a folder and subfolders that match specified uri.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">Base URI that is used if <paramref name="uri"/> is relative.</param>
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
public IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri)
{
if (uri.IsAbsoluteResm())
{
if (!TryGetAssembly(uri, out var assembly))
{
assembly = _defaultResmAssembly;
}
return assembly?.Resources?
.Where(x => x.Key.Contains(uri.GetUnescapeAbsolutePath()))
.Select(x => new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ??
Enumerable.Empty<Uri>();
}
uri = uri.EnsureAbsolute(baseUri);
if (uri.IsAvares())
{
if (!TryGetResAsmAndPath(uri, out var assembly, out var path))
{
return Enumerable.Empty<Uri>();
}
if (assembly?.AvaloniaResources == null)
{
return Enumerable.Empty<Uri>();
}
if (path.Length > 0 && path[path.Length - 1] != '/')
{
path += '/';
}
return assembly.AvaloniaResources
.Where(r => r.Key.StartsWith(path, StringComparison.Ordinal))
.Select(x => new Uri($"avares://{assembly.Name}{x.Key}"));
}
return Enumerable.Empty<Uri>();
}
private bool TryGetAsset(Uri uri, Uri? baseUri, [NotNullWhen(true)] out IAssetDescriptor? assetDescriptor)
{
assetDescriptor = null;
if (uri.IsAbsoluteResm())
{
if (!TryGetAssembly(uri, out var assembly) && !TryGetAssembly(baseUri, out assembly))
{
assembly = _defaultResmAssembly;
}
if (assembly?.Resources != null)
{
var resourceKey = uri.AbsolutePath;
if (assembly.Resources.TryGetValue(resourceKey, out assetDescriptor))
{
return true;
}
}
}
uri = uri.EnsureAbsolute(baseUri);
if (uri.IsAvares())
{
if (TryGetResAsmAndPath(uri, out var assembly, out var path))
{
if (assembly.AvaloniaResources == null)
{
return false;
}
if (assembly.AvaloniaResources.TryGetValue(path, out assetDescriptor))
{
return true;
}
}
}
return false;
}
private bool TryGetResAsmAndPath(Uri uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly, out string path)
{
path = uri.GetUnescapeAbsolutePath();
if (TryLoadAssembly(uri.Authority, out assembly))
{
return true;
}
return false;
}
private bool TryGetAssembly(Uri? uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly)
{
assembly = null;
if (uri != null)
{
if (!uri.IsAbsoluteUri)
{
return false;
}
if (uri.IsAvares() && TryGetResAsmAndPath(uri, out assembly, out _))
{
return true;
}
if (uri.IsResm())
{
var assemblyName = uri.GetAssemblyNameFromQuery();
if (assemblyName.Length > 0 && TryLoadAssembly(assemblyName, out assembly))
{
return true;
}
}
}
return false;
}
private bool TryLoadAssembly(string assemblyName, [NotNullWhen(true)] out IAssemblyDescriptor? assembly)
{
assembly = null;
try
{
assembly = _assemblyDescriptorResolver.GetAssembly(assemblyName);
return true;
}
catch (Exception) { }
return false;
}
}

2
src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs

@ -14,7 +14,7 @@ namespace Avalonia.Platform
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))
.Bind<IAssetLoader>().ToConstant(new StandardAssetLoader(assembly))
.Bind<IDynamicLibraryLoader>().ToConstant(
#if NET6_0_OR_GREATER
new Net6Loader()

27
src/Avalonia.Base/Platform/Storage/NoopStorageProvider.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Platform.Storage.FileIO;
namespace Avalonia.Platform.Storage;
internal class NoopStorageProvider : BclStorageProvider
{
public override bool CanOpen => false;
public override Task<IReadOnlyList<IStorageFile>> OpenFilePickerAsync(FilePickerOpenOptions options)
{
return Task.FromResult<IReadOnlyList<IStorageFile>>(Array.Empty<IStorageFile>());
}
public override bool CanSave => false;
public override Task<IStorageFile?> SaveFilePickerAsync(FilePickerSaveOptions options)
{
return Task.FromResult<IStorageFile?>(null);
}
public override bool CanPickFolder => false;
public override Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)
{
return Task.FromResult<IReadOnlyList<IStorageFolder>>(Array.Empty<IStorageFolder>());
}
}

5
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@ -143,11 +143,6 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
_impl.PopBitmapBlendMode();
}
public void Custom(ICustomDrawOperation custom)
{
_impl.Custom(custom);
}
public object? GetFeature(Type t) => _impl.GetFeature(t);

14
src/Avalonia.Base/Rendering/SceneGraph/CustomDrawOperation.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Logging;
using Avalonia.Media;
using Avalonia.Platform;
@ -17,7 +18,16 @@ namespace Avalonia.Rendering.SceneGraph
public override void Render(IDrawingContextImpl context)
{
Custom.Render(context);
using var immediateDrawingContext = new ImmediateDrawingContext(context, false);
try
{
Custom.Render(immediateDrawingContext);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, LogArea.Visual)
?.Log(Custom, $"Exception in {Custom.GetType().Name}.{nameof(ICustomDrawOperation.Render)} {{0}}", e);
}
}
public override void Dispose() => Custom.Dispose();
@ -48,6 +58,6 @@ namespace Avalonia.Rendering.SceneGraph
/// Renders the node to a drawing context.
/// </summary>
/// <param name="context">The drawing context.</param>
void Render(IDrawingContextImpl context);
void Render(ImmediateDrawingContext context);
}
}

1
src/Avalonia.Base/StyledElement.cs

@ -289,6 +289,7 @@ namespace Avalonia
public StyledElement? Parent { get; private set; }
/// <inheritdoc />
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1030:StyledProperty accessors should not have side effects", Justification = "False positive?")]
public ThemeVariant ActualThemeVariant => GetValue(ThemeVariant.ActualThemeVariantProperty);
/// <summary>

1
src/Avalonia.Base/Styling/IThemeVariantHost.cs

@ -7,7 +7,6 @@ namespace Avalonia.Styling;
/// <summary>
/// Interface for the host element with a theme variant.
/// </summary>
[Unstable]
public interface IThemeVariantHost : IResourceHost
{
/// <summary>

4
src/Avalonia.Base/Styling/ThemeVariant.cs

@ -9,6 +9,10 @@ namespace Avalonia.Styling;
/// Specifies a UI theme variant that should be used for the Control and Application types.
/// </summary>
[TypeConverter(typeof(ThemeVariantTypeConverter))]
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010:AvaloniaProperty objects should be owned by the type in which they are stored",
Justification = "ActualThemeVariant and RequestedThemeVariant properties are shared Avalonia.Base and Avalonia.Controls projects," +
"but shouldn't be visible on the StyledElement class." +
"Ideally we woould introduce readonly styled properties.")]
public sealed record ThemeVariant
{
/// <summary>

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

@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
@ -118,11 +117,11 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<TResult> synchronously on the
/// Executes the specified Func&lt;TResult&gt; synchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <returns>
/// The return value from the delegate being invoked.
@ -136,11 +135,11 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<TResult> synchronously on the
/// Executes the specified Func&lt;TResult&gt; synchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -156,11 +155,11 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<TResult> synchronously on the
/// Executes the specified Func&lt;TResult&gt; synchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -183,11 +182,11 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<TResult> synchronously on the
/// Executes the specified Func&lt;TResult&gt; synchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -249,11 +248,11 @@ public partial class Dispatcher
/// An operation representing the queued delegate to be invoked.
/// </returns>
/// <remarks>
/// Note that the default priority is DispatcherPriority.Normal.
/// Note that the default priority is DispatcherPriority.Default.
/// </remarks>
public DispatcherOperation InvokeAsync(Action callback)
{
return InvokeAsync(callback, DispatcherPriority.Normal, CancellationToken.None);
return InvokeAsync(callback, default, CancellationToken.None);
}
/// <summary>
@ -317,29 +316,29 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<TResult> asynchronously on the
/// Executes the specified Func&lt;TResult&gt; asynchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <returns>
/// An operation representing the queued delegate to be invoked.
/// </returns>
/// <remarks>
/// Note that the default priority is DispatcherPriority.Normal.
/// Note that the default priority is DispatcherPriority.Default.
/// </remarks>
public DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback)
{
return InvokeAsync(callback, DispatcherPriority.Normal, CancellationToken.None);
return InvokeAsync(callback, DispatcherPriority.Default, CancellationToken.None);
}
/// <summary>
/// Executes the specified Func<TResult> asynchronously on the
/// Executes the specified Func&lt;TResult&gt; asynchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -355,11 +354,11 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<TResult> asynchronously on the
/// Executes the specified Func&lt;TResult&gt; asynchronously on the
/// thread that the Dispatcher was created on.
/// </summary>
/// <param name="callback">
/// A Func<TResult> delegate to invoke through the dispatcher.
/// A Func&lt;TResult&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -479,7 +478,7 @@ public partial class Dispatcher
// operation has already started when the timeout expires,
// we still wait for it to complete. This is different
// than simply waiting on the operation with a timeout
// because we are the ones queueing the dispatcher
// because we are the ones queuing the dispatcher
// operation, not the caller. We can't leave the operation
// in a state that it might execute if we return that it did not
// invoke.
@ -492,12 +491,12 @@ public partial class Dispatcher
// Old async semantics return from Wait without
// throwing an exception if the operation was aborted.
// There is no need to test the timout condition, since
// There is no need to test the timeout condition, since
// the old async semantics would just return the result,
// which would be null.
// This should not block because either the operation
// is using the old async sematics, or the operation
// is using the old async semantics, or the operation
// completed successfully.
result = operation.GetResult();
}
@ -543,11 +542,23 @@ public partial class Dispatcher
}
/// <summary>
/// Executes the specified Func<Task> asynchronously on the
/// Executes the specified Func&lt;Task&gt; asynchronously on the
/// thread that the Dispatcher was created on
/// </summary>
/// <param name="callback">
/// A Func<Task> delegate to invoke through the dispatcher.
/// A Func&lt;Task&gt; delegate to invoke through the dispatcher.
/// </param>
/// <returns>
/// An task that completes after the task returned from callback finishes.
/// </returns>
public Task InvokeAsync(Func<Task> callback) => InvokeAsync(callback, DispatcherPriority.Default);
/// <summary>
/// Executes the specified Func&lt;Task&gt; asynchronously on the
/// thread that the Dispatcher was created on
/// </summary>
/// <param name="callback">
/// A Func&lt;Task&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -557,18 +568,36 @@ public partial class Dispatcher
/// <returns>
/// An task that completes after the task returned from callback finishes
/// </returns>
public Task InvokeAsync(Func<Task> callback, DispatcherPriority priority = default)
public Task InvokeAsync(Func<Task> callback, DispatcherPriority priority)
{
_ = callback ?? throw new ArgumentNullException(nameof(callback));
return InvokeAsync<Task>(callback, priority).GetTask().Unwrap();
}
/// <summary>
/// Executes the specified Func&lt;Task&lt;TResult&gt;&gt; asynchronously on the
/// thread that the Dispatcher was created on
/// </summary>
/// <param name="action">
/// A Func&lt;Task&lt;TResult&gt;&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
/// callback is invoked relative to the other pending operations
/// in the Dispatcher.
/// </param>
/// <returns>
/// An task that completes after the task returned from callback finishes
/// </returns>
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> action) =>
InvokeAsync(action, DispatcherPriority.Default);
/// <summary>
/// Executes the specified Func<Task<TResult>> asynchronously on the
/// Executes the specified Func&lt;Task&lt;TResult&gt;&gt; asynchronously on the
/// thread that the Dispatcher was created on
/// </summary>
/// <param name="callback">
/// A Func<Task<TResult>> delegate to invoke through the dispatcher.
/// <param name="action">
/// A Func&lt;Task&lt;TResult&gt;&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
@ -578,7 +607,7 @@ public partial class Dispatcher
/// <returns>
/// An task that completes after the task returned from callback finishes
/// </returns>
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> action, DispatcherPriority priority = default)
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> action, DispatcherPriority priority)
{
_ = action ?? throw new ArgumentNullException(nameof(action));
return InvokeAsync<Task<TResult>>(action, priority).GetTask().Unwrap();
@ -595,4 +624,4 @@ public partial class Dispatcher
_ = action ?? throw new ArgumentNullException(nameof(action));
InvokeAsyncImpl(new SendOrPostCallbackDispatcherOperation(this, priority, action, arg, true), CancellationToken.None);
}
}
}

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

@ -91,31 +91,44 @@ public class DispatcherFrame
internal void Run(IControlledDispatcherImpl impl)
{
// Since the actual platform run loop is controlled by a Cancellation token, we are restarting
// it if frame still needs to run
while (Continue)
RunCore(impl);
}
private void RunCore(IControlledDispatcherImpl impl)
{
if (_isRunning)
throw new InvalidOperationException("This frame is already running");
_isRunning = true;
try
{
_cancellationTokenSource = new CancellationTokenSource();
// Wake up the dispatcher in case it has pending jobs
Dispatcher.RequestProcessing();
impl.RunLoop(_cancellationTokenSource.Token);
}
finally
Dispatcher.VerifyAccess();
// Since the actual platform run loop is controlled by a Cancellation token, we have an
// outer loop that restarts the platform one in case Continue was set to true after being set to false
while (true)
{
_isRunning = false;
_cancellationTokenSource?.Cancel();
_cancellationTokenSource = null;
// Take the instance lock since `Continue` is changed from one too
lock (Dispatcher.InstanceLock)
{
if (!Continue)
return;
if (_isRunning)
throw new InvalidOperationException("This frame is already running");
_cancellationTokenSource = new CancellationTokenSource();
_isRunning = true;
}
try
{
// Wake up the dispatcher in case it has pending jobs
Dispatcher.RequestProcessing();
impl.RunLoop(_cancellationTokenSource.Token);
}
finally
{
lock (Dispatcher.InstanceLock)
{
_isRunning = false;
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
}
}
}
}
internal void MaybeExitOnDispatcherRequest()
{

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

@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
namespace Avalonia.Threading
{
@ -100,7 +101,7 @@ namespace Avalonia.Threading
/// <summary>
/// The job will be processed with the same priority as data binding.
/// </summary>
[Obsolete("WPF compatibility")] public static readonly DispatcherPriority DataBind = new(Layout);
[Obsolete("WPF compatibility"), EditorBrowsable(EditorBrowsableState.Never)] public static readonly DispatcherPriority DataBind = new(Layout);
/// <summary>
/// The job will be processed with normal priority.

5
src/Avalonia.Base/Utilities/SpanHelpers.cs

@ -4,7 +4,10 @@ using System.Runtime.CompilerServices;
namespace Avalonia.Utilities
{
public static class SpanHelpers
#if !BUILDTASK
public
#endif
static class SpanHelpers
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryParseUInt(this ReadOnlySpan<char> span, NumberStyles style, IFormatProvider provider, out uint value)

1
src/Avalonia.Base/Visual.cs

@ -329,6 +329,7 @@ namespace Avalonia
/// <summary>
/// Gets the control's parent visual.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "GetVisualParent extension method is supposed to be used instead.")]
internal Visual? VisualParent => _visualParent;
/// <summary>

5
src/Avalonia.Base/VisualTree/IVisualWithRoundRectClip.cs

@ -1,14 +1,15 @@
using System;
using System.ComponentModel;
namespace Avalonia.VisualTree
{
[Obsolete("Internal API, will be removed in future versions, you've been warned")]
[Obsolete("Internal API, will be removed in future versions, you've been warned"), EditorBrowsable(EditorBrowsableState.Never)]
public interface IVisualWithRoundRectClip
{
/// <summary>
/// Gets a value indicating the corner radius of control's clip bounds
/// </summary>
[Obsolete("Internal API, will be removed in future versions, you've been warned")]
[Obsolete("Internal API, will be removed in future versions, you've been warned"), EditorBrowsable(EditorBrowsableState.Never)]
CornerRadius ClipToBoundsRadius { get; }
}

1
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -115,6 +115,7 @@
</Compile>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />
<Compile Include="..\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" />
<Compile Include="..\Avalonia.Base\Utilities\SpanHelpers.cs" Link="Utilities\SpanHelpers.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
<PackageReference Include="Mono.Cecil" Version="0.11.4" />

26
src/Avalonia.Build.Tasks/SpanCompat.cs

@ -85,31 +85,7 @@ namespace System
{
return TrimStart().TrimEnd();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseUInt(NumberStyles style, IFormatProvider provider, out uint value)
{
return uint.TryParse(ToString(), style, provider, out value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseInt(out int value)
{
return int.TryParse(ToString(), out value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseDouble(NumberStyles style, IFormatProvider provider, out double value)
{
return double.TryParse(ToString(), style, provider, out value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseByte(NumberStyles style, IFormatProvider provider, out byte value)
{
return byte.TryParse(ToString(), style, provider, out value);
}
public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length);
internal int IndexOf(ReadOnlySpan<char> v, StringComparison ordinal, int start = 0)

39
src/Avalonia.Controls/AppBuilder.cs

@ -118,6 +118,43 @@ namespace Avalonia
};
}
/// <summary>
/// Begin configuring an <see cref="Application"/>.
/// Should only be used for testing and design purposes, as it relies on dynamic code.
/// </summary>
/// <param name="entryPointType">
/// Parameter from which <see cref="AppBuilder"/> should be created.
/// It either needs to have BuildAvaloniaApp -> AppBuilder method or inherit Application.
/// </param>
/// <returns>An <see cref="AppBuilder"/> instance. If can't be created, thrown an exception.</returns>
internal static AppBuilder Configure(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
Type entryPointType)
{
var appBuilderObj = entryPointType
.GetMethod(
"BuildAvaloniaApp",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy,
null,
Array.Empty<Type>(),
null)?
.Invoke(null, Array.Empty<object?>());
if (appBuilderObj is AppBuilder appBuilder)
{
return appBuilder;
}
if (typeof(Application).IsAssignableFrom(entryPointType))
{
return Configure(() => (Application)Activator.CreateInstance(entryPointType)!);
}
throw new InvalidOperationException(
$"Unable to create AppBuilder from type {entryPointType.Name}." +
$"Input type either needs to have BuildAvaloniaApp -> AppBuilder method or inherit Application type.");
}
protected AppBuilder Self => this;
public AppBuilder AfterSetup(Action<AppBuilder> callback)
@ -206,7 +243,7 @@ namespace Avalonia
_optionsInitializers += () => { AvaloniaLocator.CurrentMutable.Bind<T>().ToFunc(options); };
return Self;
}
/// <summary>
/// Registers an action that is executed with the current font manager.
/// </summary>

2
src/Avalonia.Controls/Application.cs

@ -94,6 +94,8 @@ namespace Avalonia
}
/// <inheritdoc />
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1031", Justification = "This property is supposed to be a styled readonly property.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1030", Justification = "False positive.")]
public ThemeVariant ActualThemeVariant => GetValue(ActualThemeVariantProperty);
/// <summary>

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -2042,6 +2042,8 @@ namespace Avalonia.Controls
/// <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));

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteFilterMode.cs

@ -9,7 +9,7 @@ namespace Avalonia.Controls
{
/// <summary>
/// Specifies how text in the text box portion of the <see cref="AutoCompleteBox" />
/// control is used to filter items specified by the <see cref="AutoCompleteBox.Items" />
/// control is used to filter items specified by the <see cref="AutoCompleteBox.ItemsSource" />
/// property for display in the drop-down.
/// </summary>
public enum AutoCompleteFilterMode

6
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -17,5 +17,11 @@
<InternalsVisibleTo Include="Avalonia.DesignerSupport, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Diagnostics, PublicKey=$(AvaloniaPublicKey)"/>
<InternalsVisibleTo Include="Avalonia.LeakTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Headless, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Headless.XUnit, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Native, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.X11, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.DesignerSupport.Remote, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Browser, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup>
</Project>

2
src/Avalonia.Controls/ColumnDefinition.cs

@ -46,8 +46,8 @@ namespace Avalonia.Controls
/// <param name="value">The width of the column.</param>
/// <param name="type">The width unit of the column.</param>
public ColumnDefinition(double value, GridUnitType type)
: this(new GridLength(value, type))
{
Width = new GridLength(value, type);
}
/// <summary>

6
src/Avalonia.Controls/ContextMenu.cs

@ -56,13 +56,15 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Placement"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1013",
Justification = "We keep PlacementModeProperty for backward compatibility.")]
public static readonly StyledProperty<PlacementMode> PlacementProperty =
Popup.PlacementProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementMode"/> property.
/// </summary>
[Obsolete("Use the Placement property instead.")]
[Obsolete("Use the Placement property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly StyledProperty<PlacementMode> PlacementModeProperty = PlacementProperty;
/// <summary>
@ -155,7 +157,7 @@ namespace Avalonia.Controls
}
/// <inheritdoc cref="Placement"/>
[Obsolete("Use the Placement property instead.")]
[Obsolete("Use the Placement property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public PlacementMode PlacementMode
{
get => GetValue(PlacementProperty);

12
src/Avalonia.Controls/DefinitionBase.cs

@ -37,7 +37,7 @@ namespace Avalonia.Controls
{
// start with getting SharedSizeGroup value.
// this property is NOT inherited which should result in better overall perf.
if (SharedSizeGroup is { } sharedSizeGroupId && PrivateSharedSizeScope is { } privateSharedSizeScope)
if (SharedSizeGroup is { } sharedSizeGroupId && GetValue(PrivateSharedSizeScopeProperty) is { } privateSharedSizeScope)
{
_sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
_sharedState.AddMember(this);
@ -333,7 +333,7 @@ namespace Avalonia.Controls
if (definition._sharedState == null
&& sharedSizeGroupId != null
&& definition.PrivateSharedSizeScope is { } privateSharedSizeScope)
&& definition.GetValue(PrivateSharedSizeScopeProperty) is { } privateSharedSizeScope)
{
// if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition.
@ -412,14 +412,6 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Private getter of shared state collection dynamic property.
/// </summary>
private SharedSizeScope? PrivateSharedSizeScope
{
get { return GetValue(PrivateSharedSizeScopeProperty); }
}
/// <summary>
/// Convenience accessor to UseSharedMinimum flag
/// </summary>

2
src/Avalonia.Controls/DefinitionList.cs

@ -1,9 +1,11 @@
using System.Collections;
using System.Collections.Specialized;
using Avalonia.Collections;
using Avalonia.Metadata;
namespace Avalonia.Controls
{
[AvaloniaList(Separators = new [] { ",", " " })]
public abstract class DefinitionList<T> : AvaloniaList<T> where T : DefinitionBase
{
public DefinitionList()

2
src/Avalonia.Controls/Documents/Span.cs

@ -18,6 +18,8 @@ namespace Avalonia.Controls.Documents
AvaloniaProperty.Register<Span, InlineCollection>(
nameof(Inlines));
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public Span()
{
Inlines = new InlineCollection

4
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -47,7 +47,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
set
{
_clientSize = value;
Resized?.Invoke(value, PlatformResizeReason.Unspecified);
Resized?.Invoke(value, WindowResizeReason.Unspecified);
}
}
@ -65,7 +65,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
public Action<RawInputEventArgs>? Input { get; set; }
public Action<Rect>? Paint { get; set; }
public Action<Size, PlatformResizeReason>? Resized { get; set; }
public Action<Size, WindowResizeReason>? Resized { get; set; }
public Action<double>? ScalingChanged { get; set; }
public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }

2
src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs

@ -44,7 +44,7 @@ namespace Avalonia.Controls.Primitives
/// Defines the <see cref="OverlayInputPassThroughElement"/> property
/// </summary>
public static readonly StyledProperty<IInputElement?> OverlayInputPassThroughElementProperty =
Popup.OverlayInputPassThroughElementProperty.AddOwner<FlyoutBase>();
Popup.OverlayInputPassThroughElementProperty.AddOwner<PopupFlyoutBase>();
private readonly Lazy<Popup> _popupLazy;
private Rect? _enlargedPopupRect;

48
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
namespace Avalonia.Controls.Generators
{
@ -7,8 +8,8 @@ namespace Avalonia.Controls.Generators
/// </summary>
/// <remarks>
/// When creating a container for an item from a <see cref="VirtualizingPanel"/>, the following
/// method order should be followed:
///
/// process should be followed:
///
/// - <see cref="IsItemItsOwnContainer(Control)"/> should first be called if the item is
/// derived from the <see cref="Control"/> class. If this method returns true then the
/// item itself should be used as the container.
@ -19,9 +20,29 @@ namespace Avalonia.Controls.Generators
/// - The container should then be added to the panel using
/// <see cref="VirtualizingPanel.AddInternalChild(Control)"/>
/// - Finally, <see cref="ItemContainerPrepared(Control, object?, int)"/> should be called.
/// - When the item is ready to be recycled, <see cref="ClearItemContainer(Control)"/> should
/// be called if <see cref="IsItemItsOwnContainer(Control)"/> returned false.
///
/// NOTE: If <see cref="IsItemItsOwnContainer(Control)"/> in the first step above returns true
/// then the above steps should be carried out a single time; the first time the item is
/// displayed. Otherwise the steps should be carried out each time a new container is realized
/// for an item.
///
/// When unrealizing a container, the following process should be followed:
///
/// - If <see cref="IsItemItsOwnContainer(Control)"/> for the item returned true then the item
/// cannot be unrealized or recycled.
/// - Otherwise, <see cref="ClearItemContainer(Control)"/> should be called for the container
/// - If recycling is supported then the container should be added to a recycle pool.
/// - It is assumed that recyclable containers will not be removed from the panel but instead
/// hidden from view using e.g. `container.IsVisible = false`.
///
/// When recycling an unrealized container, the following process should be followed:
///
/// - An element should be taken from the recycle pool.
/// - The container should be made visible.
/// - <see cref="PrepareItemContainer(Control, object?, int)"/> method should be called for the
/// container.
/// - <see cref="ItemContainerPrepared(Control, object?, int)"/> should be called.
///
/// NOTE: Although this class is similar to that found in WPF/UWP, in Avalonia this class only
/// concerns itself with generating and clearing item containers; it does not maintain a
/// record of the currently realized containers, that responsibility is delegated to the
@ -65,7 +86,7 @@ namespace Avalonia.Controls.Generators
/// <param name="index">The index of the item to display.</param>
/// <remarks>
/// If <see cref="IsItemItsOwnContainer(Control)"/> is true for an item, then this method
/// only needs to be called a single time, otherwise this method should be called after the
/// must only be called a single time, otherwise this method must be called after the
/// container is created, and each subsequent time the container is recycled to display a
/// new item.
/// </remarks>
@ -80,10 +101,11 @@ namespace Avalonia.Controls.Generators
/// <param name="item">The item being displayed.</param>
/// <param name="index">The index of the item being displayed.</param>
/// <remarks>
/// This method should be called when a container has been fully prepared and added
/// This method must be called when a container has been fully prepared and added
/// to the logical and visual trees, but may be called before a layout pass has completed.
/// It should be called regardless of the result of
/// <see cref="IsItemItsOwnContainer(Control)"/>.
/// It must be called regardless of the result of
/// <see cref="IsItemItsOwnContainer(Control)"/> but if that method returned true then
/// must be called only a single time.
/// </remarks>
public void ItemContainerPrepared(Control container, object? item, int index) =>
_owner.ItemContainerPrepared(container, item, index);
@ -102,12 +124,18 @@ namespace Avalonia.Controls.Generators
/// Undoes the effects of the <see cref="PrepareItemContainer(Control, object, int)"/> method.
/// </summary>
/// <param name="container">The container control.</param>
/// <remarks>
/// This method must be called when a container is unrealized. The container must have
/// already have been removed from the virtualizing panel's list of realized containers before
/// this method is called. This method must not be called if
/// <see cref="IsItemItsOwnContainer"/> returned true for the item.
/// </remarks>
public void ClearItemContainer(Control container) => _owner.ClearItemContainer(container);
[Obsolete("Use ItemsControl.ContainerFromIndex")]
[Obsolete("Use ItemsControl.ContainerFromIndex"), EditorBrowsable(EditorBrowsableState.Never)]
public Control? ContainerFromIndex(int index) => _owner.ContainerFromIndex(index);
[Obsolete("Use ItemsControl.IndexFromContainer")]
[Obsolete("Use ItemsControl.IndexFromContainer"), EditorBrowsable(EditorBrowsableState.Never)]
public int IndexFromContainer(Control container) => _owner.IndexFromContainer(container);
}
}

7
src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Avalonia.Controls.Generators
{
@ -20,13 +21,13 @@ namespace Avalonia.Controls.Generators
internal TreeContainerIndex(TreeView owner) => _owner = owner;
[Obsolete("Use TreeView.GetRealizedTreeContainers")]
[Obsolete("Use TreeView.GetRealizedTreeContainers"), EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<Control> Containers => _owner.GetRealizedTreeContainers();
[Obsolete("Use TreeView.TreeContainerFromItem")]
[Obsolete("Use TreeView.TreeContainerFromItem"), EditorBrowsable(EditorBrowsableState.Never)]
public Control? ContainerFromItem(object item) => _owner.TreeContainerFromItem(item);
[Obsolete("Use TreeView.TreeItemFromContainer")]
[Obsolete("Use TreeView.TreeItemFromContainer"), EditorBrowsable(EditorBrowsableState.Never)]
public object? ItemFromContainer(Control container) => _owner.TreeItemFromContainer(container);
}
}

3
src/Avalonia.Controls/ItemsControl.cs

@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata;
@ -626,7 +627,7 @@ namespace Avalonia.Controls
/// TreeView to be able to create a <see cref="TreeItemContainerGenerator"/>. Can be
/// removed in 12.0.
/// </remarks>
[Obsolete]
[Obsolete, EditorBrowsable(EditorBrowsableState.Never)]
private protected virtual ItemContainerGenerator CreateItemContainerGenerator()
{
return new ItemContainerGenerator(this);

4
src/Avalonia.Controls/LayoutTransformControl.cs

@ -63,7 +63,7 @@ namespace Avalonia.Controls
{
if (TransformRoot == null || LayoutTransform == null)
{
LayoutTransform = RenderTransform;
SetCurrentValue(LayoutTransformProperty, RenderTransform);
return base.ArrangeOverride(finalSize);
}
@ -176,7 +176,7 @@ namespace Avalonia.Controls
else
{
_renderTransformChangedEvent?.Dispose();
LayoutTransform = null;
ClearValue(LayoutTransformProperty);
}
}
}

8
src/Avalonia.Controls/ListBox.cs

@ -29,18 +29,24 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="SelectedItems"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public static readonly new DirectProperty<SelectingItemsControl, IList?> SelectedItemsProperty =
SelectingItemsControl.SelectedItemsProperty;
/// <summary>
/// Defines the <see cref="Selection"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public static readonly new DirectProperty<SelectingItemsControl, ISelectionModel> SelectionProperty =
SelectingItemsControl.SelectionProperty;
/// <summary>
/// Defines the <see cref="SelectionMode"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public static readonly new StyledProperty<SelectionMode> SelectionModeProperty =
SelectingItemsControl.SelectionModeProperty;
@ -84,6 +90,8 @@ namespace Avalonia.Controls
/// Note that the selection mode only applies to selections made via user interaction.
/// Multiple selections can be made programmatically regardless of the value of this property.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public new SelectionMode SelectionMode
{
get { return base.SelectionMode; }

6
src/Avalonia.Controls/MenuItem.cs

@ -53,12 +53,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<KeyGesture?> InputGestureProperty =
AvaloniaProperty.Register<MenuItem, KeyGesture?>(nameof(InputGesture));
/// <summary>
/// Defines the <see cref="IsSelected"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsSelectedProperty =
SelectingItemsControl.IsSelectedProperty.AddOwner<MenuItem>();
/// <summary>
/// Defines the <see cref="IsSubMenuOpen"/> property.
/// </summary>

3
src/Avalonia.Controls/Platform/Dialogs/ISystemDialogImpl.cs

@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Avalonia.Metadata;
@ -7,7 +8,7 @@ namespace Avalonia.Controls.Platform
/// <summary>
/// Defines a platform-specific system dialog implementation.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")]
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
[Unstable]
public interface ISystemDialogImpl
{

3
src/Avalonia.Controls/Platform/Dialogs/SystemDialogImpl.cs

@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Platform.Storage;
@ -10,7 +11,7 @@ namespace Avalonia.Controls.Platform
/// <summary>
/// Defines a platform-specific system dialog implementation.
/// </summary>
[Obsolete]
[Obsolete, EditorBrowsable(EditorBrowsableState.Never)]
internal class SystemDialogImpl : ISystemDialogImpl
{
public async Task<string[]?> ShowFileDialogAsync(FileDialog dialog, Window parent)

36
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -9,40 +9,6 @@ using Avalonia.Rendering;
namespace Avalonia.Platform
{
/// <summary>
/// Describes the reason for a <see cref="ITopLevelImpl.Resized"/> message.
/// </summary>
public enum PlatformResizeReason
{
/// <summary>
/// The resize reason is unknown or unspecified.
/// </summary>
Unspecified,
/// <summary>
/// The resize was due to the user resizing the window, for example by dragging the
/// window frame.
/// </summary>
User,
/// <summary>
/// The resize was initiated by the application, for example by setting one of the sizing-
/// related properties on <see cref="Window"/> such as <see cref="Layoutable.Width"/> or
/// <see cref="Layoutable.Height"/>.
/// </summary>
Application,
/// <summary>
/// The resize was initiated by the layout system.
/// </summary>
Layout,
/// <summary>
/// The resize was due to a change in DPI.
/// </summary>
DpiChange,
}
/// <summary>
/// Defines a platform-specific top-level window implementation.
/// </summary>
@ -93,7 +59,7 @@ namespace Avalonia.Platform
/// <summary>
/// Gets or sets a method called when the toplevel is resized.
/// </summary>
Action<Size, PlatformResizeReason>? Resized { get; set; }
Action<Size, WindowResizeReason>? Resized { get; set; }
/// <summary>
/// Gets or sets a method called when the toplevel's scaling changes.

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

Loading…
Cancel
Save