Browse Source

Merge branch 'master' into features/NetAnalyzers/CA1822

pull/9189/head
Giuseppe Lippolis 3 years ago
parent
commit
9fbd163b33
  1. 10
      .gitignore
  2. 0
      .ncrunch/Avalonia.Benchmarks.v3.ncrunchproject
  3. 0
      .ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject
  4. 0
      .ncrunch/Avalonia.Browser.v3.ncrunchproject
  5. 0
      .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject
  6. 5
      .ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject
  7. 5
      .ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject
  8. 5
      .ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject
  9. 5
      .ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject
  10. 5
      .ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject
  11. 5
      .ncrunch/ControlCatalog.Browser.v3.ncrunchproject
  12. 5
      .ncrunch/MobileSandbox.v3.ncrunchproject
  13. 54
      Avalonia.sln
  14. 2
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  15. 2
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  16. 5
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  17. 4
      packages/Avalonia/AvaloniaBuildTasks.targets
  18. 14
      samples/BindingDemo/App.xaml
  19. 0
      samples/ControlCatalog.Browser.Blazor/App.razor
  20. 4
      samples/ControlCatalog.Browser.Blazor/App.razor.cs
  21. 6
      samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj
  22. 2
      samples/ControlCatalog.Browser.Blazor/Pages/Index.razor
  23. 2
      samples/ControlCatalog.Browser.Blazor/Program.cs
  24. 0
      samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json
  25. 0
      samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor
  26. 2
      samples/ControlCatalog.Browser.Blazor/_Imports.razor
  27. 0
      samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css
  28. 0
      samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico
  29. 0
      samples/ControlCatalog.Browser.Blazor/wwwroot/index.html
  30. 6
      samples/ControlCatalog.Browser/ControlCatalog.Browser.csproj
  31. 4
      samples/ControlCatalog.Browser/EmbedSample.Browser.cs
  32. 0
      samples/ControlCatalog.Browser/Logo.svg
  33. 4
      samples/ControlCatalog.Browser/Program.cs
  34. 0
      samples/ControlCatalog.Browser/Roots.xml
  35. 0
      samples/ControlCatalog.Browser/app.css
  36. 0
      samples/ControlCatalog.Browser/embed.js
  37. 0
      samples/ControlCatalog.Browser/favicon.ico
  38. 0
      samples/ControlCatalog.Browser/index.html
  39. 0
      samples/ControlCatalog.Browser/main.js
  40. 0
      samples/ControlCatalog.Browser/runtimeconfig.template.json
  41. 9
      samples/ControlCatalog.NetCore/Program.cs
  42. 11
      samples/ControlCatalog.NetCore/Properties/launchSettings.json
  43. 10
      samples/ControlCatalog/ControlCatalog.csproj
  44. 29
      samples/ControlCatalog/Converter/DegToRadConverter.cs
  45. 3
      samples/ControlCatalog/MainView.xaml
  46. 2
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  47. 107
      samples/ControlCatalog/Pages/CustomDrawing.xaml
  48. 67
      samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
  49. 215
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  50. 51
      samples/ControlCatalog/Pages/DataGridPage.xaml
  51. 18
      samples/ControlCatalog/Pages/ExpanderPage.xaml
  52. 6
      samples/ControlCatalog/Pages/ExpanderPage.xaml.cs
  53. 1
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  54. 8
      samples/ControlCatalog/Pages/TabControlPage.xaml
  55. 6
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  56. 36
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  57. 6
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  58. 4
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  59. 25
      src/Android/Avalonia.Android/AvaloniaMainActivity.cs
  60. 24
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  61. 2
      src/Avalonia.Base/Animation/PageSlide.cs
  62. 2
      src/Avalonia.Base/AttachedProperty.cs
  63. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  64. 2
      src/Avalonia.Base/AvaloniaObject.cs
  65. 100
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  66. 24
      src/Avalonia.Base/AvaloniaProperty.cs
  67. 6
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
  68. 4
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
  69. 12
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  70. 2
      src/Avalonia.Base/AvaloniaProperty`1.cs
  71. 4
      src/Avalonia.Base/ClassBindingManager.cs
  72. 2
      src/Avalonia.Base/Controls/Classes.cs
  73. 2
      src/Avalonia.Base/Controls/ISetInheritanceParent.cs
  74. 3
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  75. 4
      src/Avalonia.Base/Data/BindingOperations.cs
  76. 22
      src/Avalonia.Base/Data/BindingPriority.cs
  77. 4
      src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
  78. 2
      src/Avalonia.Base/Data/IBinding.cs
  79. 6
      src/Avalonia.Base/Data/IndexerBinding.cs
  80. 2
      src/Avalonia.Base/Data/InstancedBinding.cs
  81. 2
      src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
  82. 10
      src/Avalonia.Base/DirectProperty.cs
  83. 6
      src/Avalonia.Base/DirectPropertyBase.cs
  84. 79
      src/Avalonia.Base/IAvaloniaObject.cs
  85. 2
      src/Avalonia.Base/IDataContextProvider.cs
  86. 4
      src/Avalonia.Base/IDirectPropertyAccessor.cs
  87. 39
      src/Avalonia.Base/IStyledElement.cs
  88. 4
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  89. 5
      src/Avalonia.Base/Input/DragDropDevice.cs
  90. 2
      src/Avalonia.Base/Input/DragEventArgs.cs
  91. 17
      src/Avalonia.Base/Input/FocusManager.cs
  92. 4
      src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs
  93. 4
      src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs
  94. 33
      src/Avalonia.Base/Input/Gestures.cs
  95. 39
      src/Avalonia.Base/Input/IInputElement.cs
  96. 2
      src/Avalonia.Base/Input/IMainMenu.cs
  97. 17
      src/Avalonia.Base/Input/InputExtensions.cs
  98. 43
      src/Avalonia.Base/Input/KeyboardDevice.cs
  99. 2
      src/Avalonia.Base/Input/KeyboardNavigation.cs
  100. 6
      src/Avalonia.Base/Input/KeyboardNavigationHandler.cs

10
.gitignore

@ -210,9 +210,9 @@ coc-settings.json
.ccls-cache
.ccls
*.map
src/Web/Avalonia.Web.Blazor/wwwroot/*.js
src/Web/Avalonia.Web.Blazor/Interop/Typescript/*.js
src/Browser/Avalonia.Browser.Blazor/wwwroot/*.js
src/Browser/Avalonia.Browser.Blazor/Interop/Typescript/*.js
node_modules
src/Web/Avalonia.Web.Blazor/webapp/package-lock.json
src/Web/Avalonia.Web.Blazor/wwwroot
src/Web/Avalonia.Web/wwwroot
src/Browser/Avalonia.Browser.Blazor/webapp/package-lock.json
src/Browser/Avalonia.Browser.Blazor/wwwroot
src/Browser/Avalonia.Browser/wwwroot

0
.ncrunch/Avalonia.Web.Blazor.v3.ncrunchproject → .ncrunch/Avalonia.Benchmarks.v3.ncrunchproject

0
.ncrunch/Avalonia.Web.v3.ncrunchproject → .ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject

0
.ncrunch/ControlCatalog.Blazor.Web.v3.ncrunchproject → .ncrunch/Avalonia.Browser.v3.ncrunchproject

0
.ncrunch/ControlCatalog.Web.v3.ncrunchproject → .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject

5
.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject

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

5
.ncrunch/ControlCatalog.Browser.v3.ncrunchproject

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

5
.ncrunch/MobileSandbox.v3.ncrunchproject

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

54
Avalonia.sln

@ -198,9 +198,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestApp", "sampl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.IntegrationTests.Appium", "tests\Avalonia.IntegrationTests.Appium\Avalonia.IntegrationTests.Appium.csproj", "{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web.Blazor", "src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj", "{25831348-EB2A-483E-9576-E8F6528674A5}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Browser", "Browser", "{86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}"
EndProject
@ -216,8 +214,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Te
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevGenerators", "src\tools\DevGenerators\DevGenerators.csproj", "{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web", "src\Web\Avalonia.Web\Avalonia.Web.csproj", "{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox", "samples\MobileSandbox\MobileSandbox.csproj", "{3B8519C1-2F51-4F12-A348-120AB91D4532}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Android", "samples\MobileSandbox.Android\MobileSandbox.Android.csproj", "{C90FE60B-B01E-4F35-91D6-379D6966030F}"
@ -226,9 +222,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.iOS", "sample
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Blazor.Web", "samples\ControlCatalog.Blazor.Web\ControlCatalog.Blazor.Web.csproj", "{6A710364-AE6D-40BD-968B-024311527AC2}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{8B3E8405-DE18-4048-A459-9CA4AC3319A2}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser.Blazor", "samples\ControlCatalog.Browser.Blazor\ControlCatalog.Browser.Blazor.csproj", "{90B08091-9BBD-4362-B712-E9F2CC62B218}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -480,10 +480,6 @@ Global
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.Build.0 = Release|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.Build.0 = Release|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -512,10 +508,6 @@ Global
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.Build.0 = Release|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Release|Any CPU.Build.0 = Release|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -533,14 +525,22 @@ Global
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Release|Any CPU.Build.0 = Release|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Release|Any CPU.Build.0 = Release|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.Build.0 = Release|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.Build.0 = Release|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Release|Any CPU.Build.0 = Release|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.Build.0 = Release|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -591,20 +591,20 @@ Global
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{676D6BFD-029D-4E43-BFC7-3892265CE251} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{25831348-EB2A-483E-9576-E8F6528674A5} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{EABE2161-989B-42BF-BD8D-1E34B20C21F1} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{3B8519C1-2F51-4F12-A348-120AB91D4532} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C90FE60B-B01E-4F35-91D6-379D6966030F} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{62D392C9-81CF-487F-92E8-598B2AF3FDCE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{6A710364-AE6D-40BD-968B-024311527AC2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{8B3E8405-DE18-4048-A459-9CA4AC3319A2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4A39637C-9338-4925-A4DB-D072E292EC78} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{15B93A4C-1B46-43F6-B534-7B25B6E99932} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

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

@ -171,9 +171,7 @@
_closed = false;
_isEnabled = true;
[self backingScaleFactor];
[self setOpaque:NO];
[self setBackgroundColor: [NSColor clearColor]];
_isExtended = false;
_isTransitioningToFullScreen = false;

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

@ -90,7 +90,7 @@ BEGIN_INTERFACE_MAP()
virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost **retOut) override;
virtual HRESULT SetBlurEnabled(bool enable) override;
virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override;
virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
IAvnClipboard *clipboard, IAvnDndResultCallback *cb,

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

@ -489,10 +489,11 @@ HRESULT WindowBaseImpl::CreateNativeControlHost(IAvnNativeControlHost **retOut)
return S_OK;
}
HRESULT WindowBaseImpl::SetBlurEnabled(bool enable) {
HRESULT WindowBaseImpl::SetTransparencyMode(AvnWindowTransparencyMode mode) {
START_COM_CALL;
[StandardContainer ShowBlur:enable];
[Window setBackgroundColor: (mode != Transparent ? [NSColor windowBackgroundColor] : [NSColor clearColor])];
[StandardContainer ShowBlur: mode == Blur];
return S_OK;
}

4
packages/Avalonia/AvaloniaBuildTasks.targets

@ -74,7 +74,7 @@
ReportImportance="$(AvaloniaXamlReportImportance)"/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
</Target>
@ -112,7 +112,7 @@
/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
</Target>

14
samples/BindingDemo/App.xaml

@ -2,8 +2,14 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BindingDemo.App">
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Themes.Simple/Accents/BaseLight.xaml"/>
</Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://Avalonia.Themes.Simple/Accents/BaseLight.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

0
samples/ControlCatalog.Blazor.Web/App.razor → samples/ControlCatalog.Browser.Blazor/App.razor

4
samples/ControlCatalog.Blazor.Web/App.razor.cs → samples/ControlCatalog.Browser.Blazor/App.razor.cs

@ -1,7 +1,7 @@
using Avalonia;
using Avalonia.Web.Blazor;
using Avalonia.Browser.Blazor;
namespace ControlCatalog.Blazor.Web;
namespace ControlCatalog.Browser.Blazor;
public partial class App
{

6
samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj → samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj

@ -15,15 +15,15 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj" />
<ProjectReference Include="..\..\src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.props" />
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.targets" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.targets" />
</Project>

2
samples/ControlCatalog.Blazor.Web/Pages/Index.razor → samples/ControlCatalog.Browser.Blazor/Pages/Index.razor

@ -1,5 +1,5 @@
@page "/"
@using Avalonia.Web.Blazor
@using Avalonia.Browser.Blazor
<AvaloniaView />

2
samples/ControlCatalog.Blazor.Web/Program.cs → samples/ControlCatalog.Browser.Blazor/Program.cs

@ -3,7 +3,7 @@ using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using ControlCatalog.Blazor.Web;
using ControlCatalog.Browser.Blazor;
public class Program
{

0
samples/ControlCatalog.Blazor.Web/Properties/launchSettings.json → samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json

0
samples/ControlCatalog.Blazor.Web/Shared/MainLayout.razor → samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor

2
samples/ControlCatalog.Blazor.Web/_Imports.razor → samples/ControlCatalog.Browser.Blazor/_Imports.razor

@ -6,5 +6,5 @@
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using ControlCatalog.Blazor.Web.Shared
@using ControlCatalog.Browser.Blazor.Shared
@using SkiaSharp

0
samples/ControlCatalog.Blazor.Web/wwwroot/css/app.css → samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css

0
samples/ControlCatalog.Blazor.Web/wwwroot/favicon.ico → samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

0
samples/ControlCatalog.Blazor.Web/wwwroot/index.html → samples/ControlCatalog.Browser.Blazor/wwwroot/index.html

6
samples/ControlCatalog.Web/ControlCatalog.Web.csproj → samples/ControlCatalog.Browser/ControlCatalog.Browser.csproj

@ -26,7 +26,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Web\Avalonia.Web\Avalonia.Web.csproj" />
<ProjectReference Include="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
@ -39,6 +39,6 @@
<WasmExtraFilesToDeploy Include="app.css" />
</ItemGroup>
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.props" />
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.targets" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.targets" />
</Project>

4
samples/ControlCatalog.Web/EmbedSample.Browser.cs → samples/ControlCatalog.Browser/EmbedSample.Browser.cs

@ -1,11 +1,11 @@
using System;
using System.Runtime.InteropServices.JavaScript;
using Avalonia.Platform;
using Avalonia.Web;
using Avalonia.Browser;
using ControlCatalog.Pages;
namespace ControlCatalog.Web;
namespace ControlCatalog.Browser;
public class EmbedSampleWeb : INativeDemoControl
{

0
samples/ControlCatalog.Web/Logo.svg → samples/ControlCatalog.Browser/Logo.svg

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

4
samples/ControlCatalog.Web/Program.cs → samples/ControlCatalog.Browser/Program.cs

@ -1,8 +1,8 @@
using System.Runtime.Versioning;
using Avalonia;
using Avalonia.Web;
using Avalonia.Browser;
using ControlCatalog;
using ControlCatalog.Web;
using ControlCatalog.Browser;
[assembly:SupportedOSPlatform("browser")]

0
samples/ControlCatalog.Web/Roots.xml → samples/ControlCatalog.Browser/Roots.xml

0
samples/ControlCatalog.Web/app.css → samples/ControlCatalog.Browser/app.css

0
samples/ControlCatalog.Web/embed.js → samples/ControlCatalog.Browser/embed.js

0
samples/ControlCatalog.Web/favicon.ico → samples/ControlCatalog.Browser/favicon.ico

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

0
samples/ControlCatalog.Web/index.html → samples/ControlCatalog.Browser/index.html

0
samples/ControlCatalog.Web/main.js → samples/ControlCatalog.Browser/main.js

0
samples/ControlCatalog.Web/runtimeconfig.template.json → samples/ControlCatalog.Browser/runtimeconfig.template.json

9
samples/ControlCatalog.NetCore/Program.cs

@ -99,6 +99,15 @@ namespace ControlCatalog.NetCore
SilenceConsole();
return builder.StartLinuxDrm(args, scaling: GetScaling());
}
else if (args.Contains("--dxgi"))
{
builder.With(new Win32PlatformOptions()
{
UseLowLatencyDxgiSwapChain = true,
UseWindowsUIComposition = false
});
return builder.StartWithClassicDesktopLifetime(args);
}
else
return builder.StartWithClassicDesktopLifetime(args);
}

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

@ -0,0 +1,11 @@
{
"profiles": {
"ControlCatalog.NetCore": {
"commandName": "Project"
},
"Dxgi": {
"commandName": "Project",
"commandLineArgs": "--dxgi"
}
}
}

10
samples/ControlCatalog/ControlCatalog.csproj

@ -33,4 +33,14 @@
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
<ItemGroup>
<None Remove="Pages\CustomDrawing.xaml" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Update="Pages\CustomDrawing.xaml">
<Generator></Generator>
</AvaloniaResource>
</ItemGroup>
</Project>

29
samples/ControlCatalog/Converter/DegToRadConverter.cs

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Avalonia.Data.Converters;
namespace ControlCatalog.Converter
{
public class DegToRadConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is double rad)
{
return rad * 180.0d / Math.PI;
}
return 0.0d;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is double deg)
{
return deg / 180.0d * Math.PI;
}
return 0.0d;
}
}
}

3
samples/ControlCatalog/MainView.xaml

@ -66,6 +66,9 @@
<TabItem Header="Cursor" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CursorPage />
</TabItem>
<TabItem Header="Custom Drawing" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CustomDrawing/>
</TabItem>
<TabItem Header="DataGrid"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled">

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

@ -143,7 +143,7 @@ namespace ControlCatalog.Pages
.OfType<AutoCompleteBox>();
}
private bool StringContains(string str, string? query)
private static bool StringContains(string str, string? query)
{
if (query == null) return false;
return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;

107
samples/ControlCatalog/Pages/CustomDrawing.xaml

@ -0,0 +1,107 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:ControlCatalog.Pages"
xmlns:converters="using:ControlCatalog.Converter"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ControlCatalog.Pages.CustomDrawing">
<UserControl.Resources>
<converters:DegToRadConverter x:Key="DegToRadConverter"/>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical">
<TextBlock Text="Translation" HorizontalAlignment="Center"/>
<Grid ColumnDefinitions="*,*"
RowDefinitions="Auto,Auto"
>
<TextBlock Text="Horizontal"/>
<TextBlock Text="Vertical" Grid.Column="1"/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=ViewportCenterX,
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1"
/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=ViewportCenterY,
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1" Grid.Column="1"
/>
</Grid>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Column="1"
>
<TextBlock Text="Rotation" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
>
<Button Content="➖" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="RotateMinus"
/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=Rotation,
Converter={StaticResource DegToRadConverter},
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1" Grid.Column="1"
/>
<Button Content="➕" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="RotatePlus"
/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Column="2"
>
<TextBlock Text="Scale" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
>
<Button Content="➖" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="ZoomOut"
/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=Scale,
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1" Grid.Column="1"
/>
<Button Content="➕" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="ZoomIn"
/>
</StackPanel>
</StackPanel>
<Grid Grid.Row="1" Grid.ColumnSpan="3" ClipToBounds="True">
<local:CustomDrawingExampleControl
x:Name="CustomDrawingControl"
/>
</Grid>
</Grid>
</UserControl>

67
samples/ControlCatalog/Pages/CustomDrawing.xaml.cs

@ -0,0 +1,67 @@
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages
{
public partial class CustomDrawing : UserControl
{
public CustomDrawing()
{
InitializeComponent();
}
private CustomDrawingExampleControl? _customControl;
public CustomDrawingExampleControl CustomDrawingControl
{
get
{
if (_customControl is not null)
return _customControl;
throw new System.Exception("Control did not get initialized");
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
var cntrl = this.FindControl<CustomDrawingExampleControl>("CustomDrawingControl");
if (cntrl != null)
{
_customControl = cntrl;
}
else
{
// be sad about it
}
}
private void RotateMinus (object? sender, RoutedEventArgs e)
{
if (_customControl is null) return;
_customControl.Rotation -= Math.PI / 20.0d;
}
private void RotatePlus(object? sender, RoutedEventArgs e)
{
if (_customControl is null)
return;
_customControl.Rotation += Math.PI / 20.0d;
}
private void ZoomIn(object? sender, RoutedEventArgs e)
{
if (_customControl is null)
return;
_customControl.Scale *= 1.2d;
}
private void ZoomOut(object? sender, RoutedEventArgs e)
{
if (_customControl is null)
return;
_customControl.Scale /= 1.2d;
}
}
}

215
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

@ -0,0 +1,215 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Input;
using Avalonia.Threading;
using Avalonia.Controls.Shapes;
namespace ControlCatalog.Pages
{
public class CustomDrawingExampleControl : Control
{
private Point _cursorPoint;
public StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
public StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation));
/// <summary>
/// Rotation, measured in Radians!
/// </summary>
public double Rotation
{
get => GetValue(RotationProperty);
set
{
double valueToUse = value % (Math.PI * 2);
SetValue(RotationProperty, valueToUse);
}
}
public StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); }
public StyledProperty<double> ViewportCenterXProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterX), 0.0d);
public double ViewportCenterX { get => GetValue(ViewportCenterXProperty); set => SetValue(ViewportCenterXProperty, value); }
private IPen _pen;
private System.Diagnostics.Stopwatch _timeKeeper = System.Diagnostics.Stopwatch.StartNew();
private bool _isPointerCaptured = false;
public CustomDrawingExampleControl()
{
_pen = new Pen(new SolidColorBrush(Colors.Black), lineCap: PenLineCap.Round);
var _arc = new ArcSegment()
{
IsLargeArc = false,
Point = new Point(0, 0),
RotationAngle = 0,
Size = new Size(25, 25),
SweepDirection = SweepDirection.Clockwise,
};
StreamGeometry sg = new StreamGeometry();
var cntx = sg.Open();
cntx.BeginFigure(new Point(-25.0d, -10.0d), false);
cntx.ArcTo(new Point(25.0d, -10.0d), new Size(10.0d, 10.0d), 0.0d, false, SweepDirection.Clockwise);
cntx.EndFigure(true);
_smileGeometry = sg.Clone();
}
private Geometry _smileGeometry;
protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);
Point previousPoint = _cursorPoint;
_cursorPoint = e.GetPosition(this);
if (_isPointerCaptured)
{
Point oldWorldPoint = UIPointToWorldPoint(previousPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
Vector diff = newWorldPoint - oldWorldPoint;
ViewportCenterX -= diff.X;
ViewportCenterY -= diff.Y;
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
e.Handled = true;
e.Pointer.Capture(this);
_isPointerCaptured = true;
base.OnPointerPressed(e);
}
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
base.OnPointerWheelChanged(e);
var oldScale = Scale;
Scale *= (1.0d + e.Delta.Y / 12.0d);
Point oldWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, oldScale, Rotation);
Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
Vector diff = newWorldPoint - oldWorldPoint;
ViewportCenterX -= diff.X;
ViewportCenterY -= diff.Y;
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
e.Pointer.Capture(null);
_isPointerCaptured = false;
base.OnPointerReleased(e);
}
public override void Render(DrawingContext context)
{
var localBounds = new Rect(new Size(this.Bounds.Width, this.Bounds.Height));
var clip = context.PushClip(this.Bounds);
context.DrawRectangle(Brushes.White, _pen, localBounds, 1.0d);
var halfMax = Math.Max(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) * Math.Sqrt(2.0d);
var halfMin = Math.Min(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) / 1.3d;
var halfWidth = this.Bounds.Width / 2.0d;
var halfHeight = this.Bounds.Height / 2.0d;
// 0,0 refers to the top-left of the control now. It is not prime time to draw gui stuff because it'll be under the world
var translateModifier = context.PushPreTransform(Avalonia.Matrix.CreateTranslation(new Avalonia.Vector(halfWidth, halfHeight)));
// now 0,0 refers to the ViewportCenter(X,Y).
var rotationMatrix = Avalonia.Matrix.CreateRotation(Rotation);
var rotationModifier = context.PushPreTransform(rotationMatrix);
// everything is rotated but not scaled
var scaleModifier = context.PushPreTransform(Avalonia.Matrix.CreateScale(Scale, -Scale));
var mapPositionModifier = context.PushPreTransform(Matrix.CreateTranslation(new Vector(-ViewportCenterX, -ViewportCenterY)));
// now everything is rotated and scaled, and at the right position, now we're drawing strictly in world coordinates
context.DrawEllipse(Brushes.White, _pen, new Point(0.0d, 0.0d), 50.0d, 50.0d);
context.DrawLine(_pen, new Point(-25.0d, -5.0d), new Point(-25.0d, 15.0d));
context.DrawLine(_pen, new Point(25.0d, -5.0d), new Point(25.0d, 15.0d));
context.DrawGeometry(null, _pen, _smileGeometry);
Point cursorInWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
context.DrawEllipse(Brushes.Gray, _pen, cursorInWorldPoint, 20.0d, 20.0d);
for (int i = 0; i < 10; i++)
{
double orbitRadius = i * 100 + 200;
var orbitInput = ((_timeKeeper.Elapsed.TotalMilliseconds + 987654d) / orbitRadius) / 10.0d;
if (i % 3 == 0)
orbitInput *= -1;
Point orbitPosition = new Point(Math.Sin(orbitInput) * orbitRadius, Math.Cos(orbitInput) * orbitRadius);
context.DrawEllipse(Brushes.Gray, _pen, orbitPosition, 20.0d, 20.0d);
}
// end drawing the world
mapPositionModifier.Dispose();
scaleModifier.Dispose();
rotationModifier.Dispose();
translateModifier.Dispose();
// this is prime time to draw gui stuff
context.DrawLine(_pen, _cursorPoint + new Vector(-20, 0), _cursorPoint + new Vector(20, 0));
context.DrawLine(_pen, _cursorPoint + new Vector(0, -20), _cursorPoint + new Vector(0, 20));
clip.Dispose();
// oh and draw again when you can, no rush, right?
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
}
private Point UIPointToWorldPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
{
Point workingPoint = new Point(inPoint.X, -inPoint.Y);
workingPoint += new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
workingPoint /= scale;
workingPoint = Matrix.CreateRotation(rotation).Transform(workingPoint);
workingPoint += new Vector(viewportCenterX, viewportCenterY);
return workingPoint;
}
private Point WorldPointToUIPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
{
Point workingPoint = new Point(inPoint.X, inPoint.Y);
workingPoint -= new Vector(viewportCenterX, viewportCenterY);
// undo rotation
workingPoint = Matrix.CreateRotation(-rotation).Transform(workingPoint);
workingPoint *= scale;
workingPoint -= new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
workingPoint = new Point(workingPoint.X, -workingPoint.Y);
return workingPoint;
}
}
}

51
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -14,22 +14,6 @@
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</ControlTheme>
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="DataGridColumnHeader:nth-last-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="DataGridCell:nth-last-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="DataGrid#dataGridGrouping DataGridRow:nth-child(5n+3)">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="DataGrid#dataGridGrouping DataGridRow:nth-last-child(5n+1)">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,Auto,*">
<StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
<TextBlock Classes="h2">A control for displaying and interacting with a data source.</TextBlock>
@ -45,8 +29,7 @@
<CheckBox x:Name="ShowGDP" IsChecked="True" Content="Toggle GDP Column Visibility"
DockPanel.Dock="Top"/>
<DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All"
RowBackground="#1000"
AlternatingRowBackground="#1fff">
RowBackground="#1000">
<DataGrid.Columns>
<!-- Using HeaderTemplate -->
<DataGridTextColumn Header="Country" HeaderTemplate="{StaticResource Demo.DataTemplates.CountryHeader}" Binding="{Binding Name}" Width="6*" x:DataType="local:Country" />
@ -59,6 +42,24 @@
IsVisible="{Binding #ShowGDP.IsChecked}"
x:DataType="local:Country" />
</DataGrid.Columns>
<DataGrid.CellTheme>
<ControlTheme TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<ControlTheme.Children>
<Style Selector="^:nth-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme.Children>
</ControlTheme>
</DataGrid.CellTheme>
<DataGrid.ColumnHeaderTheme>
<ControlTheme TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<ControlTheme.Children>
<Style Selector="^:nth-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme.Children>
</ControlTheme>
</DataGrid.ColumnHeaderTheme>
</DataGrid>
</DockPanel>
</TabItem>
@ -71,6 +72,20 @@
<DataGridTextColumn DisplayIndex="2" Header="Area" Binding="{Binding Area}" Width="3*" x:DataType="local:Country" />
<DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" x:DataType="local:Country" />
</DataGrid.Columns>
<DataGrid.RowTheme>
<ControlTheme TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<ControlTheme.Children>
<Style Selector="^:nth-child(5n+3)">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="^:nth-last-child(5n+1)">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme.Children>
</ControlTheme>
</DataGrid.RowTheme>
</DataGrid>
</TabItem>
<TabItem x:Name="EditableTab" Header="Editable">

18
samples/ControlCatalog/Pages/ExpanderPage.xaml

@ -52,6 +52,24 @@
</StackPanel>
</Expander>
<CheckBox IsChecked="{Binding Rounded}">Rounded</CheckBox>
<Expander x:Name="CollapsingDisabledExpander"
Header="Collapsing Disabled"
IsExpanded="True"
ExpandDirection="Down"
CornerRadius="{Binding CornerRadius}">
<StackPanel>
<TextBlock>Expanded content</TextBlock>
</StackPanel>
</Expander>
<Expander x:Name="ExpandingDisabledExpander"
Header="Expanding Disabled"
IsExpanded="False"
ExpandDirection="Down"
CornerRadius="{Binding CornerRadius}">
<StackPanel>
<TextBlock>Expanded content</TextBlock>
</StackPanel>
</Expander>
</StackPanel>
</StackPanel>
</UserControl>

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

@ -10,6 +10,12 @@ namespace ControlCatalog.Pages
{
this.InitializeComponent();
DataContext = new ExpanderPageViewModel();
var CollapsingDisabledExpander = this.Get<Expander>("CollapsingDisabledExpander");
var ExpandingDisabledExpander = this.Get<Expander>("ExpandingDisabledExpander");
CollapsingDisabledExpander.Collapsing += (s, e) => { e.Handled = true; };
ExpandingDisabledExpander.Expanding += (s, e) => { e.Handled = true; };
}
private void InitializeComponent()

1
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -32,6 +32,7 @@
</StackPanel>
<ListBox Items="{Binding Items}"
Selection="{Binding Selection}"
DisplayMemberBinding="{Binding (viewModels:ItemModel).ID, StringFormat='{}Item {0:N0}'}"
AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}"
SelectionMode="{Binding SelectionMode^}"
WrapSelection="{Binding WrapSelection}"/>

8
samples/ControlCatalog/Pages/TabControlPage.xaml

@ -53,14 +53,8 @@
<TabControl
Items="{Binding Tabs}"
Margin="0 16"
HeaderDisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
TabStripPlacement="{Binding TabPlacement}">
<TabControl.ItemTemplate>
<DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
<TextBlock
Text="{Binding Header}">
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
<StackPanel Orientation="Vertical" Spacing="8">

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

@ -25,13 +25,13 @@ namespace ControlCatalog.Pages
{
Header = "Arch",
Text = "This is the first templated tab page.",
Image = LoadBitmap("avares://ControlCatalog/Assets/delicate-arch-896885_640.jpg"),
Image = TabControlPage.LoadBitmap("avares://ControlCatalog/Assets/delicate-arch-896885_640.jpg"),
},
new TabControlPageViewModelItem
{
Header = "Leaf",
Text = "This is the second templated tab page.",
Image = LoadBitmap("avares://ControlCatalog/Assets/maple-leaf-888807_640.jpg"),
Image = TabControlPage.LoadBitmap("avares://ControlCatalog/Assets/maple-leaf-888807_640.jpg"),
},
new TabControlPageViewModelItem
{
@ -49,7 +49,7 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
private IBitmap LoadBitmap(string uri)
private static IBitmap LoadBitmap(string uri)
{
var assets = AvaloniaLocator.Current!.GetService<IAssetLoader>()!;
return new Bitmap(assets.Open(new Uri(uri)));

36
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
using ControlCatalog.Pages;
using MiniMvvm;
namespace ControlCatalog.ViewModels
@ -20,9 +21,9 @@ namespace ControlCatalog.ViewModels
public ListBoxPageViewModel()
{
Items = new ObservableCollection<string>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
Items = new ObservableCollection<ItemModel>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
Selection = new SelectionModel<string>();
Selection = new SelectionModel<ItemModel>();
Selection.Select(1);
_selectionMode = this.WhenAnyValue(
@ -58,8 +59,8 @@ namespace ControlCatalog.ViewModels
});
}
public ObservableCollection<string> Items { get; }
public SelectionModel<string> Selection { get; }
public ObservableCollection<ItemModel> Items { get; }
public SelectionModel<ItemModel> Selection { get; }
public IObservable<SelectionMode> SelectionMode => _selectionMode;
public bool Multiple
@ -96,6 +97,31 @@ namespace ControlCatalog.ViewModels
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }
private string GenerateItem() => $"Item {_counter++.ToString()}";
private ItemModel GenerateItem() => new ItemModel(_counter ++);
}
/// <summary>
/// An Item model for the <see cref="ListBoxPage"/>
/// </summary>
public class ItemModel
{
/// <summary>
/// Creates a new ItemModel with the given ID
/// </summary>
/// <param name="id">The ID to display</param>
public ItemModel(int id)
{
ID = id;
}
/// <summary>
/// The ID of this Item
/// </summary>
public int ID { get; }
public override string ToString()
{
return $"Item {ID}";
}
}
}

6
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@ -293,10 +293,10 @@ namespace ControlCatalog.ViewModels
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
private static IVisual GetVisualParent(IVisual? from, IVisual? to)
private static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;
var p1 = (from ?? to)!.GetVisualParent();
var p2 = (to ?? from)!.GetVisualParent();
if (p1 != null && p2 != null && p1 != p2)
{

4
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -95,6 +95,10 @@ namespace Avalonia.Android
_imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset);
}
else
{
_imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.ImplicitOnly);
}
}
private void SurroundingTextChanged(object sender, EventArgs e)

25
src/Android/Avalonia.Android/AvaloniaMainActivity.cs

@ -4,9 +4,12 @@ using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android
{
public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler
@ -15,6 +18,7 @@ namespace Avalonia.Android
public Action<int, Result, Intent> ActivityResult { get; set; }
internal AvaloniaView View;
private GlobalLayoutListener _listener;
protected override void OnCreate(Bundle savedInstanceState)
{
@ -32,6 +36,10 @@ namespace Avalonia.Android
base.OnCreate(savedInstanceState);
SetContentView(View);
_listener = new GlobalLayoutListener(View);
View.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener);
}
public object Content
@ -57,6 +65,8 @@ namespace Avalonia.Android
{
View.Content = null;
View.ViewTreeObserver?.RemoveOnGlobalLayoutListener(_listener);
base.OnDestroy();
}
@ -66,5 +76,20 @@ namespace Avalonia.Android
ActivityResult?.Invoke(requestCode, resultCode, data);
}
class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
private AvaloniaView _view;
public GlobalLayoutListener(AvaloniaView view)
{
_view = view;
}
public void OnGlobalLayout()
{
_view.TopLevelImpl?.Resize(_view.TopLevelImpl.ClientSize);
}
}
}
}

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

@ -26,6 +26,7 @@ using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Java.Lang;
using Math = System.Math;
using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@ -63,7 +64,21 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IInputRoot InputRoot { get; private set; }
public virtual Size ClientSize => Size.ToSize(RenderScaling);
public virtual Size ClientSize
{
get
{
AndroidRect rect = new AndroidRect();
AndroidRect intersection = new AndroidRect();
_view.GetWindowVisibleDisplayFrame(intersection);
_view.GetGlobalVisibleRect(rect);
intersection.Intersect(rect);
return new PixelSize(intersection.Right - intersection.Left, intersection.Bottom - intersection.Top).ToSize(RenderScaling);
}
}
public Size? FrameSize => null;
@ -94,7 +109,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
? new CompositingRenderer(root, AndroidPlatform.Compositor)
: AndroidPlatform.Options.UseDeferredRendering
? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService<IRenderLoop>()) { RenderOnlyOnRenderThread = true }
: new ImmediateRenderer(root);
: new ImmediateRenderer((Visual)root);
public virtual void Hide()
{
@ -149,6 +164,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
Resized?.Invoke(size, PlatformResizeReason.Unspecified);
}
internal void Resize(Size size)
{
Resized?.Invoke(size, PlatformResizeReason.Layout);
}
class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo
{
private readonly TopLevelImpl _tl;

2
src/Avalonia.Base/Animation/PageSlide.cs

@ -157,7 +157,7 @@ namespace Avalonia.Animation
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
protected static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;

2
src/Avalonia.Base/AttachedProperty.cs

@ -34,7 +34,7 @@ namespace Avalonia
/// </summary>
/// <typeparam name="TOwner">The owner type.</typeparam>
/// <returns>The property.</returns>
public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : IAvaloniaObject
public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : AvaloniaObject
{
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this);
return this;

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

@ -42,7 +42,6 @@
<InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Benchmarks, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Win32, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Web.Blazor, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Dialogs, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Diagnostics, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />

2
src/Avalonia.Base/AvaloniaObject.cs

@ -16,7 +16,7 @@ namespace Avalonia
/// <remarks>
/// This class is analogous to DependencyObject in WPF.
/// </remarks>
public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
public class AvaloniaObject : IAvaloniaObjectDebug, INotifyPropertyChanged
{
private readonly ValueStore _values;
private AvaloniaObject? _inheritanceParent;

100
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@ -36,7 +36,7 @@ namespace Avalonia
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<object?> GetObservable(this IAvaloniaObject o, AvaloniaProperty property)
public static IObservable<object?> GetObservable(this AvaloniaObject o, AvaloniaProperty property)
{
return new AvaloniaPropertyObservable<object?>(
o ?? throw new ArgumentNullException(nameof(o)),
@ -56,7 +56,7 @@ namespace Avalonia
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<T> GetObservable<T>(this IAvaloniaObject o, AvaloniaProperty<T> property)
public static IObservable<T> GetObservable<T>(this AvaloniaObject o, AvaloniaProperty<T> property)
{
return new AvaloniaPropertyObservable<T>(
o ?? throw new ArgumentNullException(nameof(o)),
@ -76,7 +76,7 @@ namespace Avalonia
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<BindingValue<object?>> GetBindingObservable(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property)
{
return new AvaloniaPropertyBindingObservable<object?>(
@ -98,7 +98,7 @@ namespace Avalonia
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<BindingValue<T>> GetBindingObservable<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property)
{
return new AvaloniaPropertyBindingObservable<T>(
@ -115,11 +115,11 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <returns>
/// An observable which when subscribed pushes the property changed event args
/// each time a <see cref="IAvaloniaObject.PropertyChanged"/> event is raised
/// each time a <see cref="AvaloniaObject.PropertyChanged"/> event is raised
/// for the specified property.
/// </returns>
public static IObservable<AvaloniaPropertyChangedEventArgs> GetPropertyChangedObservable(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property)
{
return new AvaloniaPropertyChangedObservable(
@ -140,7 +140,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<object?> GetSubject(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -163,7 +163,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<T> GetSubject<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -185,7 +185,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<BindingValue<object?>> GetBindingSubject(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -214,7 +214,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<BindingValue<T>> GetBindingSubject<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -241,7 +241,7 @@ namespace Avalonia
/// A disposable which can be used to terminate the binding.
/// </returns>
public static IDisposable Bind<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property,
IObservable<BindingValue<T>> source,
BindingPriority priority = BindingPriority.LocalValue)
@ -250,17 +250,12 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
source = source ?? throw new ArgumentNullException(nameof(source));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
DirectPropertyBase<T> direct => ao.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
DirectPropertyBase<T> direct => target.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
/// <summary>
@ -274,22 +269,17 @@ namespace Avalonia
/// A disposable which can be used to terminate the binding.
/// </returns>
public static IDisposable Bind<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property,
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue)
{
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
DirectPropertyBase<T> direct => ao.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
DirectPropertyBase<T> direct => target.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
/// <summary>
@ -306,7 +296,7 @@ namespace Avalonia
/// </param>
/// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
public static IDisposable Bind(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty property,
IBinding binding,
object? anchor = null)
@ -340,23 +330,17 @@ namespace Avalonia
/// <param name="target">The object.</param>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
public static T GetValue<T>(this IAvaloniaObject target, AvaloniaProperty<T> property)
public static T GetValue<T>(this AvaloniaObject target, AvaloniaProperty<T> property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.GetValue(styled),
DirectPropertyBase<T> direct => ao.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.GetValue(styled),
DirectPropertyBase<T> direct => target.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
/// <summary>
@ -372,15 +356,13 @@ namespace Avalonia
/// For direct properties returns the current value of the property.
/// </remarks>
public static object? GetBaseValue(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property.RouteGetBaseValue(ao);
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
return property.RouteGetBaseValue(target);
}
/// <summary>
@ -396,24 +378,18 @@ namespace Avalonia
/// For direct properties returns the current value of the property.
/// </remarks>
public static Optional<T> GetBaseValue<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.GetBaseValue(styled),
DirectPropertyBase<T> direct => ao.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.GetBaseValue(styled),
DirectPropertyBase<T> direct => target.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
/// <summary>
@ -474,7 +450,7 @@ namespace Avalonia
}
public InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false)

24
src/Avalonia.Base/AvaloniaProperty.cs

@ -38,7 +38,7 @@ namespace Avalonia
Type valueType,
Type ownerType,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool>? notifying = null)
Action<AvaloniaObject, bool>? notifying = null)
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -145,7 +145,7 @@ namespace Avalonia
/// will be true before the property change notifications are sent and false afterwards. This
/// callback is intended to support Control.IsDataContextChanging.
/// </remarks>
public Action<IAvaloniaObject, bool>? Notifying { get; }
public Action<AvaloniaObject, bool>? Notifying { get; }
/// <summary>
/// Gets the integer ID that represents this property.
@ -177,7 +177,7 @@ namespace Avalonia
{
return new IndexerDescriptor
{
Priority = BindingPriority.TemplatedParent,
Priority = BindingPriority.Template,
Property = property,
};
}
@ -238,9 +238,9 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null,
Action<IAvaloniaObject, bool>? notifying = null)
where TOwner : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null,
Action<AvaloniaObject, bool>? notifying = null)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -279,8 +279,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null)
where THost : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where THost : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -316,8 +316,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null)
where THost : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where THost : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -354,7 +354,7 @@ namespace Avalonia
TValue unsetValue = default!,
BindingMode defaultBindingMode = BindingMode.OneWay,
bool enableDataValidation = false)
where TOwner : IAvaloniaObject
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
_ = getter ?? throw new ArgumentNullException(nameof(getter));
@ -415,7 +415,7 @@ namespace Avalonia
/// <returns>
/// The property metadata.
/// </returns>
public AvaloniaPropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
public AvaloniaPropertyMetadata GetMetadata<T>() where T : AvaloniaObject
{
return GetMetadata(typeof(T));
}

6
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs

@ -9,7 +9,7 @@ namespace Avalonia
public abstract class AvaloniaPropertyChangedEventArgs : EventArgs
{
public AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
BindingPriority priority)
{
Sender = sender;
@ -18,7 +18,7 @@ namespace Avalonia
}
internal AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
BindingPriority priority,
bool isEffectiveValueChange)
{
@ -31,7 +31,7 @@ namespace Avalonia
/// Gets the <see cref="AvaloniaObject"/> that the property changed on.
/// </summary>
/// <value>The sender object.</value>
public IAvaloniaObject Sender { get; }
public AvaloniaObject Sender { get; }
/// <summary>
/// Gets the property that changed.

4
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs

@ -16,7 +16,7 @@ namespace Avalonia
/// <param name="newValue">The new value of the property.</param>
/// <param name="priority">The priority of the binding that produced the value.</param>
public AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
AvaloniaProperty<T> property,
Optional<T> oldValue,
BindingValue<T> newValue,
@ -26,7 +26,7 @@ namespace Avalonia
}
internal AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
AvaloniaProperty<T> property,
Optional<T> oldValue,
BindingValue<T> newValue,

12
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -189,7 +189,7 @@ namespace Avalonia
/// </summary>
/// <param name="o">The object.</param>
/// <returns>A collection of <see cref="AvaloniaProperty"/> definitions.</returns>
public IReadOnlyList<AvaloniaProperty> GetRegistered(IAvaloniaObject o)
public IReadOnlyList<AvaloniaProperty> GetRegistered(AvaloniaObject o)
{
_ = o ?? throw new ArgumentNullException(nameof(o));
@ -205,7 +205,7 @@ namespace Avalonia
/// The registered.
/// </returns>
public DirectPropertyBase<T> GetRegisteredDirect<T>(
IAvaloniaObject o,
AvaloniaObject o,
DirectPropertyBase<T> property)
{
return FindRegisteredDirect(o, property) ??
@ -260,7 +260,7 @@ namespace Avalonia
/// <exception cref="InvalidOperationException">
/// The property name contains a '.'.
/// </exception>
public AvaloniaProperty? FindRegistered(IAvaloniaObject o, string name)
public AvaloniaProperty? FindRegistered(AvaloniaObject o, string name)
{
_ = o ?? throw new ArgumentNullException(nameof(o));
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -277,7 +277,7 @@ namespace Avalonia
/// The registered property or null if no matching property found.
/// </returns>
public DirectPropertyBase<T>? FindRegisteredDirect<T>(
IAvaloniaObject o,
AvaloniaObject o,
DirectPropertyBase<T> property)
{
if (property.Owner == o.GetType())
@ -362,7 +362,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <remarks>
/// You won't usually want to call this method directly, instead use the
/// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue}, Action{IAvaloniaObject, bool})"/>
/// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue}, Action{AvaloniaObject, bool})"/>
/// method.
/// </remarks>
public void Register(Type type, AvaloniaProperty property)
@ -413,7 +413,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <remarks>
/// You won't usually want to call this method directly, instead use the
/// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue})"/>
/// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue})"/>
/// method.
/// </remarks>
public void RegisterAttached(Type type, AvaloniaProperty property)

2
src/Avalonia.Base/AvaloniaProperty`1.cs

@ -24,7 +24,7 @@ namespace Avalonia
string name,
Type ownerType,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool>? notifying = null)
Action<AvaloniaObject, bool>? notifying = null)
: base(name, typeof(TValue), ownerType, metadata, notifying)
{
_changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();

4
src/Avalonia.Base/ClassBindingManager.cs

@ -9,7 +9,7 @@ namespace Avalonia
private static readonly Dictionary<string, AvaloniaProperty> s_RegisteredProperties =
new Dictionary<string, AvaloniaProperty>();
public static IDisposable Bind(IStyledElement target, string className, IBinding source, object anchor)
public static IDisposable Bind(StyledElement target, string className, IBinding source, object anchor)
{
if (!s_RegisteredProperties.TryGetValue(className, out var prop))
s_RegisteredProperties[className] = prop = RegisterClassProxyProperty(className);
@ -21,7 +21,7 @@ namespace Avalonia
var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);
prop.Changed.Subscribe(args =>
{
var classes = ((IStyledElement)args.Sender).Classes;
var classes = ((StyledElement)args.Sender).Classes;
classes.Set(className, args.NewValue.GetValueOrDefault());
});

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

@ -6,7 +6,7 @@ using Avalonia.Utilities;
namespace Avalonia.Controls
{
/// <summary>
/// Holds a collection of style classes for an <see cref="IStyledElement"/>.
/// Holds a collection of style classes for an <see cref="StyledElement"/>.
/// </summary>
/// <remarks>
/// Similar to CSS, each control may have any number of styling classes applied.

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

@ -17,6 +17,6 @@ namespace Avalonia.Controls
/// Sets the control's inheritance parent.
/// </summary>
/// <param name="parent">The parent.</param>
void SetParent(IAvaloniaObject? parent);
void SetParent(AvaloniaObject? parent);
}
}

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

@ -2,6 +2,7 @@
using Avalonia.Data.Converters;
using Avalonia.LogicalTree;
using Avalonia.Reactive;
using Avalonia.Styling;
#nullable enable
@ -49,7 +50,7 @@ namespace Avalonia.Controls
return true;
}
current = (current as IStyledElement)?.StylingParent as IResourceNode;
current = (current as IStyleHost)?.StylingParent as IResourceNode;
}
value = null;

4
src/Avalonia.Base/Data/BindingOperations.cs

@ -9,7 +9,7 @@ namespace Avalonia.Data
public static readonly object DoNothing = new DoNothingType();
/// <summary>
/// Applies an <see cref="InstancedBinding"/> a property on an <see cref="IAvaloniaObject"/>.
/// Applies an <see cref="InstancedBinding"/> a property on an <see cref="AvaloniaObject"/>.
/// </summary>
/// <param name="target">The target object.</param>
/// <param name="property">The property to bind.</param>
@ -22,7 +22,7 @@ namespace Avalonia.Data
/// </param>
/// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
public static IDisposable Apply(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty property,
InstancedBinding binding,
object? anchor)

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

@ -1,7 +1,9 @@
using System;
namespace Avalonia.Data
{
/// <summary>
/// The priority of a binding.
/// The priority of a value or binding.
/// </summary>
public enum BindingPriority
{
@ -16,23 +18,22 @@ namespace Avalonia.Data
LocalValue = 0,
/// <summary>
/// A triggered style binding.
/// A triggered style value.
/// </summary>
/// <remarks>
/// A style trigger is a selector such as .class which overrides a
/// <see cref="TemplatedParent"/> binding. In this way, a basic control can have
/// for example a Background from the templated parent which changes when the
/// control has the :pointerover class.
/// <see cref="Template"/> value. In this way, a control can have, e.g. a Background from
/// the template which changes when the control has the :pointerover class.
/// </remarks>
StyleTrigger,
/// <summary>
/// A binding to a property on the templated parent.
/// A value from the control's template.
/// </summary>
TemplatedParent,
Template,
/// <summary>
/// A style binding.
/// A style value.
/// </summary>
Style,
@ -42,8 +43,11 @@ namespace Avalonia.Data
Inherited,
/// <summary>
/// The binding is uninitialized.
/// The value is uninitialized.
/// </summary>
Unset = int.MaxValue,
[Obsolete("Use Template priority")]
TemplatedParent = Template,
}
}

4
src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs

@ -24,7 +24,7 @@ namespace Avalonia.Data.Core
{
try
{
if (Target.TryGetTarget(out var target) && target is IAvaloniaObject obj)
if (Target.TryGetTarget(out var target) && target is AvaloniaObject obj)
{
obj.SetValue(_property, value, priority);
return true;
@ -39,7 +39,7 @@ namespace Avalonia.Data.Core
protected override void StartListeningCore(WeakReference<object?> reference)
{
if (reference.TryGetTarget(out var target) && target is IAvaloniaObject obj)
if (reference.TryGetTarget(out var target) && target is AvaloniaObject obj)
{
_subscription = new AvaloniaPropertyObservable<object?>(obj, _property).Subscribe(ValueChanged);
}

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

@ -24,7 +24,7 @@ namespace Avalonia.Data
/// A <see cref="InstancedBinding"/> or null if the binding could not be resolved.
/// </returns>
InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false);

6
src/Avalonia.Base/Data/IndexerBinding.cs

@ -3,7 +3,7 @@
public class IndexerBinding : IBinding
{
public IndexerBinding(
IAvaloniaObject source,
AvaloniaObject source,
AvaloniaProperty property,
BindingMode mode)
{
@ -12,12 +12,12 @@
Mode = mode;
}
private IAvaloniaObject Source { get; }
private AvaloniaObject Source { get; }
public AvaloniaProperty Property { get; }
private BindingMode Mode { get; }
public InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false)

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

@ -9,7 +9,7 @@ namespace Avalonia.Data
/// <remarks>
/// Whereas an <see cref="IBinding"/> holds a description of a binding such as "Bind to the X
/// property on a control's DataContext"; this class represents a binding that has been
/// *instanced* by calling <see cref="IBinding.Initiate(IAvaloniaObject, AvaloniaProperty, object, bool)"/>
/// *instanced* by calling <see cref="IBinding.Initiate(AvaloniaObject, AvaloniaProperty, object, bool)"/>
/// on a target object.
/// </remarks>
public class InstancedBinding

2
src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs

@ -8,7 +8,7 @@ namespace Avalonia.Diagnostics
public interface IAvaloniaObjectDebug
{
/// <summary>
/// Gets the subscriber list for the <see cref="IAvaloniaObject.PropertyChanged"/>
/// Gets the subscriber list for the <see cref="AvaloniaObject.PropertyChanged"/>
/// event.
/// </summary>
/// <returns>

10
src/Avalonia.Base/DirectProperty.cs

@ -15,7 +15,7 @@ namespace Avalonia
/// allows the avalonia property system to read and write the current value.
/// </remarks>
public class DirectProperty<TOwner, TValue> : DirectPropertyBase<TValue>, IDirectPropertyAccessor
where TOwner : IAvaloniaObject
where TOwner : AvaloniaObject
{
/// <summary>
/// Initializes a new instance of the <see cref="DirectProperty{TOwner, TValue}"/> class.
@ -151,13 +151,13 @@ namespace Avalonia
}
/// <inheritdoc/>
internal override TValue InvokeGetter(IAvaloniaObject instance)
internal override TValue InvokeGetter(AvaloniaObject instance)
{
return Getter((TOwner)instance);
}
/// <inheritdoc/>
internal override void InvokeSetter(IAvaloniaObject instance, BindingValue<TValue> value)
internal override void InvokeSetter(AvaloniaObject instance, BindingValue<TValue> value)
{
if (Setter == null)
{
@ -171,13 +171,13 @@ namespace Avalonia
}
/// <inheritdoc/>
object? IDirectPropertyAccessor.GetValue(IAvaloniaObject instance)
object? IDirectPropertyAccessor.GetValue(AvaloniaObject instance)
{
return Getter((TOwner)instance);
}
/// <inheritdoc/>
void IDirectPropertyAccessor.SetValue(IAvaloniaObject instance, object? value)
void IDirectPropertyAccessor.SetValue(AvaloniaObject instance, object? value)
{
if (Setter == null)
{

6
src/Avalonia.Base/DirectPropertyBase.cs

@ -54,14 +54,14 @@ namespace Avalonia
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>The property value.</returns>
internal abstract TValue InvokeGetter(IAvaloniaObject instance);
internal abstract TValue InvokeGetter(AvaloniaObject instance);
/// <summary>
/// Sets the value of the property on the instance.
/// </summary>
/// <param name="instance">The instance.</param>
/// <param name="value">The value.</param>
internal abstract void InvokeSetter(IAvaloniaObject instance, BindingValue<TValue> value);
internal abstract void InvokeSetter(AvaloniaObject instance, BindingValue<TValue> value);
/// <summary>
/// Gets the unset value for the property on the specified type.
@ -91,7 +91,7 @@ namespace Avalonia
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="metadata">The metadata.</param>
public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : IAvaloniaObject
public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : AvaloniaObject
{
base.OverrideMetadata(typeof(T), metadata);
}

79
src/Avalonia.Base/IAvaloniaObject.cs

@ -1,79 +0,0 @@
using System;
using Avalonia.Data;
using Avalonia.Metadata;
namespace Avalonia
{
/// <summary>
/// Interface for getting/setting <see cref="AvaloniaProperty"/> values on an object.
/// </summary>
[NotClientImplementable]
public interface IAvaloniaObject
{
/// <summary>
/// Raised when a <see cref="AvaloniaProperty"/> value changes on this object.
/// </summary>
event EventHandler<AvaloniaPropertyChangedEventArgs>? PropertyChanged;
/// <summary>
/// Clears an <see cref="AvaloniaProperty"/>'s local value.
/// </summary>
/// <param name="property">The property.</param>
void ClearValue(AvaloniaProperty property);
/// <summary>
/// Gets a <see cref="AvaloniaProperty"/> value.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
object? GetValue(AvaloniaProperty property);
/// <summary>
/// Checks whether a <see cref="AvaloniaProperty"/> is animating.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>True if the property is animating, otherwise false.</returns>
bool IsAnimating(AvaloniaProperty property);
/// <summary>
/// Checks whether a <see cref="AvaloniaProperty"/> is set on this object.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>True if the property is set, otherwise false.</returns>
bool IsSet(AvaloniaProperty property);
/// <summary>
/// Sets a <see cref="AvaloniaProperty"/> value.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <param name="priority">The priority of the value.</param>
/// <returns>
/// An <see cref="IDisposable"/> if setting the property can be undone, otherwise null.
/// </returns>
IDisposable? SetValue(
AvaloniaProperty property,
object? value,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Binds a <see cref="AvaloniaProperty"/> to an observable.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="source">The observable.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
IDisposable Bind(
AvaloniaProperty property,
IObservable<object?> source,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Coerces the specified <see cref="AvaloniaProperty"/>.
/// </summary>
/// <param name="property">The property.</param>
void CoerceValue(AvaloniaProperty property);
}
}

2
src/Avalonia.Base/IDataContextProvider.cs

@ -6,7 +6,7 @@ namespace Avalonia
/// Defines an element with a data context that can be used for binding.
/// </summary>
[NotClientImplementable]
public interface IDataContextProvider : IAvaloniaObject
public interface IDataContextProvider
{
/// <summary>
/// Gets or sets the element's data context.

4
src/Avalonia.Base/IDirectPropertyAccessor.cs

@ -24,13 +24,13 @@ namespace Avalonia
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>The property value.</returns>
object? GetValue(IAvaloniaObject instance);
object? GetValue(AvaloniaObject instance);
/// <summary>
/// Sets the value of the property on the instance.
/// </summary>
/// <param name="instance">The instance.</param>
/// <param name="value">The value.</param>
void SetValue(IAvaloniaObject instance, object? value);
void SetValue(AvaloniaObject instance, object? value);
}
}

39
src/Avalonia.Base/IStyledElement.cs

@ -1,39 +0,0 @@
using System;
using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Styling;
namespace Avalonia
{
[NotClientImplementable]
public interface IStyledElement :
IStyleable,
IStyleHost,
ILogical,
IResourceHost,
IDataContextProvider,
ISupportInitialize
{
/// <summary>
/// Occurs when the control has finished initialization.
/// </summary>
event EventHandler? Initialized;
/// <summary>
/// Gets a value that indicates whether the element has finished initialization.
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Gets or sets the control's styling classes.
/// </summary>
new Classes Classes { get; set; }
/// <summary>
/// Gets the control's logical parent.
/// </summary>
IStyledElement? Parent { get; }
}
}

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

@ -182,13 +182,13 @@ namespace Avalonia.Input
// find all controls who have registered that access key.
var text = e.Key.ToString().ToUpper();
var matches = _registered
.Where(x => x.Item1 == text && x.Item2.IsEffectivelyVisible)
.Where(x => x.Item1 == text && ((Visual)x.Item2).IsEffectivelyVisible)
.Select(x => x.Item2);
// If the menu is open, only match controls in the menu's visual tree.
if (menuIsOpen)
{
matches = matches.Where(x => x is not null && MainMenu!.IsVisualAncestorOf(x));
matches = matches.Where(x => x is not null && ((Visual)MainMenu!).IsVisualAncestorOf((Visual)x));
}
var match = matches.FirstOrDefault();

5
src/Avalonia.Base/Input/DragDropDevice.cs

@ -13,7 +13,8 @@ namespace Avalonia.Input
private static Interactive? GetTarget(IInputRoot root, Point local)
{
var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
var hit = root.InputHitTest(local) as Visual;
var target = hit?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
if (target != null && DragDrop.GetAllowDrop(target))
return target;
return null;
@ -24,7 +25,7 @@ namespace Avalonia.Input
if (target == null)
return DragDropEffects.None;
var p = inputRoot.TranslatePoint(point, target);
var p = ((Visual)inputRoot).TranslatePoint(point, target);
if (!p.HasValue)
return DragDropEffects.None;

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

@ -15,7 +15,7 @@ namespace Avalonia.Input
public KeyModifiers KeyModifiers { get; private set; }
public Point GetPosition(IVisual relativeTo)
public Point GetPosition(Visual relativeTo)
{
var point = new Point(0, 0);

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

@ -185,7 +185,7 @@ namespace Avalonia.Input
/// </summary>
/// <param name="e">The element.</param>
/// <returns>True if the element can be focused.</returns>
private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && e.IsVisible;
private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && IsVisible(e);
/// <summary>
/// Gets the focus scope ancestors of the specified control, traversing popups.
@ -198,14 +198,15 @@ namespace Avalonia.Input
while (c != null)
{
var scope = c as IFocusScope;
if (scope != null && c.VisualRoot?.IsVisible == true)
if (c is IFocusScope scope &&
c is Visual v &&
v.VisualRoot is Visual root &&
root.IsVisible)
{
yield return scope;
}
c = c.GetVisualParent<IInputElement>() ??
c = (c as Visual)?.GetVisualParent<IInputElement>() ??
((c as IHostedVisualTreeRoot)?.Host as IInputElement);
}
}
@ -221,11 +222,11 @@ namespace Avalonia.Input
return;
var ev = (PointerPressedEventArgs)e;
var visual = (IVisual)sender;
var visual = (Visual)sender;
if (sender == e.Source && ev.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
IVisual? element = ev.Pointer?.Captured ?? e.Source as IInputElement;
Visual? element = ev.Pointer?.Captured as Visual ?? e.Source as Visual;
while (element != null)
{
@ -240,5 +241,7 @@ namespace Avalonia.Input
}
}
}
private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true;
}
}

4
src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs

@ -35,8 +35,8 @@ namespace Avalonia.Input.GestureRecognizers
if (_inputElement is ILogical logicalParent && recognizer is ISetLogicalParent logical)
{
logical.SetParent(logicalParent);
if (recognizer is IStyleable styleableRecognizer
&& _inputElement is IStyleable styleableParent)
if (recognizer is StyledElement styleableRecognizer
&& _inputElement is StyledElement styleableParent)
styleableRecognizer.Bind(StyledElement.TemplatedParentProperty,
styleableParent.GetObservable(StyledElement.TemplatedParentProperty));
}

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

@ -72,7 +72,7 @@ namespace Avalonia.Input.GestureRecognizers
EndGesture();
_tracking = e.Pointer;
_gestureId = ScrollGestureEventArgs.GetNextFreeId();
_trackedRootPoint = e.GetPosition(_target);
_trackedRootPoint = e.GetPosition((Visual?)_target);
}
}
@ -86,7 +86,7 @@ namespace Avalonia.Input.GestureRecognizers
{
if (e.Pointer == _tracking)
{
var rootPoint = e.GetPosition(_target);
var rootPoint = e.GetPosition((Visual?)_target);
if (!_scrolling)
{
if (CanHorizontallyScroll && Math.Abs(_trackedRootPoint.X - rootPoint.X) > ScrollStartDistance)

33
src/Avalonia.Base/Input/Gestures.cs

@ -43,7 +43,7 @@ namespace Avalonia.Input
RoutedEvent.Register<PointerDeltaEventArgs>(
"PointerSwipeGesture", RoutingStrategies.Bubble, typeof(Gestures));
private static readonly WeakReference<IInteractive?> s_lastPress = new WeakReference<IInteractive?>(null);
private static readonly WeakReference<object?> s_lastPress = new WeakReference<object?>(null);
private static Point s_lastPressPoint;
static Gestures()
@ -52,32 +52,32 @@ namespace Avalonia.Input
InputElement.PointerReleasedEvent.RouteFinished.Subscribe(PointerReleased);
}
public static void AddTappedHandler(IInteractive element, EventHandler<RoutedEventArgs> handler)
public static void AddTappedHandler(Interactive element, EventHandler<RoutedEventArgs> handler)
{
element.AddHandler(TappedEvent, handler);
}
public static void AddDoubleTappedHandler(IInteractive element, EventHandler<RoutedEventArgs> handler)
public static void AddDoubleTappedHandler(Interactive element, EventHandler<RoutedEventArgs> handler)
{
element.AddHandler(DoubleTappedEvent, handler);
}
public static void AddRightTappedHandler(IInteractive element, EventHandler<RoutedEventArgs> handler)
public static void AddRightTappedHandler(Interactive element, EventHandler<RoutedEventArgs> handler)
{
element.AddHandler(RightTappedEvent, handler);
}
public static void RemoveTappedHandler(IInteractive element, EventHandler<RoutedEventArgs> handler)
public static void RemoveTappedHandler(Interactive element, EventHandler<RoutedEventArgs> handler)
{
element.RemoveHandler(TappedEvent, handler);
}
public static void RemoveDoubleTappedHandler(IInteractive element, EventHandler<RoutedEventArgs> handler)
public static void RemoveDoubleTappedHandler(Interactive element, EventHandler<RoutedEventArgs> handler)
{
element.RemoveHandler(DoubleTappedEvent, handler);
}
public static void RemoveRightTappedHandler(IInteractive element, EventHandler<RoutedEventArgs> handler)
public static void RemoveRightTappedHandler(Interactive element, EventHandler<RoutedEventArgs> handler)
{
element.RemoveHandler(RightTappedEvent, handler);
}
@ -92,20 +92,22 @@ namespace Avalonia.Input
if (ev.Route == RoutingStrategies.Bubble)
{
var e = (PointerPressedEventArgs)ev;
var visual = (IVisual)ev.Source;
var visual = (Visual)ev.Source;
if (e.ClickCount % 2 == 1)
{
s_isDoubleTapped = false;
s_lastPress.SetTarget(ev.Source);
s_lastPressPoint = e.GetPosition((IVisual)ev.Source);
s_lastPressPoint = e.GetPosition((Visual)ev.Source);
}
else if (e.ClickCount % 2 == 0 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
if (s_lastPress.TryGetTarget(out var target) && target == e.Source)
if (s_lastPress.TryGetTarget(out var target) &&
target == e.Source &&
e.Source is Interactive i)
{
s_isDoubleTapped = true;
e.Source.RaiseEvent(new TappedEventArgs(DoubleTappedEvent, e));
i.RaiseEvent(new TappedEventArgs(DoubleTappedEvent, e));
}
}
}
@ -119,9 +121,10 @@ namespace Avalonia.Input
if (s_lastPress.TryGetTarget(out var target) &&
target == e.Source &&
e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right)
e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right &&
e.Source is Interactive i)
{
var point = e.GetCurrentPoint((IVisual)target);
var point = e.GetCurrentPoint((Visual)target);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(s_lastPressPoint, new Size())
@ -131,13 +134,13 @@ namespace Avalonia.Input
{
if (e.InitialPressMouseButton == MouseButton.Right)
{
e.Source.RaiseEvent(new TappedEventArgs(RightTappedEvent, e));
i.RaiseEvent(new TappedEventArgs(RightTappedEvent, e));
}
//s_isDoubleTapped needed here to prevent invoking Tapped event when DoubleTapped is called.
//This behaviour matches UWP behaviour.
else if (s_isDoubleTapped == false)
{
e.Source.RaiseEvent(new TappedEventArgs(TappedEvent, e));
i.RaiseEvent(new TappedEventArgs(TappedEvent, e));
}
}
}

39
src/Avalonia.Base/Input/IInputElement.cs

@ -2,9 +2,6 @@ using System;
using System.Collections.Generic;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using Avalonia.VisualTree;
#nullable enable
namespace Avalonia.Input
{
@ -12,7 +9,7 @@ namespace Avalonia.Input
/// Defines input-related functionality for a control.
/// </summary>
[NotClientImplementable]
public interface IInputElement : IInteractive, IVisual
public interface IInputElement
{
/// <summary>
/// Occurs when the control receives focus.
@ -93,7 +90,12 @@ namespace Avalonia.Input
/// <see cref="IsEnabled"/> value of this control and its parent controls.
/// </remarks>
bool IsEffectivelyEnabled { get; }
/// <summary>
/// Gets a value indicating whether this control and all its parents are visible.
/// </summary>
bool IsEffectivelyVisible { get; }
/// <summary>
/// Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements.
/// </summary>
@ -123,5 +125,32 @@ namespace Avalonia.Input
/// Gets the key bindings for the element.
/// </summary>
List<KeyBinding> KeyBindings { get; }
/// <summary>
/// Adds a handler for the specified routed event.
/// </summary>
/// <param name="routedEvent">The routed event.</param>
/// <param name="handler">The handler.</param>
/// <param name="routes">The routing strategies to listen to.</param>
/// <param name="handledEventsToo">Whether handled events should also be listened for.</param>
/// <returns>A disposable that terminates the event subscription.</returns>
void AddHandler(
RoutedEvent routedEvent,
Delegate handler,
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
bool handledEventsToo = false);
/// <summary>
/// Removes a handler for the specified routed event.
/// </summary>
/// <param name="routedEvent">The routed event.</param>
/// <param name="handler">The handler.</param>
void RemoveHandler(RoutedEvent routedEvent, Delegate handler);
/// <summary>
/// Raises a routed event.
/// </summary>
/// <param name="e">The event args.</param>
void RaiseEvent(RoutedEventArgs e);
}
}

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

@ -9,7 +9,7 @@ namespace Avalonia.Input
/// Defines the interface for a window's main menu.
/// </summary>
[NotClientImplementable]
public interface IMainMenu : IVisual
public interface IMainMenu
{
/// <summary>
/// Gets a value indicating whether the menu is open.

17
src/Avalonia.Base/Input/InputExtensions.cs

@ -12,7 +12,7 @@ namespace Avalonia.Input
/// </summary>
public static class InputExtensions
{
private static readonly Func<IVisual, bool> s_hitTestDelegate = IsHitTestVisible;
private static readonly Func<Visual, bool> s_hitTestDelegate = IsHitTestVisible;
/// <summary>
/// Returns the active input elements at a point on an <see cref="IInputElement"/>.
@ -26,7 +26,8 @@ namespace Avalonia.Input
{
element = element ?? throw new ArgumentNullException(nameof(element));
return element.GetVisualsAt(p, s_hitTestDelegate).Cast<IInputElement>();
return (element as Visual)?.GetVisualsAt(p, s_hitTestDelegate).Cast<IInputElement>() ??
Enumerable.Empty<IInputElement>();
}
/// <summary>
@ -39,7 +40,7 @@ namespace Avalonia.Input
{
element = element ?? throw new ArgumentNullException(nameof(element));
return element.GetVisualAt(p, s_hitTestDelegate) as IInputElement;
return (element as Visual)?.GetVisualAt(p, s_hitTestDelegate) as IInputElement;
}
/// <summary>
@ -55,22 +56,22 @@ namespace Avalonia.Input
public static IInputElement? InputHitTest(
this IInputElement element,
Point p,
Func<IVisual, bool> filter)
Func<Visual, bool> filter)
{
element = element ?? throw new ArgumentNullException(nameof(element));
filter = filter ?? throw new ArgumentNullException(nameof(filter));
return element.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement;
return (element as Visual)?.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement;
}
private static bool IsHitTestVisible(IVisual visual)
private static bool IsHitTestVisible(Visual visual)
{
var element = visual as IInputElement;
return element != null &&
element.IsVisible &&
visual.IsVisible &&
element.IsHitTestVisible &&
element.IsEffectivelyEnabled &&
element.IsAttachedToVisualTree;
visual.IsAttachedToVisualTree;
}
}
}

43
src/Avalonia.Base/Input/KeyboardDevice.cs

@ -3,7 +3,6 @@ using System.Runtime.CompilerServices;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
namespace Avalonia.Input
{
@ -37,18 +36,21 @@ namespace Avalonia.Input
ie.IsKeyboardFocusWithin = false;
}
el = (IInputElement?)el.VisualParent;
el = (IInputElement?)(el as Visual)?.VisualParent;
}
}
private void ClearFocusWithin(IInputElement element, bool clearRoot)
{
foreach (var visual in element.VisualChildren)
if (element is Visual v)
{
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
foreach (var visual in v.VisualChildren)
{
ClearFocusWithin(el, true);
break;
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
{
ClearFocusWithin(el, true);
break;
}
}
}
@ -81,7 +83,7 @@ namespace Avalonia.Input
break;
}
el = el.VisualParent as IInputElement;
el = (el as Visual)?.VisualParent as IInputElement;
}
el = oldElement;
@ -100,18 +102,21 @@ namespace Avalonia.Input
ie.IsKeyboardFocusWithin = true;
}
el = el.VisualParent as IInputElement;
el = (el as Visual)?.VisualParent as IInputElement;
}
}
private void ClearChildrenFocusWithin(IInputElement element, bool clearRoot)
{
foreach (var visual in element.VisualChildren)
if (element is Visual v)
{
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
foreach (var visual in v.VisualChildren)
{
ClearChildrenFocusWithin(el, true);
break;
if (visual is IInputElement el && el.IsKeyboardFocusWithin)
{
ClearChildrenFocusWithin(el, true);
break;
}
}
}
@ -128,11 +133,11 @@ namespace Avalonia.Input
{
if (element != FocusedElement)
{
var interactive = FocusedElement as IInteractive;
var interactive = FocusedElement as Interactive;
if (FocusedElement != null &&
(!FocusedElement.IsAttachedToVisualTree ||
_focusedRoot != element?.VisualRoot as IInputRoot) &&
(!((Visual)FocusedElement).IsAttachedToVisualTree ||
_focusedRoot != ((Visual?)element)?.VisualRoot as IInputRoot) &&
_focusedRoot != null)
{
ClearChildrenFocusWithin(_focusedRoot, true);
@ -140,14 +145,14 @@ namespace Avalonia.Input
SetIsFocusWithin(FocusedElement, element);
_focusedElement = element;
_focusedRoot = _focusedElement?.VisualRoot as IInputRoot;
_focusedRoot = ((Visual?)_focusedElement)?.VisualRoot as IInputRoot;
interactive?.RaiseEvent(new RoutedEventArgs
{
RoutedEvent = InputElement.LostFocusEvent,
});
interactive = element as IInteractive;
interactive = element as Interactive;
interactive?.RaiseEvent(new GotFocusEventArgs
{
@ -191,8 +196,8 @@ namespace Avalonia.Input
KeyModifiers = keyInput.Modifiers.ToKeyModifiers(),
Source = element,
};
IVisual? currentHandler = element;
var currentHandler = element as Visual;
while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown)
{
var bindings = (currentHandler as IInputElement)?.KeyBindings;

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

@ -68,7 +68,7 @@ namespace Avalonia.Input
/// <param name="value">The tab index.</param>
public static void SetTabIndex(IInputElement element, int value)
{
((IAvaloniaObject)element).SetValue(TabIndexProperty, value);
((AvaloniaObject)element).SetValue(TabIndexProperty, value);
}
/// <summary>

6
src/Avalonia.Base/Input/KeyboardNavigationHandler.cs

@ -50,7 +50,7 @@ namespace Avalonia.Input
element = element ?? throw new ArgumentNullException(nameof(element));
// If there's a custom keyboard navigation handler as an ancestor, use that.
var custom = element.FindAncestorOfType<ICustomKeyboardNavigation>(true);
var custom = (element as Visual)?.FindAncestorOfType<ICustomKeyboardNavigation>(true);
if (custom is object && HandlePreCustomNavigation(custom, element, direction, out var ce))
return ce;
@ -156,9 +156,9 @@ namespace Avalonia.Input
NavigationDirection direction,
[NotNullWhen(true)] out IInputElement? result)
{
if (newElement is object)
if (newElement is Visual v)
{
var customHandler = newElement.FindAncestorOfType<ICustomKeyboardNavigation>(true);
var customHandler = v.FindAncestorOfType<ICustomKeyboardNavigation>(true);
if (customHandler is object)
{

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

Loading…
Cancel
Save