Browse Source

Merge branch 'master' into remove-non-ref-resources

pull/10999/head
Max Katz 3 years ago
committed by GitHub
parent
commit
f4c07b31d7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 5
      .ncrunch/Avalonia.Generators.Tests.v3.ncrunchproject
  3. 5
      .ncrunch/Generators.Sandbox.v3.ncrunchproject
  4. 4
      .nuke/build.schema.json
  5. 13
      Avalonia.Desktop.slnf
  6. 38
      Avalonia.sln
  7. 28
      azure-pipelines-integrationtests.yml
  8. 17
      build/SourceGenerators.props
  9. 12
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  10. 46
      native/Avalonia.Native/src/OSX/AvnTextInputMethod.h
  11. 41
      native/Avalonia.Native/src/OSX/AvnTextInputMethod.mm
  12. 20
      native/Avalonia.Native/src/OSX/AvnTextInputMethodDelegate.h
  13. 6
      native/Avalonia.Native/src/OSX/AvnView.h
  14. 91
      native/Avalonia.Native/src/OSX/AvnView.mm
  15. 2
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  16. 2
      native/Avalonia.Native/src/OSX/Screens.mm
  17. 6
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  18. 34
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  19. 2
      native/Avalonia.Native/src/OSX/WindowImpl.h
  20. 17
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  21. 341
      native/Avalonia.Native/src/OSX/platformthreading.mm
  22. 16
      nukebuild/Build.cs
  23. 104
      nukebuild/BuildTasksPatcher.cs
  24. 5
      nukebuild/numerge.config
  25. 10
      packages/Avalonia/Avalonia.csproj
  26. 6
      packages/Avalonia/Avalonia.props
  27. 4
      readme.md
  28. 1
      samples/BindingDemo/BindingDemo.csproj
  29. 4
      samples/BindingDemo/MainWindow.xaml
  30. 2
      samples/ControlCatalog.Android/MainActivity.cs
  31. 2
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  32. 4
      samples/ControlCatalog.Android/Resources/values-night/colors.xml
  33. 2
      samples/ControlCatalog.Android/Resources/values/styles.xml
  34. 9
      samples/ControlCatalog.Browser/app.css
  35. 2
      samples/ControlCatalog.NetCore/Program.cs
  36. 4
      samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
  37. 6
      samples/ControlCatalog.iOS/Info.plist
  38. 4
      samples/ControlCatalog/App.xaml.cs
  39. 15
      samples/ControlCatalog/ControlCatalog.csproj
  40. 5
      samples/ControlCatalog/MainView.xaml
  41. 38
      samples/ControlCatalog/MainView.xaml.cs
  42. 1
      samples/ControlCatalog/MainWindow.xaml.cs
  43. 74
      samples/ControlCatalog/Pages/ClipboardPage.xaml.cs
  44. 35
      samples/ControlCatalog/Pages/ColorPickerPage.xaml
  45. 2
      samples/ControlCatalog/Pages/ComboBoxPage.xaml.cs
  46. 2
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  47. 2
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml
  48. 5
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs
  49. 4
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  50. 2
      samples/ControlCatalog/Pages/CursorPage.xaml
  51. 16
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  52. 16
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  53. 8
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  54. 18
      samples/ControlCatalog/Pages/FlyoutsPage.axaml
  55. 8
      samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs
  56. 11
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  57. 2
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  58. 6
      samples/ControlCatalog/Pages/MenuPage.xaml
  59. 8
      samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs
  60. 6
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  61. 8
      samples/ControlCatalog/Pages/PointerCanvas.cs
  62. 2
      samples/ControlCatalog/Pages/RefreshContainerPage.axaml
  63. 14
      samples/ControlCatalog/Pages/RefreshContainerPage.axaml.cs
  64. 13
      samples/ControlCatalog/Pages/RelativePanelPage.axaml.cs
  65. 222
      samples/ControlCatalog/Pages/ScrollSnapPage.xaml
  66. 68
      samples/ControlCatalog/Pages/ScrollSnapPage.xaml.cs
  67. 290
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml
  68. 37
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs
  69. 2
      samples/ControlCatalog/Pages/TabControlPage.xaml
  70. 2
      samples/ControlCatalog/Pages/TabStripPage.xaml
  71. 20
      samples/ControlCatalog/Pages/ThemePage.axaml.cs
  72. 2
      samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml
  73. 2
      samples/ControlCatalog/Pages/TreeViewPage.xaml
  74. 22
      samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml
  75. 30
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  76. 7
      samples/Generators.Sandbox/App.xaml
  77. 20
      samples/Generators.Sandbox/App.xaml.cs
  78. 10
      samples/Generators.Sandbox/Controls/CustomTextBox.cs
  79. 45
      samples/Generators.Sandbox/Controls/SignUpView.xaml
  80. 54
      samples/Generators.Sandbox/Controls/SignUpView.xaml.cs
  81. 28
      samples/Generators.Sandbox/Generators.Sandbox.csproj
  82. 15
      samples/Generators.Sandbox/Program.cs
  83. 70
      samples/Generators.Sandbox/ViewModels/SignUpViewModel.cs
  84. 9
      samples/Generators.Sandbox/Views/SignUpView.xaml
  85. 28
      samples/Generators.Sandbox/Views/SignUpView.xaml.cs
  86. 1
      samples/GpuInterop/GpuInterop.csproj
  87. 1
      samples/IntegrationTestApp/IntegrationTestApp.csproj
  88. 12
      samples/IntegrationTestApp/MainWindow.axaml
  89. 18
      samples/IntegrationTestApp/MainWindow.axaml.cs
  90. 22
      samples/IntegrationTestApp/Program.cs
  91. 87
      samples/IntegrationTestApp/ShowWindowTest.axaml
  92. 31
      samples/IntegrationTestApp/ShowWindowTest.axaml.cs
  93. 11
      samples/IntegrationTestApp/bundle.sh
  94. 1
      samples/MobileSandbox/MobileSandbox.csproj
  95. 1
      samples/PlatformSanityChecks/PlatformSanityChecks.csproj
  96. 1
      samples/Previewer/Previewer.csproj
  97. 1
      samples/ReactiveUIDemo/ReactiveUIDemo.csproj
  98. 2
      samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
  99. 1
      samples/RenderDemo/RenderDemo.csproj
  100. 2
      samples/SampleControls/HamburgerMenu/HamburgerMenu.cs

1
.gitignore

@ -102,6 +102,7 @@ csx
AppPackages/ AppPackages/
# NCrunch # NCrunch
.NCrunch_*/
_NCrunch_*/ _NCrunch_*/
*.ncrunchsolution.user *.ncrunchsolution.user
nCrunchTemp_* nCrunchTemp_*

5
.ncrunch/Avalonia.Generators.Tests.v3.ncrunchproject

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

5
.ncrunch/Generators.Sandbox.v3.ncrunchproject

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

4
.nuke/build.schema.json

@ -84,11 +84,11 @@
"GenerateCppHeaders", "GenerateCppHeaders",
"Package", "Package",
"RunCoreLibsTests", "RunCoreLibsTests",
"RunDesignerTests",
"RunHtmlPreviewerTests", "RunHtmlPreviewerTests",
"RunLeakTests", "RunLeakTests",
"RunRenderTests", "RunRenderTests",
"RunTests", "RunTests",
"RunToolsTests",
"ZipFiles" "ZipFiles"
] ]
} }
@ -123,11 +123,11 @@
"GenerateCppHeaders", "GenerateCppHeaders",
"Package", "Package",
"RunCoreLibsTests", "RunCoreLibsTests",
"RunDesignerTests",
"RunHtmlPreviewerTests", "RunHtmlPreviewerTests",
"RunLeakTests", "RunLeakTests",
"RunRenderTests", "RunRenderTests",
"RunTests", "RunTests",
"RunToolsTests",
"ZipFiles" "ZipFiles"
] ]
} }

13
Avalonia.Desktop.slnf

@ -8,9 +8,9 @@
"samples\\GpuInterop\\GpuInterop.csproj", "samples\\GpuInterop\\GpuInterop.csproj",
"samples\\IntegrationTestApp\\IntegrationTestApp.csproj", "samples\\IntegrationTestApp\\IntegrationTestApp.csproj",
"samples\\MiniMvvm\\MiniMvvm.csproj", "samples\\MiniMvvm\\MiniMvvm.csproj",
"samples\\ReactiveUIDemo\\ReactiveUIDemo.csproj",
"samples\\SampleControls\\ControlSamples.csproj", "samples\\SampleControls\\ControlSamples.csproj",
"samples\\Sandbox\\Sandbox.csproj", "samples\\Sandbox\\Sandbox.csproj",
"samples\\ReactiveUIDemo\\ReactiveUIDemo.csproj",
"src\\Avalonia.Base\\Avalonia.Base.csproj", "src\\Avalonia.Base\\Avalonia.Base.csproj",
"src\\Avalonia.Build.Tasks\\Avalonia.Build.Tasks.csproj", "src\\Avalonia.Build.Tasks\\Avalonia.Build.Tasks.csproj",
"src\\Avalonia.Controls.ColorPicker\\Avalonia.Controls.ColorPicker.csproj", "src\\Avalonia.Controls.ColorPicker\\Avalonia.Controls.ColorPicker.csproj",
@ -21,6 +21,7 @@
"src\\Avalonia.Desktop\\Avalonia.Desktop.csproj", "src\\Avalonia.Desktop\\Avalonia.Desktop.csproj",
"src\\Avalonia.Diagnostics\\Avalonia.Diagnostics.csproj", "src\\Avalonia.Diagnostics\\Avalonia.Diagnostics.csproj",
"src\\Avalonia.Dialogs\\Avalonia.Dialogs.csproj", "src\\Avalonia.Dialogs\\Avalonia.Dialogs.csproj",
"src\\Avalonia.Fonts.Inter\\Avalonia.Fonts.Inter.csproj",
"src\\Avalonia.FreeDesktop\\Avalonia.FreeDesktop.csproj", "src\\Avalonia.FreeDesktop\\Avalonia.FreeDesktop.csproj",
"src\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj", "src\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
"src\\Avalonia.Headless\\Avalonia.Headless.csproj", "src\\Avalonia.Headless\\Avalonia.Headless.csproj",
@ -37,12 +38,14 @@
"src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj", "src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
"src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj", "src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj",
"src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj", "src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj",
"src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj", "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
"src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj", "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
"src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
"src\\tools\\DevAnalyzers\\DevAnalyzers.csproj", "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
"src\\tools\\DevGenerators\\DevGenerators.csproj", "src\\tools\\DevGenerators\\DevGenerators.csproj",
"src\\tools\\PublicAnalyzers\\Avalonia.Analyzers.csproj", "src\\tools\\PublicAnalyzers\\Avalonia.Analyzers.csproj",
"src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj",
"src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj",
"src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
"tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj", "tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
"tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj", "tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
"tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj", "tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",
@ -62,4 +65,4 @@
"tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj" "tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj"
] ]
} }
} }

38
Avalonia.sln

@ -244,6 +244,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepe
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepeater.UnitTests", "tests\Avalonia.Controls.ItemsRepeater.UnitTests\Avalonia.Controls.ItemsRepeater.UnitTests.csproj", "{F4E36AA8-814E-4704-BC07-291F70F45193}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepeater.UnitTests", "tests\Avalonia.Controls.ItemsRepeater.UnitTests\Avalonia.Controls.ItemsRepeater.UnitTests.csproj", "{F4E36AA8-814E-4704-BC07-291F70F45193}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -555,9 +563,14 @@ Global
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.Build.0 = Release|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.Build.0 = Release|Any CPU
{EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.Build.0 = Debug|Any CPU {EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Release|Any CPU.ActiveCfg = Release|Any CPU {EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -566,10 +579,22 @@ Global
{F4E36AA8-814E-4704-BC07-291F70F45193}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4E36AA8-814E-4704-BC07-291F70F45193}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.Build.0 = Release|Any CPU {F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.ActiveCfg = Release|Any CPU {DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.Build.0 = Release|Any CPU {DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.Build.0 = Release|Any CPU {DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.Build.0 = Release|Any CPU
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}.Release|Any CPU.Build.0 = Release|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.Build.0 = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -635,8 +660,11 @@ Global
{90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098} {90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098} {75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

28
azure-pipelines-integrationtests.yml

@ -1,11 +1,3 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master
jobs: jobs:
- job: Mac - job: Mac
pool: pool:
@ -23,27 +15,41 @@ jobs:
version: 7.0.101 version: 7.0.101
- script: system_profiler SPDisplaysDataType |grep Resolution - script: system_profiler SPDisplaysDataType |grep Resolution
displayName: 'Get Resolution'
- script: | - script: |
arch="x64"
if [[ $(uname -m) == 'arm64' ]]; then
arch="arm64"
fi
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
pkill node pkill node
appium & pkill testmanagerd
appium > appium.out &
pkill IntegrationTestApp pkill IntegrationTestApp
./build.sh CompileNative ./build.sh CompileNative
rm -rf $(osascript -e "POSIX path of (path to application id \"net.avaloniaui.avalonia.integrationtestapp\")") rm -rf $(osascript -e "POSIX path of (path to application id \"net.avaloniaui.avalonia.integrationtestapp\")")
pkill IntegrationTestApp pkill IntegrationTestApp
./samples/IntegrationTestApp/bundle.sh ./samples/IntegrationTestApp/bundle.sh
open -n ./samples/IntegrationTestApp/bin/Debug/net7.0/osx-arm64/publish/IntegrationTestApp.app open -n ./samples/IntegrationTestApp/bin/Debug/net7.0/osx-$arch/publish/IntegrationTestApp.app
pkill IntegrationTestApp pkill IntegrationTestApp
displayName: 'Build IntegrationTestApp'
- task: DotNetCoreCLI@2 - task: DotNetCoreCLI@2
displayName: 'Run Integration Tests'
inputs: inputs:
command: 'test' command: 'test'
projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj' projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj'
arguments: '-l "console;verbosity=detailed"'
- script: | - script: |
pkill IntegrationTestApp pkill IntegrationTestApp
pkill node pkill node
displayName: 'Stop Appium'
- publish: appium.out
displayName: 'Publish appium logs on failure'
condition: failed()
- job: Windows - job: Windows
pool: pool:
@ -67,11 +73,13 @@ jobs:
displayName: 'Start WinAppDriver' displayName: 'Start WinAppDriver'
- task: DotNetCoreCLI@2 - task: DotNetCoreCLI@2
displayName: 'Build IntegrationTestApp'
inputs: inputs:
command: 'build' command: 'build'
projects: 'samples/IntegrationTestApp/IntegrationTestApp.csproj' projects: 'samples/IntegrationTestApp/IntegrationTestApp.csproj'
- task: DotNetCoreCLI@2 - task: DotNetCoreCLI@2
displayName: 'Run Integration Tests'
retryCountOnTaskFailure: 3 retryCountOnTaskFailure: 3
inputs: inputs:
command: 'test' command: 'test'

17
build/SourceGenerators.props

@ -1,5 +1,10 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <PropertyGroup>
<IncludeDevGenerators Condition="'$(IncludeDevGenerators)' == ''">true</IncludeDevGenerators>
<IncludeAvaloniaGenerators Condition="'$(IncludeAvaloniaGenerators)' == ''">false</IncludeAvaloniaGenerators>
</PropertyGroup>
<ItemGroup Condition="'$(IncludeDevGenerators)' == 'true'">
<ProjectReference <ProjectReference
Include="$(MSBuildThisFileDirectory)/../src/tools/DevGenerators/DevGenerators.csproj" Include="$(MSBuildThisFileDirectory)/../src/tools/DevGenerators/DevGenerators.csproj"
OutputItemType="Analyzer" OutputItemType="Analyzer"
@ -7,4 +12,14 @@
PrivateAssets="all" /> PrivateAssets="all" />
<Compile Include="$(MSBuildThisFileDirectory)/../src/Shared/SourceGeneratorAttributes.cs" /> <Compile Include="$(MSBuildThisFileDirectory)/../src/Shared/SourceGeneratorAttributes.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(IncludeAvaloniaGenerators)' == 'true'">
<ProjectReference
Include="../../src/tools/Avalonia.Generators/Avalonia.Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"
PrivateAssets="all" />
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)/../src/tools/Avalonia.Generators/Avalonia.Generators.props"
Condition="'$(IncludeDevGenerators)' == 'true'" />
</Project> </Project>

12
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -44,6 +44,9 @@
5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; }; 5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; }; 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */; }; 855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */; };
8D2F3512292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D2F3511292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h */; };
8D300D65292D0A6800320C49 /* AvnTextInputMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D300D64292D0A6800320C49 /* AvnTextInputMethod.h */; };
8D300D69292E1E5D00320C49 /* AvnTextInputMethod.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8D300D68292E1E5D00320C49 /* AvnTextInputMethod.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; }; AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; }; AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; };
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; }; AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
@ -97,6 +100,9 @@
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; }; 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; };
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; }; 5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; };
855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformBehaviorInhibition.mm; sourceTree = "<group>"; }; 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformBehaviorInhibition.mm; sourceTree = "<group>"; };
8D2F3511292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnTextInputMethodDelegate.h; sourceTree = "<group>"; };
8D300D64292D0A6800320C49 /* AvnTextInputMethod.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnTextInputMethod.h; sourceTree = "<group>"; };
8D300D68292E1E5D00320C49 /* AvnTextInputMethod.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnTextInputMethod.mm; sourceTree = "<group>"; };
AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; }; AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
@ -143,6 +149,9 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */, 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */,
8D2F3511292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h */,
8D300D68292E1E5D00320C49 /* AvnTextInputMethod.mm */,
8D300D64292D0A6800320C49 /* AvnTextInputMethod.h */,
BC11A5BC2608D58F0017BAD0 /* automation.h */, BC11A5BC2608D58F0017BAD0 /* automation.h */,
BC11A5BD2608D58F0017BAD0 /* automation.mm */, BC11A5BD2608D58F0017BAD0 /* automation.mm */,
1A1852DB23E05814008F0DED /* deadlock.mm */, 1A1852DB23E05814008F0DED /* deadlock.mm */,
@ -213,6 +222,8 @@
1839171DCC651B0638603AC4 /* INSWindowHolder.h in Headers */, 1839171DCC651B0638603AC4 /* INSWindowHolder.h in Headers */,
183919D91DB9AAB5D700C2EA /* WindowImpl.h in Headers */, 183919D91DB9AAB5D700C2EA /* WindowImpl.h in Headers */,
18391CF07316F819E76B617C /* IWindowStateChanged.h in Headers */, 18391CF07316F819E76B617C /* IWindowStateChanged.h in Headers */,
8D300D65292D0A6800320C49 /* AvnTextInputMethod.h in Headers */,
8D2F3512292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h in Headers */,
18391C28BF1823B5464FDD36 /* ResizeScope.h in Headers */, 18391C28BF1823B5464FDD36 /* ResizeScope.h in Headers */,
18391ED5F611FF62C45F196D /* AvnView.h in Headers */, 18391ED5F611FF62C45F196D /* AvnView.h in Headers */,
18391E1381E2D5BFD60265A9 /* AutoFitContentView.h in Headers */, 18391E1381E2D5BFD60265A9 /* AutoFitContentView.h in Headers */,
@ -293,6 +304,7 @@
37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */,
855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */, 855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */,
520624B322973F4100C4DCEF /* menu.mm in Sources */, 520624B322973F4100C4DCEF /* menu.mm in Sources */,
8D300D69292E1E5D00320C49 /* AvnTextInputMethod.mm in Sources */,
37A517B32159597E00FBA241 /* Screens.mm in Sources */, 37A517B32159597E00FBA241 /* Screens.mm in Sources */,
1AFD334123E03C4F0042899B /* controlhost.mm in Sources */, 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */,
1A465D10246AB61600C5858B /* dnd.mm in Sources */, 1A465D10246AB61600C5858B /* dnd.mm in Sources */,

46
native/Avalonia.Native/src/OSX/AvnTextInputMethod.h

@ -0,0 +1,46 @@
//
// AvnTextInputMethod.h
// Avalonia.Native.OSX
//
// Created by Benedikt Stebner on 22.11.22.
// Copyright © 2022 Avalonia. All rights reserved.
//
#ifndef AvnTextInputMethod_h
#define AvnTextInputMethod_h
#import <Foundation/Foundation.h>
#include "com.h"
#include "comimpl.h"
#include "avalonia-native.h"
#import "AvnTextInputMethodDelegate.h"
class AvnTextInputMethod: public virtual ComObject, public virtual IAvnTextInputMethod{
private:
id<AvnTextInputMethodDelegate> _inputMethodDelegate;
public:
FORWARD_IUNKNOWN()
BEGIN_INTERFACE_MAP()
INTERFACE_MAP_ENTRY(IAvnTextInputMethod, IID_IAvnTextInputMethod)
END_INTERFACE_MAP()
virtual ~AvnTextInputMethod();
AvnTextInputMethod(id<AvnTextInputMethodDelegate> inputMethodDelegate);
bool IsActive ();
HRESULT SetClient (IAvnTextInputMethodClient* client) override;
virtual void Reset () override;
virtual void SetCursorRect (AvnRect rect) override;
virtual void SetSurroundingText (char* text, int anchorOffset, int cursorOffset) override;
public:
ComPtr<IAvnTextInputMethodClient> Client;
};
#endif /* AvnTextInputMethod_h */

41
native/Avalonia.Native/src/OSX/AvnTextInputMethod.mm

@ -0,0 +1,41 @@
//
// AvnTextInputMethod.mm
// Avalonia.Native.OSX
//
// Created by Benedikt Stebner on 23.11.22.
// Copyright © 2022 Avalonia. All rights reserved.
//
#include "AvnTextInputMethod.h"
AvnTextInputMethod::~AvnTextInputMethod() {
Client = nullptr;
}
AvnTextInputMethod::AvnTextInputMethod(id<AvnTextInputMethodDelegate> inputMethodDelegate) {
_inputMethodDelegate = inputMethodDelegate;
}
bool AvnTextInputMethod::IsActive() {
return Client != nullptr;
}
HRESULT AvnTextInputMethod::SetClient(IAvnTextInputMethodClient *client) {
START_COM_CALL;
Client = client;
return S_OK;
}
void AvnTextInputMethod::Reset() {
}
void AvnTextInputMethod::SetSurroundingText(char* text, int anchorOffset, int cursorOffset) {
[_inputMethodDelegate setText:[NSString stringWithUTF8String:text]];
[_inputMethodDelegate setSelection: anchorOffset : cursorOffset];
}
void AvnTextInputMethod::SetCursorRect(AvnRect rect) {
[_inputMethodDelegate setCursorRect: rect];
}

20
native/Avalonia.Native/src/OSX/AvnTextInputMethodDelegate.h

@ -0,0 +1,20 @@
//
// AvnTextInputMethodHost.h
// Avalonia.Native.OSX
//
// Created by Benedikt Stebner on 24.11.22.
// Copyright © 2022 Avalonia. All rights reserved.
//
#ifndef AvnTextInputMethodHost_h
#define AvnTextInputMethodHost_h
@protocol AvnTextInputMethodDelegate
@required
-(void) setText:(NSString* _Nonnull) text;
-(void) setCursorRect:(AvnRect) cursorRect;
-(void) setSelection: (int) start : (int) end;
@end
#endif /* AvnTextInputMethodHost_h */

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

@ -5,8 +5,6 @@
#pragma once #pragma once
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
#include "common.h" #include "common.h"
#include "WindowImpl.h" #include "WindowImpl.h"
@ -14,7 +12,7 @@
@class AvnAccessibilityElement; @class AvnAccessibilityElement;
@interface AvnView : NSView<NSTextInputClient, NSDraggingDestination> @interface AvnView : NSView<NSTextInputClient, NSDraggingDestination, AvnTextInputMethodDelegate>
-(AvnView* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent; -(AvnView* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent;
-(NSEvent* _Nonnull) lastMouseDownEvent; -(NSEvent* _Nonnull) lastMouseDownEvent;
-(AvnPoint) translateLocalPoint:(AvnPoint)pt; -(AvnPoint) translateLocalPoint:(AvnPoint)pt;
@ -24,4 +22,4 @@
-(AvnPlatformResizeReason) getResizeReason; -(AvnPlatformResizeReason) getResizeReason;
-(void) setResizeReason:(AvnPlatformResizeReason)reason; -(void) setResizeReason:(AvnPlatformResizeReason)reason;
+ (AvnPoint)toAvnPoint:(CGPoint)p; + (AvnPoint)toAvnPoint:(CGPoint)p;
@end @end

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

@ -12,6 +12,7 @@
{ {
ComPtr<WindowBaseImpl> _parent; ComPtr<WindowBaseImpl> _parent;
NSTrackingArea* _area; NSTrackingArea* _area;
NSMutableAttributedString* _markedText;
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed; bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed;
AvnInputModifiers _modifierState; AvnInputModifiers _modifierState;
NSEvent* _lastMouseDownEvent; NSEvent* _lastMouseDownEvent;
@ -20,6 +21,9 @@
NSObject<IRenderTarget>* _renderTarget; NSObject<IRenderTarget>* _renderTarget;
AvnPlatformResizeReason _resizeReason; AvnPlatformResizeReason _resizeReason;
AvnAccessibilityElement* _accessibilityChild; AvnAccessibilityElement* _accessibilityChild;
NSRect _cursorRect;
NSMutableString* _text;
NSRange _selection;
} }
- (void)onClosed - (void)onClosed
@ -127,11 +131,8 @@
[self updateRenderTarget]; [self updateRenderTarget];
auto reason = [self inLiveResize] ? ResizeUser : _resizeReason; auto reason = [self inLiveResize] ? ResizeUser : _resizeReason;
if(_parent->IsShown()) _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}, reason);
{
_parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}, reason);
}
} }
} }
@ -521,7 +522,7 @@
- (void)keyDown:(NSEvent *)event - (void)keyDown:(NSEvent *)event
{ {
[self keyboardEvent:event withType:KeyDown]; [self keyboardEvent:event withType:KeyDown];
[[self inputContext] handleEvent:event]; _lastKeyHandled = [[self inputContext] handleEvent:event];
[super keyDown:event]; [super keyDown:event];
} }
@ -560,27 +561,50 @@
- (BOOL)hasMarkedText - (BOOL)hasMarkedText
{ {
return _lastKeyHandled; return [_markedText length] > 0;
} }
- (NSRange)markedRange - (NSRange)markedRange
{ {
if([_markedText length] > 0)
return NSMakeRange(0, [_markedText length] - 1);
return NSMakeRange(NSNotFound, 0); return NSMakeRange(NSNotFound, 0);
} }
- (NSRange)selectedRange - (NSRange)selectedRange
{ {
return NSMakeRange(NSNotFound, 0); return _selection;
} }
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange - (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{ {
if([string isKindOfClass:[NSAttributedString class]])
{
_markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
}
else
{
_markedText = [[NSMutableAttributedString alloc] initWithString:string];
}
if(!_parent->InputMethod->IsActive()){
return;
}
_parent->InputMethod->Client->SetPreeditText((char*)[_markedText.string UTF8String]);
} }
- (void)unmarkText - (void)unmarkText
{ {
[[_markedText mutableString] setString:@""];
[[self inputContext] discardMarkedText];
if(!_parent->InputMethod->IsActive()){
return;
}
_parent->InputMethod->Client->SetPreeditText(nullptr);
} }
- (NSArray<NSString *> *)validAttributesForMarkedText - (NSArray<NSString *> *)validAttributesForMarkedText
@ -590,30 +614,33 @@
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{ {
return [NSAttributedString new]; return nullptr;
} }
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{ {
if(!_lastKeyHandled) [self unmarkText];
if(_parent != nullptr)
{ {
if(_parent != nullptr) _lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]);
{
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]);
}
} }
[[self inputContext] invalidateCharacterCoordinates];
} }
- (NSUInteger)characterIndexForPoint:(NSPoint)point - (NSUInteger)characterIndexForPoint:(NSPoint)point
{ {
return 0; return NSNotFound;
} }
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{ {
CGRect result = { 0 }; if(!_parent->InputMethod->IsActive()){
return NSZeroRect;
return result; }
return _cursorRect;
} }
- (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id <NSDraggingInfo>)info - (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id <NSDraggingInfo>)info
@ -718,4 +745,28 @@
return [[self accessibilityChild] accessibilityFocusedUIElement]; return [[self accessibilityChild] accessibilityFocusedUIElement];
} }
- (void) setText:(NSString *)text{
[_text setString:text];
[[self inputContext] discardMarkedText];
}
- (void) setSelection:(int)start :(int)end{
_selection = NSMakeRange(start, end - start);
[[self inputContext] invalidateCharacterCoordinates];
}
- (void) setCursorRect:(AvnRect)rect{
NSRect cursorRect = ToNSRect(rect);
NSRect windowRectOnScreen = [[self window] convertRectToScreen:self.frame];
windowRectOnScreen.size = cursorRect.size;
windowRectOnScreen.origin = NSMakePoint(windowRectOnScreen.origin.x + cursorRect.origin.x, windowRectOnScreen.origin.y + self.frame.size.height - cursorRect.origin.y - cursorRect.size.height);
_cursorRect = windowRectOnScreen;
[[self inputContext] invalidateCharacterCoordinates];
}
@end @end

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

@ -394,7 +394,7 @@
- (BOOL)windowShouldZoom:(NSWindow *_Nonnull)window toFrame:(NSRect)newFrame - (BOOL)windowShouldZoom:(NSWindow *_Nonnull)window toFrame:(NSRect)newFrame
{ {
return true; return _parent->CanZoom();
} }
-(void)windowDidResignKey:(NSNotification *)notification -(void)windowDidResignKey:(NSNotification *)notification

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

@ -41,7 +41,7 @@ public:
ret->WorkingArea.X = [screen visibleFrame].origin.x; ret->WorkingArea.X = [screen visibleFrame].origin.x;
ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height; ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height;
ret->Scaling = [screen backingScaleFactor]; ret->Scaling = 1;
ret->IsPrimary = index == 0; ret->IsPrimary = index == 0;

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

@ -8,6 +8,7 @@
#include "rendertarget.h" #include "rendertarget.h"
#include "INSWindowHolder.h" #include "INSWindowHolder.h"
#include "AvnTextInputMethod.h"
@class AutoFitContentView; @class AutoFitContentView;
@class AvnMenu; @class AvnMenu;
@ -103,7 +104,11 @@ BEGIN_INTERFACE_MAP()
id<AvnWindowProtocol> GetWindowProtocol (); id<AvnWindowProtocol> GetWindowProtocol ();
virtual void BringToFront (); virtual void BringToFront ();
virtual HRESULT GetInputMethod(IAvnTextInputMethod **retOut) override;
virtual bool CanZoom() { return false; }
protected: protected:
virtual NSWindowStyleMask CalculateStyleMask() = 0; virtual NSWindowStyleMask CalculateStyleMask() = 0;
virtual void UpdateStyle(); virtual void UpdateStyle();
@ -130,6 +135,7 @@ public:
NSObject <IRenderTarget> *renderTarget; NSObject <IRenderTarget> *renderTarget;
NSWindow * Window; NSWindow * Window;
ComPtr<IAvnWindowBaseEvents> BaseEvents; ComPtr<IAvnWindowBaseEvents> BaseEvents;
ComPtr<AvnTextInputMethod> InputMethod;
AvnView *View; AvnView *View;
}; };

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

@ -4,6 +4,7 @@
// //
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
#include "common.h" #include "common.h"
#include "AvnView.h" #include "AvnView.h"
#include "menu.h" #include "menu.h"
@ -14,6 +15,7 @@
#import "WindowProtocol.h" #import "WindowProtocol.h"
#import "WindowInterfaces.h" #import "WindowInterfaces.h"
#include "WindowBaseImpl.h" #include "WindowBaseImpl.h"
#include "AvnTextInputMethod.h"
WindowBaseImpl::~WindowBaseImpl() { WindowBaseImpl::~WindowBaseImpl() {
@ -28,6 +30,7 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl,
_glContext = gl; _glContext = gl;
renderTarget = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext:gl]; renderTarget = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext:gl];
View = [[AvnView alloc] initWithParent:this]; View = [[AvnView alloc] initWithParent:this];
InputMethod = new AvnTextInputMethod(View);
StandardContainer = [[AutoFitContentView new] initWithContent:View]; StandardContainer = [[AutoFitContentView new] initWithContent:View];
lastPositionSet = { 0, 0 }; lastPositionSet = { 0, 0 };
@ -293,15 +296,24 @@ HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reaso
} }
@try { @try {
if(x != lastSize.width || y != lastSize.height) { if(x != lastSize.width || y != lastSize.height)
lastSize = NSSize{x, y}; {
if (!_shown) { if (!_shown) {
BaseEvents->Resized(AvnSize{x, y}, reason); auto screenSize = [Window screen].visibleFrame.size;
} else if (Window != nullptr) {
[Window setContentSize:lastSize]; if (x > screenSize.width) {
[Window invalidateShadow]; x = screenSize.width;
}
if (y > screenSize.height) {
y = screenSize.height;
}
} }
lastSize = NSSize{x, y};
[Window setContentSize:lastSize];
[Window invalidateShadow];
} }
} }
@finally { @finally {
@ -595,6 +607,14 @@ void WindowBaseImpl::BringToFront()
// do nothing. // do nothing.
} }
HRESULT WindowBaseImpl::GetInputMethod(IAvnTextInputMethod **retOut) {
START_COM_CALL;
*retOut = InputMethod;
return S_OK;
}
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl) extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl)
{ {
@autoreleasepool @autoreleasepool

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

@ -97,6 +97,8 @@ BEGIN_INTERFACE_MAP()
bool CanBecomeKeyWindow (); bool CanBecomeKeyWindow ();
bool CanZoom() override { return _isEnabled && _canResize; }
protected: protected:
virtual NSWindowStyleMask CalculateStyleMask() override; virtual NSWindowStyleMask CalculateStyleMask() override;
void UpdateStyle () override; void UpdateStyle () override;

17
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -54,6 +54,11 @@ HRESULT WindowImpl::Show(bool activate, bool isDialog) {
WindowBaseImpl::Show(activate, isDialog); WindowBaseImpl::Show(activate, isDialog);
GetWindowState(&_actualWindowState); GetWindowState(&_actualWindowState);
if(IsZoomed()) {
_lastWindowState = _actualWindowState;
}
return SetWindowState(_lastWindowState); return SetWindowState(_lastWindowState);
} }
} }
@ -276,10 +281,13 @@ HRESULT WindowImpl::SetDecorations(SystemDecorations value) {
case SystemDecorationsFull: case SystemDecorationsFull:
[Window setHasShadow:YES]; [Window setHasShadow:YES];
[Window setTitleVisibility:NSWindowTitleVisible];
[Window setTitlebarAppearsTransparent:NO];
[Window setTitle:_lastTitle]; [Window setTitle:_lastTitle];
if (!_isClientAreaExtended) {
[Window setTitleVisibility:NSWindowTitleVisible];
[Window setTitlebarAppearsTransparent:NO];
}
if (currentWindowState == Maximized) { if (currentWindowState == Maximized) {
auto newFrame = [Window contentRectForFrameRect:[Window frame]].size; auto newFrame = [Window contentRectForFrameRect:[Window frame]].size;
@ -606,7 +614,8 @@ void WindowImpl::UpdateStyle() {
} }
bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations == SystemDecorationsFull; bool hasTrafficLights = (_decorations == SystemDecorationsFull) &&
(_isClientAreaExtended ? wantsChrome : true);
NSButton* closeButton = [Window standardWindowButton:NSWindowCloseButton]; NSButton* closeButton = [Window standardWindowButton:NSWindowCloseButton];
NSButton* miniaturizeButton = [Window standardWindowButton:NSWindowMiniaturizeButton]; NSButton* miniaturizeButton = [Window standardWindowButton:NSWindowMiniaturizeButton];
@ -617,5 +626,5 @@ void WindowImpl::UpdateStyle() {
[miniaturizeButton setHidden:!hasTrafficLights]; [miniaturizeButton setHidden:!hasTrafficLights];
[miniaturizeButton setEnabled:_isEnabled]; [miniaturizeButton setEnabled:_isEnabled];
[zoomButton setHidden:!hasTrafficLights]; [zoomButton setHidden:!hasTrafficLights];
[zoomButton setEnabled:_isEnabled && _canResize]; [zoomButton setEnabled:CanZoom()];
} }

341
native/Avalonia.Native/src/OSX/platformthreading.mm

@ -1,193 +1,266 @@
#include "common.h" #include "common.h"
class PlatformThreadingInterface; class PlatformThreadingInterface;
class LoopCancellation : public ComSingleObject<IAvnLoopCancellation, &IID_IAvnLoopCancellation>
{
public:
FORWARD_IUNKNOWN()
bool Running = false;
bool Cancelled = false;
bool IsApp = false;
virtual void Cancel() override
{
Cancelled = true;
if(Running)
{
Running = false;
if(![NSThread isMainThread])
{
AddRef();
dispatch_async(dispatch_get_main_queue(), ^{
if(Release() == 0)
return;
Cancel();
});
return;
};
if(IsApp)
[NSApp stop:nil];
else
{
// Wakeup the event loop
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:event atStart:YES];
}
}
};
};
// CFRunLoopTimerSetNextFireDate docs recommend to "create a repeating timer with an initial
// firing time in the distant future (or the initial firing time) and a very large repeat
// interval—on the order of decades or more"
static double distantFutureInterval = (double)50*365*24*3600;
@interface Signaler : NSObject @interface Signaler : NSObject
-(void) setParent: (PlatformThreadingInterface*)parent; -(void) setEvents:(IAvnPlatformThreadingInterfaceEvents*) events;
-(void) signal: (int) priority; -(void) updateTimer:(int)ms;
-(Signaler*) init; -(Signaler*) init;
-(void) destroyObserver;
-(void) signal;
@end @end
@implementation ActionCallback @implementation Signaler
{ {
ComPtr<IAvnActionCallback> _callback; ComPtr<IAvnPlatformThreadingInterfaceEvents> _events;
bool _wakeupDelegateSent;
bool _signaled;
bool _backgroundProcessingRequested;
CFRunLoopObserverRef _observer;
CFRunLoopTimerRef _timer;
}
- (void) checkSignaled
{
bool signaled;
@synchronized (self) {
signaled = _signaled;
_signaled = false;
}
if(signaled)
{
_events->Signaled();
}
} }
- (ActionCallback*) initWithCallback: (IAvnActionCallback*) callback
- (Signaler*) init
{ {
_callback = callback; _observer = CFRunLoopObserverCreateWithHandler(nil,
kCFRunLoopBeforeSources
| kCFRunLoopAfterWaiting
| kCFRunLoopBeforeWaiting
,
true, 0,
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
if(activity == kCFRunLoopBeforeWaiting)
{
bool triggerProcessing;
@synchronized (self) {
triggerProcessing = self->_backgroundProcessingRequested;
self->_backgroundProcessingRequested = false;
}
if(triggerProcessing)
self->_events->ReadyForBackgroundProcessing();
}
[self checkSignaled];
});
CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
_timer = CFRunLoopTimerCreateWithHandler(nil, CFAbsoluteTimeGetCurrent() + distantFutureInterval, distantFutureInterval, 0, 0, ^(CFRunLoopTimerRef timer) {
self->_events->Timer();
});
CFRunLoopAddTimer(CFRunLoopGetMain(), _timer, kCFRunLoopCommonModes);
return self; return self;
} }
- (void) action - (void) destroyObserver
{ {
_callback->Run(); if(_observer != nil)
{
CFRunLoopObserverInvalidate(_observer);
CFRelease(_observer);
_observer = nil;
}
if(_timer != nil)
{
CFRunLoopTimerInvalidate(_timer);
CFRelease(_timer);
_timer = nil;
}
} }
-(void) updateTimer:(int)ms
{
if(_timer == nil)
return;
double interval = ms < 0 ? distantFutureInterval : ((double)ms / 1000);
CFRunLoopTimerSetTolerance(_timer, 0);
CFRunLoopTimerSetNextFireDate(_timer, CFAbsoluteTimeGetCurrent() + interval);
}
@end - (void) setEvents: (IAvnPlatformThreadingInterfaceEvents*) events
{
_events = events;
}
class TimerWrapper : public ComUnknownObject - (void) signal
{ {
NSTimer* _timer; @synchronized (self) {
public: if(_signaled)
TimerWrapper(IAvnActionCallback* callback, int ms) return;
{ _signaled = true;
auto cb = [[ActionCallback alloc] initWithCallback:callback]; dispatch_async(dispatch_get_main_queue(), ^{
_timer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(double)ms/1000 target:cb selector:@selector(action) userInfo:nullptr repeats:true]; [self checkSignaled];
});
CFRunLoopWakeUp(CFRunLoopGetMain());
} }
}
virtual ~TimerWrapper()
{ - (void) requestBackgroundProcessing
[_timer invalidate]; {
@synchronized (self) {
if(_backgroundProcessingRequested)
return;
_backgroundProcessingRequested = true;
dispatch_async(dispatch_get_main_queue(), ^{
// This is needed to wakeup the loop if we are called from inside of BeforeWait hook
});
} }
};
}
@end
class PlatformThreadingInterface : public ComSingleObject<IAvnPlatformThreadingInterface, &IID_IAvnPlatformThreadingInterface> class PlatformThreadingInterface : public ComSingleObject<IAvnPlatformThreadingInterface, &IID_IAvnPlatformThreadingInterface>
{ {
private: private:
ComPtr<IAvnPlatformThreadingInterfaceEvents> _events;
Signaler* _signaler; Signaler* _signaler;
bool _wasRunningAtLeastOnce = false; CFRunLoopObserverRef _observer = nil;
class LoopCancellation : public ComSingleObject<IAvnLoopCancellation, &IID_IAvnLoopCancellation>
{
public:
FORWARD_IUNKNOWN()
bool Running = false;
bool Cancelled = false;
virtual void Cancel() override
{
Cancelled = true;
if(Running)
{
Running = false;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSApplication sharedApplication] stop:nil];
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:event atStart:YES];
});
}
}
};
public: public:
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
ComPtr<IAvnSignaledCallback> SignaledCallback;
PlatformThreadingInterface() PlatformThreadingInterface()
{ {
_signaler = [Signaler new]; _signaler = [Signaler new];
[_signaler setParent:this]; };
}
~PlatformThreadingInterface() ~PlatformThreadingInterface()
{ {
if(_signaler) [_signaler destroyObserver];
[_signaler setParent: NULL];
_signaler = NULL;
} }
virtual bool GetCurrentThreadIsLoopThread() override bool GetCurrentThreadIsLoopThread() override
{ {
return [NSThread isMainThread]; return [NSThread isMainThread];
} };
virtual void SetSignaledCallback(IAvnSignaledCallback* cb) override
void SetEvents(IAvnPlatformThreadingInterfaceEvents *cb) override
{ {
SignaledCallback = cb; _events = cb;
} [_signaler setEvents:cb];
virtual IAvnLoopCancellation* CreateLoopCancellation() override };
IAvnLoopCancellation *CreateLoopCancellation() override
{ {
return new LoopCancellation(); return new LoopCancellation();
} };
virtual HRESULT RunLoop(IAvnLoopCancellation* cancel) override void RunLoop(IAvnLoopCancellation *cancel) override
{ {
START_COM_CALL; START_COM_CALL;
auto can = dynamic_cast<LoopCancellation*>(cancel); auto can = dynamic_cast<LoopCancellation*>(cancel);
if(can->Cancelled) if(can->Cancelled)
return S_OK; return;
if(_wasRunningAtLeastOnce)
return E_FAIL;
can->Running = true; can->Running = true;
_wasRunningAtLeastOnce = true; if(![NSApp isRunning])
[NSApp run]; {
return S_OK; can->IsApp = true;
} [NSApp run];
return;
}
else
{
while(!can->Cancelled)
{
@autoreleasepool
{
NSEvent* ev = [NSApp
nextEventMatchingMask:NSEventMaskAny
untilDate: [NSDate dateWithTimeIntervalSinceNow:1]
inMode:NSDefaultRunLoopMode
dequeue:true];
if(ev != NULL)
[NSApp sendEvent:ev];
}
}
}
};
virtual void Signal(int priority) override void Signal() override
{ {
[_signaler signal:priority]; [_signaler signal];
} };
virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback) override void UpdateTimer(int ms) override
{
@autoreleasepool {
return new TimerWrapper(callback, ms);
}
}
};
@implementation Signaler
PlatformThreadingInterface* _parent = 0;
bool _signaled = 0;
NSArray<NSString*>* _modes;
-(Signaler*) init
{
if(self = [super init])
{ {
_modes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode, nil]; [_signaler updateTimer:ms];
} };
return self;
} void RequestBackgroundProcessing() override {
[_signaler requestBackgroundProcessing];
-(void) perform
{
ComPtr<IAvnSignaledCallback> cb;
@synchronized (self) {
_signaled = false;
if(_parent != NULL)
cb = _parent->SignaledCallback;
}
if(cb != nullptr)
cb->Signaled(0, false);
}
-(void) setParent:(PlatformThreadingInterface *)parent
{
@synchronized (self) {
_parent = parent;
}
}
-(void) signal: (int) priority
{
@synchronized (self) {
if(_signaled)
return;
_signaled = true;
[self performSelector:@selector(perform) onThread:[NSThread mainThread] withObject:NULL waitUntilDone:false modes:_modes];
} }
}
@end };
extern IAvnPlatformThreadingInterface* CreatePlatformThreading() extern IAvnPlatformThreadingInterface* CreatePlatformThreading()
{ {

16
nukebuild/Build.cs

@ -165,10 +165,10 @@ partial class Build : NukeBuild
foreach (var fw in targetFrameworks) foreach (var fw in targetFrameworks)
{ {
if (fw.StartsWith("net4") if (fw.StartsWith("net4")
&& RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
&& Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1") && Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1")
{ {
Information($"Skipping {projectName} ({fw}) tests on Linux - https://github.com/mono/mono/issues/13969"); Information($"Skipping {projectName} ({fw}) tests on *nix - https://github.com/mono/mono/issues/13969");
continue; continue;
} }
@ -220,16 +220,18 @@ partial class Build : NukeBuild
.Executes(() => .Executes(() =>
{ {
RunCoreTest("Avalonia.Skia.RenderTests"); RunCoreTest("Avalonia.Skia.RenderTests");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (Parameters.IsRunningOnWindows)
RunCoreTest("Avalonia.Direct2D1.RenderTests"); RunCoreTest("Avalonia.Direct2D1.RenderTests");
}); });
Target RunDesignerTests => _ => _ Target RunToolsTests => _ => _
.OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) .OnlyWhenStatic(() => !Parameters.SkipTests)
.DependsOn(Compile) .DependsOn(Compile)
.Executes(() => .Executes(() =>
{ {
RunCoreTest("Avalonia.DesignerSupport.Tests"); RunCoreTest("Avalonia.Generators.Tests");
if (Parameters.IsRunningOnWindows)
RunCoreTest("Avalonia.DesignerSupport.Tests");
}); });
Target RunLeakTests => _ => _ Target RunLeakTests => _ => _
@ -276,7 +278,7 @@ partial class Build : NukeBuild
Target RunTests => _ => _ Target RunTests => _ => _
.DependsOn(RunCoreLibsTests) .DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests) .DependsOn(RunRenderTests)
.DependsOn(RunDesignerTests) .DependsOn(RunToolsTests)
.DependsOn(RunHtmlPreviewerTests) .DependsOn(RunHtmlPreviewerTests)
.DependsOn(RunLeakTests); .DependsOn(RunLeakTests);

104
nukebuild/BuildTasksPatcher.cs

@ -4,9 +4,58 @@ using System.IO.Compression;
using System.Linq; using System.Linq;
using ILRepacking; using ILRepacking;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil;
public class BuildTasksPatcher public class BuildTasksPatcher
{ {
/// <summary>
/// This helper class, avoid argument null exception
/// when cecil write AssemblyNameDefinition on MemoryStream.
/// </summary>
private class Wrapper : ISymbolWriterProvider
{
readonly ISymbolWriterProvider _provider;
readonly string _filename;
public Wrapper(ISymbolWriterProvider provider, string filename)
{
_provider = provider;
_filename = filename;
}
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName) =>
_provider.GetSymbolWriter(module, string.IsNullOrWhiteSpace(fileName) ? _filename : fileName);
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream) =>
_provider.GetSymbolWriter(module, symbolStream);
}
private static string GetSourceLinkInfo(string path)
{
try
{
using (var asm = AssemblyDefinition.ReadAssembly(path,
new ReaderParameters
{
ReadWrite = true,
InMemory = true,
ReadSymbols = true,
SymbolReaderProvider = new DefaultSymbolReaderProvider(false),
}))
{
if (asm.MainModule.CustomDebugInformations?.OfType<SourceLinkDebugInformation>()?.FirstOrDefault() is { } sli)
{
return sli.Content;
}
}
}
catch
{
}
return null;
}
public static void PatchBuildTasksInPackage(string packagePath) public static void PatchBuildTasksInPackage(string packagePath)
{ {
using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite), using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
@ -19,7 +68,7 @@ public class BuildTasksPatcher
{ {
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir); Directory.CreateDirectory(tempDir);
var temp = Path.Combine(tempDir, Guid.NewGuid() + ".dll"); var temp = Path.Combine(tempDir, entry.Name);
var output = temp + ".output"; var output = temp + ".output";
File.Copy(typeof(Microsoft.Build.Framework.ITask).Assembly.GetModules()[0].FullyQualifiedName, File.Copy(typeof(Microsoft.Build.Framework.ITask).Assembly.GetModules()[0].FullyQualifiedName,
Path.Combine(tempDir, "Microsoft.Build.Framework.dll")); Path.Combine(tempDir, "Microsoft.Build.Framework.dll"));
@ -27,41 +76,74 @@ public class BuildTasksPatcher
try try
{ {
entry.ExtractToFile(temp, true); entry.ExtractToFile(temp, true);
// Get Original SourceLinkInfo Content
var sourceLinkInfoContent = GetSourceLinkInfo(temp);
var repack = new ILRepacking.ILRepack(new RepackOptions() var repack = new ILRepacking.ILRepack(new RepackOptions()
{ {
Internalize = true, Internalize = true,
InputAssemblies = new[] InputAssemblies = new[]
{ {
temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0] temp,
.FullyQualifiedName, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0].FullyQualifiedName,
typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName, typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName,
typeof(Mono.Cecil.Pdb.PdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName, typeof(Mono.Cecil.Pdb.PdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName,
typeof(Mono.Cecil.Mdb.MdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName typeof(Mono.Cecil.Mdb.MdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName,
}, },
SearchDirectories = new string[0], SearchDirectories = Array.Empty<string>(),
DebugInfo = true, // Allowed read debug info
OutputFile = output OutputFile = output
}); });
repack.Repack(); repack.Repack();
// 'hurr-durr assembly with the same name is already loaded' prevention // 'hurr-durr assembly with the same name is already loaded' prevention
using (var asm = AssemblyDefinition.ReadAssembly(output, using (var asm = AssemblyDefinition.ReadAssembly(output,
new ReaderParameters { ReadWrite = true, InMemory = true, })) new ReaderParameters
{
ReadWrite = true,
InMemory = true,
ReadSymbols = true,
SymbolReaderProvider = new DefaultSymbolReaderProvider(false),
}))
{ {
asm.Name = new AssemblyNameDefinition( asm.Name = new AssemblyNameDefinition(
"Avalonia.Build.Tasks." "Avalonia.Build.Tasks."
+ Guid.NewGuid().ToString().Replace("-", ""), + Guid.NewGuid().ToString().Replace("-", ""),
new Version(0, 0, 0)); new Version(0, 0, 0));
asm.Write(patched);
var mainModule = asm.MainModule;
// If we have SourceLink info copy to patched assembly.
if (!string.IsNullOrEmpty(sourceLinkInfoContent))
{
mainModule.CustomDebugInformations.Add(new SourceLinkDebugInformation(sourceLinkInfoContent));
}
// Try to get SymbolWriter if it has it
var reader = mainModule.SymbolReader;
var hasDebugInfo = reader is not null;
var proivder = reader?.GetWriterProvider() is ISymbolWriterProvider p
? new Wrapper(p, "Avalonia.Build.Tasks.dll")
: default(ISymbolWriterProvider);
var parameters = new WriterParameters
{
#if ISNETFULLFRAMEWORK
StrongNameKeyPair = signingStep.KeyPair,
#endif
WriteSymbols = hasDebugInfo,
SymbolWriterProvider = proivder,
DeterministicMvid = hasDebugInfo,
};
asm.Write(patched, parameters);
patched.Position = 0; patched.Position = 0;
} }
} }
finally finally
{ {
try try
{ {
if(Directory.Exists(tempDir)) if (Directory.Exists(tempDir))
Directory.Delete(tempDir, true); Directory.Delete(tempDir, true);
} }
catch catch
@ -79,4 +161,4 @@ public class BuildTasksPatcher
} }
} }
} }
} }

5
nukebuild/numerge.config

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

10
packages/Avalonia/Avalonia.csproj

@ -6,11 +6,15 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" /> <ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" > <ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
<SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework> <SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\src\tools\Avalonia.Generators\Avalonia.Generators.csproj"
ReferenceOutputAssembly="false"
PrivateAssets="all"
OutputItemType="Analyzer" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
@ -39,6 +43,10 @@
<Pack>true</Pack> <Pack>true</Pack>
<PackagePath>build\;buildTransitive\</PackagePath> <PackagePath>build\;buildTransitive\</PackagePath>
</Content> </Content>
<Content Include="..\..\src\tools\Avalonia.Generators\Avalonia.Generators.props">
<Pack>true</Pack>
<PackagePath>build\;buildTransitive\</PackagePath>
</Content>
<Content Include="*.targets"> <Content Include="*.targets">
<Pack>true</Pack> <Pack>true</Pack>
<PackagePath>build\;buildTransitive\</PackagePath> <PackagePath>build\;buildTransitive\</PackagePath>

6
packages/Avalonia/Avalonia.props

@ -6,4 +6,10 @@
<AvaloniaUseExternalMSBuild>false</AvaloniaUseExternalMSBuild> <AvaloniaUseExternalMSBuild>false</AvaloniaUseExternalMSBuild>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.props"/> <Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.props"/>
<Import Project="$(MSBuildThisFileDirectory)\Avalonia.Generators.props"/>
<!-- Allow loading the AvaloniaVS extension when referencing the Avalonia nuget package -->
<ItemGroup>
<ProjectCapability Include="Avalonia"/>
</ItemGroup>
</Project> </Project>

4
readme.md

@ -5,6 +5,10 @@
<br /> <br />
[![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg) [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg)
# ⚠️ **v11 Update - Pausing community contributions**
for more information see [this](https://github.com/AvaloniaUI/Avalonia/discussions/10599) discussion.
## 📖 About ## 📖 About
Avalonia is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS. Avalonia is mature and production ready. We also have in beta release support for iOS, Android and in early stages support for browser via WASM. Avalonia is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS. Avalonia is mature and production ready. We also have in beta release support for iOS, Android and in early stages support for browser via WASM.

1
samples/BindingDemo/BindingDemo.csproj

@ -5,6 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />

4
samples/BindingDemo/MainWindow.xaml

@ -75,11 +75,11 @@
</StackPanel.DataTemplates> </StackPanel.DataTemplates>
<StackPanel Margin="18" Spacing="4" Width="200"> <StackPanel Margin="18" Spacing="4" Width="200">
<TextBlock FontSize="16" Text="Multiple"/> <TextBlock FontSize="16" Text="Multiple"/>
<ListBox Items="{Binding Items}" SelectionMode="Multiple" Selection="{Binding Selection}"/> <ListBox ItemsSource="{Binding Items}" SelectionMode="Multiple" Selection="{Binding Selection}"/>
</StackPanel> </StackPanel>
<StackPanel Margin="18" Spacing="4" Width="200"> <StackPanel Margin="18" Spacing="4" Width="200">
<TextBlock FontSize="16" Text="Multiple"/> <TextBlock FontSize="16" Text="Multiple"/>
<ListBox Items="{Binding Items}" SelectionMode="Multiple" Selection="{Binding Selection}"/> <ListBox ItemsSource="{Binding Items}" SelectionMode="Multiple" Selection="{Binding Selection}"/>
</StackPanel> </StackPanel>
<ContentControl Content="{ReflectionBinding Selection.SelectedItems[0]}"> <ContentControl Content="{ReflectionBinding Selection.SelectedItems[0]}">
<ContentControl.DataTemplates> <ContentControl.DataTemplates>

2
samples/ControlCatalog.Android/MainActivity.cs

@ -5,7 +5,7 @@ using Avalonia.Android;
namespace ControlCatalog.Android namespace ControlCatalog.Android
{ {
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
public class MainActivity : AvaloniaMainActivity public class MainActivity : AvaloniaMainActivity
{ {
} }

2
samples/ControlCatalog.Android/Properties/AndroidManifest.xml

@ -2,4 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> <application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE " />
</manifest> </manifest>

4
samples/ControlCatalog.Android/Resources/values-night/colors.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="splash_background">#212121</color>
</resources>

2
samples/ControlCatalog.Android/Resources/values/styles.xml

@ -4,7 +4,7 @@
<style name="MyTheme"> <style name="MyTheme">
</style> </style>
<style name="MyTheme.NoActionBar" parent="@style/Theme.AppCompat.NoActionBar"> <style name="MyTheme.NoActionBar" parent="@style/Theme.AppCompat.DayNight.NoActionBar">
<item name="android:windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
</style> </style>

9
samples/ControlCatalog.Browser/app.css

@ -1,4 +1,11 @@
#out { :root {
--sat: env(safe-area-inset-top);
--sar: env(safe-area-inset-right);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
}
#out {
height: 100vh; height: 100vh;
width: 100vw width: 100vw
} }

2
samples/ControlCatalog.NetCore/Program.cs

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Fonts.Inter;
using Avalonia.Headless; using Avalonia.Headless;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Threading; using Avalonia.Threading;
@ -124,6 +125,7 @@ namespace ControlCatalog.NetCore
EnableIme = true EnableIme = true
}) })
.UseSkia() .UseSkia()
.WithInterFont()
.AfterSetup(builder => .AfterSetup(builder =>
{ {
builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()

4
samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj

@ -3,7 +3,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<ProvisioningType>manual</ProvisioningType> <ProvisioningType>manual</ProvisioningType>
<TargetFramework>net6.0-ios</TargetFramework> <TargetFramework>net6.0-ios</TargetFramework>
<SupportedOSPlatformVersion>10.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
<!-- temporal workaround for our GL interface backend --> <!-- temporal workaround for our GL interface backend -->
<UseInterpreter>True</UseInterpreter> <UseInterpreter>True</UseInterpreter>
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier> <RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
@ -16,4 +16,4 @@
<ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" /> <ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

6
samples/ControlCatalog.iOS/Info.plist

@ -13,7 +13,7 @@
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>10.0</string> <string>13.0</string>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>
<array> <array>
<integer>1</integer> <integer>1</integer>
@ -39,9 +39,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict> </dict>
</plist> </plist>

4
samples/ControlCatalog/App.xaml.cs

@ -44,11 +44,11 @@ namespace ControlCatalog
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
{ {
desktopLifetime.MainWindow = new MainWindow(); desktopLifetime.MainWindow = new MainWindow { DataContext = new MainWindowViewModel() };
} }
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime) else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
{ {
singleViewLifetime.MainView = new MainView(); singleViewLifetime.MainView = new MainView { DataContext = new MainWindowViewModel() };
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();

15
samples/ControlCatalog/ControlCatalog.csproj

@ -2,7 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Update="**\*.xaml.cs"> <Compile Update="**\*.xaml.cs">
@ -29,19 +30,11 @@
<ProjectReference Include="..\..\src\Avalonia.Controls.ItemsRepeater\Avalonia.Controls.ItemsRepeater.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.ItemsRepeater\Avalonia.Controls.ItemsRepeater.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
<ProjectReference Include="..\SampleControls\ControlSamples.csproj" /> <ProjectReference Include="..\SampleControls\ControlSamples.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" /> <Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\SourceGenerators.props" />
<ItemGroup>
<None Remove="Pages\CustomDrawing.xaml" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Update="Pages\CustomDrawing.xaml">
<Generator></Generator>
</AvaloniaResource>
</ItemGroup>
</Project> </Project>

5
samples/ControlCatalog/MainView.xaml

@ -147,9 +147,6 @@
<TabItem Header="ScrollViewer"> <TabItem Header="ScrollViewer">
<pages:ScrollViewerPage /> <pages:ScrollViewerPage />
</TabItem> </TabItem>
<TabItem Header="ScrollViewer Snapping">
<pages:ScrollSnapPage />
</TabItem>
<TabItem Header="Slider"> <TabItem Header="Slider">
<pages:SliderPage /> <pages:SliderPage />
</TabItem> </TabItem>
@ -241,7 +238,7 @@
</ComboBox.Items> </ComboBox.Items>
</ComboBox> </ComboBox>
<ComboBox HorizontalAlignment="Stretch" <ComboBox HorizontalAlignment="Stretch"
Items="{Binding WindowStates}" ItemsSource="{Binding WindowStates}"
SelectedItem="{Binding WindowState}" /> SelectedItem="{Binding WindowState}" />
</StackPanel> </StackPanel>
</Flyout> </Flyout>

38
samples/ControlCatalog/MainView.xaml.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@ -12,6 +13,7 @@ using Avalonia.VisualTree;
using Avalonia.Styling; using Avalonia.Styling;
using ControlCatalog.Models; using ControlCatalog.Models;
using ControlCatalog.Pages; using ControlCatalog.Pages;
using ControlCatalog.ViewModels;
namespace ControlCatalog namespace ControlCatalog
{ {
@ -99,13 +101,47 @@ namespace ControlCatalog
}; };
} }
internal MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext!;
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
var decorations = this.Get<ComboBox>("Decorations"); var decorations = this.Get<ComboBox>("Decorations");
if (VisualRoot is Window window) if (VisualRoot is Window window)
decorations.SelectedIndex = (int)window.SystemDecorations; decorations.SelectedIndex = (int)window.SystemDecorations;
var insets = TopLevel.GetTopLevel(this)!.InsetsManager;
if (insets != null)
{
// In real life application these events should be unsubscribed to avoid memory leaks.
ViewModel.SafeAreaPadding = insets.SafeAreaPadding;
insets.SafeAreaChanged += (sender, args) =>
{
ViewModel.SafeAreaPadding = insets.SafeAreaPadding;
};
ViewModel.DisplayEdgeToEdge = insets.DisplayEdgeToEdge;
ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
ViewModel.PropertyChanged += async (sender, args) =>
{
if (args.PropertyName == nameof(ViewModel.DisplayEdgeToEdge))
{
insets.DisplayEdgeToEdge = ViewModel.DisplayEdgeToEdge;
}
else if (args.PropertyName == nameof(ViewModel.IsSystemBarVisible))
{
insets.IsSystemBarVisible = ViewModel.IsSystemBarVisible;
}
// Give the OS some time to apply new values and refresh the view model.
await Task.Delay(100);
ViewModel.DisplayEdgeToEdge = insets.DisplayEdgeToEdge;
ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
};
}
_platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged; _platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged;
PlatformSettingsOnColorValuesChanged(_platformSettings, _platformSettings.GetColorValues()); PlatformSettingsOnColorValuesChanged(_platformSettings, _platformSettings.GetColorValues());
} }

1
samples/ControlCatalog/MainWindow.xaml.cs

@ -17,7 +17,6 @@ namespace ControlCatalog
{ {
this.InitializeComponent(); this.InitializeComponent();
DataContext = new MainWindowViewModel();
_recentMenu = ((NativeMenu.GetMenu(this)?.Items[0] as NativeMenuItem)?.Menu?.Items[2] as NativeMenuItem)?.Menu; _recentMenu = ((NativeMenu.GetMenu(this)?.Items[0] as NativeMenuItem)?.Menu?.Items[2] as NativeMenuItem)?.Menu;
} }

74
samples/ControlCatalog/Pages/ClipboardPage.xaml.cs

@ -1,16 +1,23 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public partial class ClipboardPage : UserControl public partial class ClipboardPage : UserControl
{ {
private INotificationManager? _notificationManager;
private INotificationManager NotificationManager => _notificationManager
??= new WindowNotificationManager(TopLevel.GetTopLevel(this)!);
public ClipboardPage() public ClipboardPage()
{ {
InitializeComponent(); InitializeComponent();
@ -25,13 +32,13 @@ namespace ControlCatalog.Pages
private async void CopyText(object? sender, RoutedEventArgs args) private async void CopyText(object? sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard && ClipboardContent is { } clipboardContent) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard && ClipboardContent is { } clipboardContent)
await clipboard.SetTextAsync(clipboardContent.Text ?? String.Empty); await clipboard.SetTextAsync(clipboardContent.Text ?? String.Empty);
} }
private async void PasteText(object? sender, RoutedEventArgs args) private async void PasteText(object? sender, RoutedEventArgs args)
{ {
if(Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
ClipboardContent.Text = await clipboard.GetTextAsync(); ClipboardContent.Text = await clipboard.GetTextAsync();
} }
@ -39,7 +46,7 @@ namespace ControlCatalog.Pages
private async void CopyTextDataObject(object? sender, RoutedEventArgs args) private async void CopyTextDataObject(object? sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
var dataObject = new DataObject(); var dataObject = new DataObject();
dataObject.Set(DataFormats.Text, ClipboardContent.Text ?? string.Empty); dataObject.Set(DataFormats.Text, ClipboardContent.Text ?? string.Empty);
@ -49,7 +56,7 @@ namespace ControlCatalog.Pages
private async void PasteTextDataObject(object? sender, RoutedEventArgs args) private async void PasteTextDataObject(object? sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
ClipboardContent.Text = await clipboard.GetDataAsync(DataFormats.Text) as string ?? string.Empty; ClipboardContent.Text = await clipboard.GetDataAsync(DataFormats.Text) as string ?? string.Empty;
} }
@ -57,32 +64,63 @@ namespace ControlCatalog.Pages
private async void CopyFilesDataObject(object? sender, RoutedEventArgs args) private async void CopyFilesDataObject(object? sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
var files = (ClipboardContent.Text ?? String.Empty) var storageProvider = TopLevel.GetTopLevel(this)!.StorageProvider;
.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var filesPath = (ClipboardContent.Text ?? string.Empty)
if (files.Length == 0) .Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
if (filesPath.Length == 0)
{ {
return; return;
} }
var dataObject = new DataObject(); List<string> invalidFile = new(filesPath.Length);
dataObject.Set(DataFormats.FileNames, files); List<IStorageFile> files = new(filesPath.Length);
await clipboard.SetDataObjectAsync(dataObject);
for (int i = 0; i < filesPath.Length; i++)
{
var file = await storageProvider.TryGetFileFromPathAsync(filesPath[i]);
if (file is null)
{
invalidFile.Add(filesPath[i]);
}
else
{
files.Add(file);
}
}
if (invalidFile.Count > 0)
{
NotificationManager.Show(new Notification("Warning", "There is one o more invalid path.", NotificationType.Warning));
}
if (files.Count > 0)
{
var dataObject = new DataObject();
dataObject.Set(DataFormats.Files, files);
await clipboard.SetDataObjectAsync(dataObject);
NotificationManager.Show(new Notification("Success", "Copy completated.", NotificationType.Success));
}
else
{
NotificationManager.Show(new Notification("Warning", "Any files to copy in Clipboard.", NotificationType.Warning));
}
} }
} }
private async void PasteFilesDataObject(object? sender, RoutedEventArgs args) private async void PasteFilesDataObject(object? sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
var fiels = await clipboard.GetDataAsync(DataFormats.FileNames) as IEnumerable<string>; var files = await clipboard.GetDataAsync(DataFormats.Files) as IEnumerable<Avalonia.Platform.Storage.IStorageItem>;
ClipboardContent.Text = fiels != null ? string.Join(Environment.NewLine, fiels) : string.Empty;
ClipboardContent.Text = files != null ? string.Join(Environment.NewLine, files.Select(f => f.TryGetLocalPath() ?? f.Name)) : string.Empty;
} }
} }
private async void GetFormats(object sender, RoutedEventArgs args) private async void GetFormats(object sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
var formats = await clipboard.GetFormatsAsync(); var formats = await clipboard.GetFormatsAsync();
ClipboardContent.Text = string.Join(Environment.NewLine, formats); ClipboardContent.Text = string.Join(Environment.NewLine, formats);
@ -91,11 +129,11 @@ namespace ControlCatalog.Pages
private async void Clear(object sender, RoutedEventArgs args) private async void Clear(object sender, RoutedEventArgs args)
{ {
if (Application.Current!.Clipboard is { } clipboard) if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{ {
await clipboard.ClearAsync(); await clipboard.ClearAsync();
} }
} }
} }
} }

35
samples/ControlCatalog/Pages/ColorPickerPage.xaml

@ -28,6 +28,41 @@
<Grid Grid.Column="2" <Grid Grid.Column="2"
Grid.Row="0" Grid.Row="0"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Grid.Resources>
<x:Double x:Key="ColorSliderSize">24</x:Double>
<x:Double x:Key="ColorSliderTrackSize">18</x:Double>
<CornerRadius x:Key="ColorSliderCornerRadius">12</CornerRadius>
<CornerRadius x:Key="ColorSliderTrackCornerRadius">9</CornerRadius>
<!-- Due to 'SystemControlForegroundBaseHighBrush' usage this only works in Fluent theme. -->
<!-- Otherwise it would be necessary to make custom light/dark resources. -->
<ControlTheme x:Key="ColorSliderThumbTheme"
TargetType="Thumb">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlForegroundBaseHighBrush}" />
<Setter Property="BorderThickness" Value="5" />
<Setter Property="CornerRadius" Value="{DynamicResource ColorSliderCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}" />
<Ellipse Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}"
Fill="Transparent"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</ControlTheme>
</Grid.Resources>
<ColorSpectrum x:Name="ColorSpectrum1" <ColorSpectrum x:Name="ColorSpectrum1"
Grid.Row="0" Grid.Row="0"
Color="Red" Color="Red"

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

@ -18,7 +18,7 @@ namespace ControlCatalog.Pages
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
var fontComboBox = this.Get<ComboBox>("fontComboBox"); var fontComboBox = this.Get<ComboBox>("fontComboBox");
fontComboBox.Items = FontManager.Current.GetInstalledFontFamilyNames().Select(x => new FontFamily(x)); fontComboBox.ItemsSource = FontManager.Current.SystemFonts;
fontComboBox.SelectedIndex = 0; fontComboBox.SelectedIndex = 0;
} }
} }

2
samples/ControlCatalog/Pages/CompositionPage.axaml.cs

@ -32,7 +32,7 @@ public partial class CompositionPage : UserControl
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
this.Get<ItemsControl>("Items").Items = CreateColorItems(); this.Get<ItemsControl>("Items").ItemsSource = CreateColorItems();
} }

2
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml

@ -61,7 +61,7 @@
<Border.Styles> <Border.Styles>
<Style Selector="MenuFlyoutPresenter MenuItem" x:DataType="viewModels:MenuItemViewModel"> <Style Selector="MenuFlyoutPresenter MenuItem" x:DataType="viewModels:MenuItemViewModel">
<Setter Property="Header" Value="{Binding Header}"/> <Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Items" Value="{Binding Items}"/> <Setter Property="ItemsSource" Value="{Binding Items}"/>
<Setter Property="Command" Value="{Binding Command}"/> <Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
</Style> </Style>

5
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs

@ -36,8 +36,9 @@ namespace ControlCatalog.Pages
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel); customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.Get<Border>("CancellableContextBorder"); var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextFlyout!.Closing += ContextFlyoutPage_Closing; var flyout = (Flyout)cancellableContextBorder.ContextFlyout!;
cancellableContextBorder.ContextFlyout!.Opening += ContextFlyoutPage_Opening; flyout.Closing += ContextFlyoutPage_Closing;
flyout.Opening += ContextFlyoutPage_Opening;
} }
private ContextPageViewModel? _model; private ContextPageViewModel? _model;

4
samples/ControlCatalog/Pages/ContextMenuPage.xaml

@ -51,13 +51,13 @@
<Border.Styles> <Border.Styles>
<Style Selector="ContextMenu MenuItem" x:DataType="viewModels:MenuItemViewModel"> <Style Selector="ContextMenu MenuItem" x:DataType="viewModels:MenuItemViewModel">
<Setter Property="Header" Value="{Binding Header}"/> <Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Items" Value="{Binding Items}"/> <Setter Property="ItemsSource" Value="{Binding Items}"/>
<Setter Property="Command" Value="{Binding Command}"/> <Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
</Style> </Style>
</Border.Styles> </Border.Styles>
<Border.ContextMenu> <Border.ContextMenu>
<ContextMenu Items="{Binding MenuItems}" /> <ContextMenu ItemsSource="{Binding MenuItems}" />
</Border.ContextMenu> </Border.ContextMenu>
<TextBlock Text="Dynamically Generated"/> <TextBlock Text="Dynamically Generated"/>
</Border> </Border>

2
samples/ControlCatalog/Pages/CursorPage.xaml

@ -8,7 +8,7 @@
<TextBlock Classes="h2">Defines a cursor (mouse pointer)</TextBlock> <TextBlock Classes="h2">Defines a cursor (mouse pointer)</TextBlock>
</StackPanel> </StackPanel>
<ListBox Grid.Row="1" Items="{Binding StandardCursors}" Margin="0 8 8 8"> <ListBox Grid.Row="1" ItemsSource="{Binding StandardCursors}" Margin="0 8 8 8">
<ListBox.Styles> <ListBox.Styles>
<Style Selector="ListBoxItem"> <Style Selector="ListBoxItem">
<Setter Property="Cursor" Value="{Binding Cursor}" x:DataType="viewModels:StandardCursorModel"/> <Setter Property="Cursor" Value="{Binding Cursor}" x:DataType="viewModels:StandardCursorModel"/>

16
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

@ -16,10 +16,10 @@ namespace ControlCatalog.Pages
private Point _cursorPoint; private Point _cursorPoint;
public StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d); public static readonly StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); } public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
public StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation)); public static readonly StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation));
/// <summary> /// <summary>
/// Rotation, measured in Radians! /// Rotation, measured in Radians!
/// </summary> /// </summary>
@ -33,10 +33,10 @@ namespace ControlCatalog.Pages
} }
} }
public StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d); public static readonly StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); } public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); }
public StyledProperty<double> ViewportCenterXProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterX), 0.0d); public static readonly StyledProperty<double> ViewportCenterXProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterX), 0.0d);
public double ViewportCenterX { get => GetValue(ViewportCenterXProperty); set => SetValue(ViewportCenterXProperty, value); } public double ViewportCenterX { get => GetValue(ViewportCenterXProperty); set => SetValue(ViewportCenterXProperty, value); }
private IPen _pen; private IPen _pen;
@ -133,17 +133,17 @@ namespace ControlCatalog.Pages
// 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 // 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))); var translateModifier = context.PushTransform(Avalonia.Matrix.CreateTranslation(new Avalonia.Vector(halfWidth, halfHeight)));
// now 0,0 refers to the ViewportCenter(X,Y). // now 0,0 refers to the ViewportCenter(X,Y).
var rotationMatrix = Avalonia.Matrix.CreateRotation(Rotation); var rotationMatrix = Avalonia.Matrix.CreateRotation(Rotation);
var rotationModifier = context.PushPreTransform(rotationMatrix); var rotationModifier = context.PushTransform(rotationMatrix);
// everything is rotated but not scaled // everything is rotated but not scaled
var scaleModifier = context.PushPreTransform(Avalonia.Matrix.CreateScale(Scale, -Scale)); var scaleModifier = context.PushTransform(Avalonia.Matrix.CreateScale(Scale, -Scale));
var mapPositionModifier = context.PushPreTransform(Matrix.CreateTranslation(new Vector(-ViewportCenterX, -ViewportCenterY))); var mapPositionModifier = context.PushTransform(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 // now everything is rotated and scaled, and at the right position, now we're drawing strictly in world coordinates

16
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -106,7 +106,7 @@ namespace ControlCatalog.Pages
Directory = initialDirectory, Directory = initialDirectory,
InitialFileName = initialFileName InitialFileName = initialFileName
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
results.Items = result; results.ItemsSource = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.Get<Button>("OpenMultipleFiles").Click += async delegate this.Get<Button>("OpenMultipleFiles").Click += async delegate
@ -118,7 +118,7 @@ namespace ControlCatalog.Pages
Directory = lastSelectedDirectory?.Path is {IsAbsoluteUri:true} path ? path.LocalPath : null, Directory = lastSelectedDirectory?.Path is {IsAbsoluteUri:true} path ? path.LocalPath : null,
AllowMultiple = true AllowMultiple = true
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
results.Items = result; results.ItemsSource = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.Get<Button>("SaveFile").Click += async delegate this.Get<Button>("SaveFile").Click += async delegate
@ -132,7 +132,7 @@ namespace ControlCatalog.Pages
DefaultExtension = filters?.Any() == true ? "txt" : null, DefaultExtension = filters?.Any() == true ? "txt" : null,
InitialFileName = "test.txt" InitialFileName = "test.txt"
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
results.Items = new[] { result }; results.ItemsSource = new[] { result };
resultsVisible.IsVisible = result != null; resultsVisible.IsVisible = result != null;
}; };
this.Get<Button>("SelectFolder").Click += async delegate this.Get<Button>("SelectFolder").Click += async delegate
@ -149,7 +149,7 @@ namespace ControlCatalog.Pages
else else
{ {
SetFolder(await GetStorageProvider().TryGetFolderFromPathAsync(result)); SetFolder(await GetStorageProvider().TryGetFolderFromPathAsync(result));
results.Items = new[] { result }; results.ItemsSource = new[] { result };
resultsVisible.IsVisible = true; resultsVisible.IsVisible = true;
} }
}; };
@ -164,7 +164,7 @@ namespace ControlCatalog.Pages
{ {
AllowDirectorySelection = true AllowDirectorySelection = true
}); });
results.Items = result; results.ItemsSource = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.Get<Button>("DecoratedWindow").Click += delegate this.Get<Button>("DecoratedWindow").Click += delegate
@ -324,15 +324,15 @@ namespace ControlCatalog.Pages
mappedResults.Add("+> " + FullPathOrName(selectedItem)); mappedResults.Add("+> " + FullPathOrName(selectedItem));
if (selectedItem is IStorageFolder folder) if (selectedItem is IStorageFolder folder)
{ {
foreach (var innerItems in await folder.GetItemsAsync()) await foreach (var innerItem in folder.GetItemsAsync())
{ {
mappedResults.Add("++> " + FullPathOrName(innerItems)); mappedResults.Add("++> " + FullPathOrName(innerItem));
} }
} }
} }
} }
results.Items = mappedResults; results.ItemsSource = mappedResults;
resultsVisible.IsVisible = mappedResults.Any(); resultsVisible.IsVisible = mappedResults.Any();
} }
} }

8
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@ -104,8 +104,12 @@ namespace ControlCatalog.Pages
} }
else if (item is IStorageFolder folder) else if (item is IStorageFolder folder)
{ {
var items = await folder.GetItemsAsync(); var childrenCount = 0;
contentStr += $"Folder {item.Name}: items {items.Count}{Environment.NewLine}{Environment.NewLine}"; await foreach (var _ in folder.GetItemsAsync())
{
childrenCount++;
}
contentStr += $"Folder {item.Name}: items {childrenCount}{Environment.NewLine}{Environment.NewLine}";
} }
} }

18
samples/ControlCatalog/Pages/FlyoutsPage.axaml

@ -16,8 +16,13 @@
<MenuItem Header="Item 3" /> <MenuItem Header="Item 3" />
</MenuFlyout> </MenuFlyout>
<Flyout Placement="Bottom" x:Key="BasicFlyout"> <Flyout Placement="Bottom" x:Key="BasicFlyout">
<Flyout.FlyoutPresenterTheme>
<ControlTheme TargetType="FlyoutPresenter" BasedOn="{StaticResource {x:Type FlyoutPresenter}}">
<Setter Property="CornerRadius" Value="20" />
</ControlTheme>
</Flyout.FlyoutPresenterTheme>
<Panel Width="100" Height="100"> <Panel Width="100" Height="100">
<TextBlock Text="Flyout Content!" /> <TextBlock Text="Flyout Content with a custom presenter theme!" TextWrapping="Wrap" />
</Panel> </Panel>
</Flyout> </Flyout>
</UserControl.Resources> </UserControl.Resources>
@ -136,6 +141,15 @@
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
<Button Content="Placement=Center">
<Button.Flyout>
<Flyout Placement="Center">
<Panel Width="100" Height="100">
<TextBlock Text="Flyout Content!" />
</Panel>
</Flyout>
</Button.Flyout>
</Button>
<Button Content="Placement=TopEdgeAlignedLeft"> <Button Content="Placement=TopEdgeAlignedLeft">
<Button.Flyout> <Button.Flyout>
<Flyout Placement="TopEdgeAlignedLeft"> <Flyout Placement="TopEdgeAlignedLeft">
@ -190,7 +204,7 @@
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
<Button Content="Placement=RightEdgeAlignedBottom"> <Button Content="Placement=RightEdgeAlignedTop">
<Button.Flyout> <Button.Flyout>
<Flyout Placement="RightEdgeAlignedTop"> <Flyout Placement="RightEdgeAlignedTop">
<Panel Width="100" Height="100"> <Panel Width="100" Height="100">

8
samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs

@ -1,11 +1,10 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using Avalonia.Interactivity; using Avalonia.Interactivity;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public class FlyoutsPage : UserControl public partial class FlyoutsPage : UserControl
{ {
public FlyoutsPage() public FlyoutsPage()
{ {
@ -28,11 +27,6 @@ namespace ControlCatalog.Pages
} }
} }
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void SetXamlTexts() private void SetXamlTexts()
{ {
var bfxt = this.Get<TextBlock>("ButtonFlyoutXamlText"); var bfxt = this.Get<TextBlock>("ButtonFlyoutXamlText");

11
samples/ControlCatalog/Pages/LabelsPage.axaml.cs

@ -1,11 +1,9 @@
using Avalonia; using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.Models; using ControlCatalog.Models;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public class LabelsPage : UserControl public partial class LabelsPage : UserControl
{ {
private Person? _person; private Person? _person;
@ -25,11 +23,6 @@ namespace ControlCatalog.Pages
}; };
} }
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void DoSave() public void DoSave()
{ {

2
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -30,7 +30,7 @@
<Button Command="{Binding RemoveItemCommand}">Remove</Button> <Button Command="{Binding RemoveItemCommand}">Remove</Button>
<Button Command="{Binding SelectRandomItemCommand}">Select Random Item</Button> <Button Command="{Binding SelectRandomItemCommand}">Select Random Item</Button>
</StackPanel> </StackPanel>
<ListBox Items="{Binding Items}" <ListBox ItemsSource="{Binding Items}"
Selection="{Binding Selection}" Selection="{Binding Selection}"
DisplayMemberBinding="{Binding (viewModels:ItemModel).ID, StringFormat='{}Item {0:N0}'}" DisplayMemberBinding="{Binding (viewModels:ItemModel).ID, StringFormat='{}Item {0:N0}'}"
AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}" AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}"

6
samples/ControlCatalog/Pages/MenuPage.xaml

@ -45,11 +45,11 @@
<StackPanel> <StackPanel>
<TextBlock Classes="h3" Margin="4 8">Dyanamically generated</TextBlock> <TextBlock Classes="h3" Margin="4 8">Dyanamically generated</TextBlock>
<Menu Items="{Binding MenuItems}"> <Menu ItemsSource="{Binding MenuItems}">
<Menu.Styles> <Menu.Styles>
<Style Selector="MenuItem" x:DataType="viewModels:MenuItemViewModel"> <Style Selector="MenuItem" x:DataType="viewModels:MenuItemViewModel">
<Setter Property="Header" Value="{Binding Header}"/> <Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Items" Value="{Binding Items}"/> <Setter Property="ItemsSource" Value="{Binding Items}"/>
<Setter Property="Command" Value="{Binding Command}"/> <Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
</Style> </Style>
@ -68,7 +68,7 @@
<Separator/> <Separator/>
<MenuItem Header="Execu_te Script..." /> <MenuItem Header="Execu_te Script..." />
<Separator/> <Separator/>
<MenuItem Header="_Recent" Items="{Binding RecentItems}"> <MenuItem Header="_Recent" ItemsSource="{Binding RecentItems}">
<MenuItem.Styles> <MenuItem.Styles>
<Style Selector="MenuItem" x:DataType="viewModels:MenuItemViewModel"> <Style Selector="MenuItem" x:DataType="viewModels:MenuItemViewModel">
<Setter Property="Header" Value="{Binding Header}"/> <Setter Property="Header" Value="{Binding Header}"/>

8
samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs

@ -33,10 +33,10 @@ namespace ControlCatalog.Pages
{ {
new ContextMenu() new ContextMenu()
{ {
Items = new List<MenuItem> Items =
{ {
new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" }
} }
}.Open((Control)sender); }.Open((Control)sender);
} }

6
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -27,7 +27,7 @@
</Grid> </Grid>
<Grid Grid.Row="0" Grid.Column="1" Margin="8" ColumnDefinitions="Auto, 120" RowDefinitions="Auto,Auto,Auto,Auto,Auto"> <Grid Grid.Row="0" Grid.Column="1" Margin="8" ColumnDefinitions="Auto, 120" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="2">FormatString:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="2">FormatString:</TextBlock>
<ComboBox Grid.Row="0" Grid.Column="1" Items="{Binding Formats}" SelectedItem="{Binding SelectedFormat}" <ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Formats}" SelectedItem="{Binding SelectedFormat}"
VerticalAlignment="Center" Margin="2"> VerticalAlignment="Center" Margin="2">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -41,11 +41,11 @@
</ComboBox> </ComboBox>
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="2">ButtonSpinnerLocation:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="2">ButtonSpinnerLocation:</TextBlock>
<ComboBox Grid.Row="1" Grid.Column="1" Items="{Binding SpinnerLocations}" SelectedItem="{Binding #upDown.ButtonSpinnerLocation}" <ComboBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding SpinnerLocations}" SelectedItem="{Binding #upDown.ButtonSpinnerLocation}"
VerticalAlignment="Center" Margin="2"/> VerticalAlignment="Center" Margin="2"/>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="2">CultureInfo:</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="2">CultureInfo:</TextBlock>
<ComboBox x:Name="CultureSelector" Grid.Row="2" Grid.Column="1" Items="{Binding Cultures}" <ComboBox x:Name="CultureSelector" Grid.Row="2" Grid.Column="1" ItemsSource="{Binding Cultures}"
VerticalAlignment="Center" Margin="2"/> VerticalAlignment="Center" Margin="2"/>
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="2">Watermark:</TextBlock> <TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="2">Watermark:</TextBlock>

8
samples/ControlCatalog/Pages/PointerCanvas.cs

@ -93,7 +93,7 @@ public class PointerCanvas : Control
} }
private int _threadSleep; private int _threadSleep;
public static DirectProperty<PointerCanvas, int> ThreadSleepProperty = public static readonly DirectProperty<PointerCanvas, int> ThreadSleepProperty =
AvaloniaProperty.RegisterDirect<PointerCanvas, int>(nameof(ThreadSleep), c => c.ThreadSleep, (c, v) => c.ThreadSleep = v); AvaloniaProperty.RegisterDirect<PointerCanvas, int>(nameof(ThreadSleep), c => c.ThreadSleep, (c, v) => c.ThreadSleep = v);
public int ThreadSleep public int ThreadSleep
@ -103,7 +103,7 @@ public class PointerCanvas : Control
} }
private bool _drawOnlyPoints; private bool _drawOnlyPoints;
public static DirectProperty<PointerCanvas, bool> DrawOnlyPointsProperty = public static readonly DirectProperty<PointerCanvas, bool> DrawOnlyPointsProperty =
AvaloniaProperty.RegisterDirect<PointerCanvas, bool>(nameof(DrawOnlyPoints), c => c.DrawOnlyPoints, (c, v) => c.DrawOnlyPoints = v); AvaloniaProperty.RegisterDirect<PointerCanvas, bool>(nameof(DrawOnlyPoints), c => c.DrawOnlyPoints, (c, v) => c.DrawOnlyPoints = v);
public bool DrawOnlyPoints public bool DrawOnlyPoints
@ -113,8 +113,8 @@ public class PointerCanvas : Control
} }
private string? _status; private string? _status;
public static DirectProperty<PointerCanvas, string?> StatusProperty = public static readonly DirectProperty<PointerCanvas, string?> StatusProperty =
AvaloniaProperty.RegisterDirect<PointerCanvas, string?>(nameof(DrawOnlyPoints), c => c.Status, (c, v) => c.Status = v, AvaloniaProperty.RegisterDirect<PointerCanvas, string?>(nameof(Status), c => c.Status, (c, v) => c.Status = v,
defaultBindingMode: Avalonia.Data.BindingMode.TwoWay); defaultBindingMode: Avalonia.Data.BindingMode.TwoWay);
public string? Status public string? Status

2
samples/ControlCatalog/Pages/RefreshContainerPage.axaml

@ -21,7 +21,7 @@
Margin="5"> Margin="5">
<ListBox HorizontalAlignment="Stretch" <ListBox HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
Items="{Binding Items}"/> ItemsSource="{Binding Items}"/>
</RefreshContainer> </RefreshContainer>
</DockPanel> </DockPanel>
</UserControl> </UserControl>

14
samples/ControlCatalog/Pages/RefreshContainerPage.axaml.cs

@ -1,18 +1,15 @@
using System.Threading.Tasks; using Avalonia.Controls;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.ViewModels; using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public class RefreshContainerPage : UserControl public partial class RefreshContainerPage : UserControl
{ {
private RefreshContainerViewModel _viewModel; private RefreshContainerViewModel _viewModel;
public RefreshContainerPage() public RefreshContainerPage()
{ {
this.InitializeComponent(); InitializeComponent();
_viewModel = new RefreshContainerViewModel(); _viewModel = new RefreshContainerViewModel();
@ -27,10 +24,5 @@ namespace ControlCatalog.Pages
deferral.Complete(); deferral.Complete();
} }
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
} }
} }

13
samples/ControlCatalog/Pages/RelativePanelPage.axaml.cs

@ -1,19 +1,12 @@
using Avalonia; using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public class RelativePanelPage : UserControl public partial class RelativePanelPage : UserControl
{ {
public RelativePanelPage() public RelativePanelPage()
{ {
this.InitializeComponent(); InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
} }
} }
} }

222
samples/ControlCatalog/Pages/ScrollSnapPage.xaml

@ -1,222 +0,0 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DesignHeight="800"
d:DesignWidth="400"
x:Class="ControlCatalog.Pages.ScrollSnapPage"
xmlns:pages="using:ControlCatalog.Pages"
x:DataType="pages:ScrollSnapPageViewModel">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock TextWrapping="Wrap"
Classes="h2">Scrollviewer can snap supported content both vertically and horizontally. Snapping occurs from scrolling with touch or pen.</TextBlock>
<Grid RowDefinitions="Auto, Auto, Auto, Auto, Auto">
<StackPanel Orientation="Horizontal"
Spacing="4">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="Snap Point Type" />
<ComboBox Items="{Binding AvailableSnapPointsType}"
SelectedItem="{Binding SnapPointsType}" />
</StackPanel>
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="Snap Point Alignment" />
<ComboBox Items="{Binding AvailableSnapPointsAlignment}"
SelectedItem="{Binding SnapPointsAlignment}" />
</StackPanel>
<ToggleSwitch IsChecked="{Binding AreSnapPointsRegular}"
OffContent="No"
OnContent="Yes"
Content="Are Snap Points regular?" />
</StackPanel>
<TextBlock TextWrapping="Wrap"
Grid.Row="1"
Margin="0,10"
Classes="h2">Vertical Snapping</TextBlock>
<Border
BorderBrush="Green"
BorderThickness="1"
Padding="0"
Grid.Row="2"
Margin="10, 5">
<ScrollViewer x:Name="VerticalSnapsScrollViewer"
VerticalSnapPointsType="{Binding SnapPointsType}"
VerticalSnapPointsAlignment="{Binding SnapPointsAlignment}"
HorizontalAlignment="Stretch"
Height="350"
HorizontalScrollBarVisibility="Disabled">
<StackPanel AreVerticalSnapPointsRegular="{Binding AreSnapPointsRegular}"
Orientation="Vertical"
HorizontalAlignment="Stretch">
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 1"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 2"/>
</Border>
<Border Padding="5, 20"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 3"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 4"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 5"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 6"/>
</Border>
<Border Padding="5,8"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 7"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 8"/>
</Border>
<Border Padding="5,4"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 9"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 20"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 11"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 12"/>
</Border>
</StackPanel>
</ScrollViewer>
</Border>
<TextBlock TextWrapping="Wrap"
Grid.Row="3"
Margin="0,10"
Classes="h2">Horizontal Snapping</TextBlock>
<Border
BorderBrush="Green"
BorderThickness="1"
Padding="0"
Grid.Row="4"
Margin="10, 10">
<ScrollViewer x:Name="HorizontalSnapsScrollViewer"
HorizontalSnapPointsType="{Binding SnapPointsType}"
HorizontalSnapPointsAlignment="{Binding SnapPointsAlignment}"
HorizontalAlignment="Stretch"
Height="350"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<StackPanel AreHorizontalSnapPointsRegular="{Binding AreSnapPointsRegular}"
Orientation="Horizontal"
HorizontalAlignment="Stretch">
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 1"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 2"/>
</Border>
<Border Padding="5, 20"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 3"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 4"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 5"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 6"/>
</Border>
</StackPanel>
</ScrollViewer>
</Border>
</Grid>
</StackPanel>
</UserControl>

68
samples/ControlCatalog/Pages/ScrollSnapPage.xaml.cs

@ -1,68 +0,0 @@
using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using MiniMvvm;
namespace ControlCatalog.Pages
{
public class ScrollSnapPageViewModel : ViewModelBase
{
private SnapPointsType _snapPointsType;
private SnapPointsAlignment _snapPointsAlignment;
private bool _areSnapPointsRegular;
public ScrollSnapPageViewModel()
{
AvailableSnapPointsType = new List<SnapPointsType>()
{
SnapPointsType.None,
SnapPointsType.Mandatory,
SnapPointsType.MandatorySingle
};
AvailableSnapPointsAlignment = new List<SnapPointsAlignment>()
{
SnapPointsAlignment.Near,
SnapPointsAlignment.Center,
SnapPointsAlignment.Far,
};
}
public bool AreSnapPointsRegular
{
get => _areSnapPointsRegular;
set => this.RaiseAndSetIfChanged(ref _areSnapPointsRegular, value);
}
public SnapPointsType SnapPointsType
{
get => _snapPointsType;
set => this.RaiseAndSetIfChanged(ref _snapPointsType, value);
}
public SnapPointsAlignment SnapPointsAlignment
{
get => _snapPointsAlignment;
set => this.RaiseAndSetIfChanged(ref _snapPointsAlignment, value);
}
public List<SnapPointsType> AvailableSnapPointsType { get; }
public List<SnapPointsAlignment> AvailableSnapPointsAlignment { get; }
}
public class ScrollSnapPage : UserControl
{
public ScrollSnapPage()
{
this.InitializeComponent();
DataContext = new ScrollSnapPageViewModel();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

290
samples/ControlCatalog/Pages/ScrollViewerPage.xaml

@ -3,35 +3,267 @@
xmlns:pages="using:ControlCatalog.Pages" xmlns:pages="using:ControlCatalog.Pages"
x:Class="ControlCatalog.Pages.ScrollViewerPage" x:Class="ControlCatalog.Pages.ScrollViewerPage"
x:DataType="pages:ScrollViewerPageViewModel"> x:DataType="pages:ScrollViewerPageViewModel">
<StackPanel Orientation="Vertical" Spacing="20"> <TabControl>
<TextBlock TextWrapping="Wrap" Classes="h2">Allows for horizontal and vertical content scrolling. Supports snapping on touch and pointer wheel scrolling.</TextBlock> <TabItem Header="ScrollViewer">
<StackPanel Orientation="Vertical"
<Grid ColumnDefinitions="Auto, *"> Spacing="20">
<StackPanel Orientation="Vertical" Spacing="4"> <TextBlock TextWrapping="Wrap"
<ToggleSwitch IsChecked="{Binding AllowAutoHide}" Content="Allow auto hide" /> Classes="h2">Allows for horizontal and vertical content scrolling. Supports snapping on touch and pointer wheel scrolling.</TextBlock>
<ToggleSwitch IsChecked="{Binding EnableInertia}" Content="Enable Inertia" />
<Grid ColumnDefinitions="Auto, *">
<StackPanel Orientation="Vertical" Spacing="4"> <StackPanel Orientation="Vertical"
<TextBlock Text="Horizontal Scroll" /> Spacing="4">
<ComboBox Items="{Binding AvailableVisibility}" SelectedItem="{Binding HorizontalScrollVisibility}" /> <ToggleSwitch IsChecked="{Binding AllowAutoHide}"
</StackPanel> Content="Allow auto hide" />
<ToggleSwitch IsChecked="{Binding EnableInertia}"
<StackPanel Orientation="Vertical" Spacing="4"> Content="Enable Inertia" />
<TextBlock Text="Vertical Scroll" />
<ComboBox Items="{Binding AvailableVisibility}" SelectedItem="{Binding VerticalScrollVisibility}" /> <StackPanel Orientation="Vertical"
</StackPanel> Spacing="4">
<TextBlock Text="Horizontal Scroll" />
<ComboBox ItemsSource="{Binding AvailableVisibility}"
SelectedItem="{Binding HorizontalScrollVisibility}" />
</StackPanel>
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="Vertical Scroll" />
<ComboBox ItemsSource="{Binding AvailableVisibility}"
SelectedItem="{Binding VerticalScrollVisibility}" />
</StackPanel>
</StackPanel>
<ScrollViewer x:Name="ScrollViewer"
Grid.Column="1"
Width="400"
Height="400"
IsScrollInertiaEnabled="{Binding EnableInertia}"
AllowAutoHide="{Binding AllowAutoHide}"
HorizontalScrollBarVisibility="{Binding HorizontalScrollVisibility}"
VerticalScrollBarVisibility="{Binding VerticalScrollVisibility}">
<Image Width="800"
Height="800"
Stretch="UniformToFill"
Source="/Assets/delicate-arch-896885_640.jpg" />
</ScrollViewer>
</Grid>
</StackPanel> </StackPanel>
</TabItem>
<TabItem Header="Snapping">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock TextWrapping="Wrap"
Classes="h2">Scrollviewer can snap supported content both vertically and horizontally. Snapping occurs from scrolling with touch or pen.</TextBlock>
<Grid RowDefinitions="Auto, Auto, Auto, Auto, Auto">
<StackPanel Orientation="Horizontal"
Spacing="4">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="Snap Point Type" />
<ComboBox ItemsSource="{Binding AvailableSnapPointsType}"
SelectedItem="{Binding SnapPointsType}" />
</StackPanel>
<ScrollViewer x:Name="ScrollViewer" <StackPanel Orientation="Vertical"
Grid.Column="1" Spacing="4">
Width="400" Height="400" <TextBlock Text="Snap Point Alignment" />
IsScrollInertiaEnabled="{Binding EnableInertia}" <ComboBox ItemsSource="{Binding AvailableSnapPointsAlignment}"
AllowAutoHide="{Binding AllowAutoHide}" SelectedItem="{Binding SnapPointsAlignment}" />
HorizontalScrollBarVisibility="{Binding HorizontalScrollVisibility}" </StackPanel>
VerticalScrollBarVisibility="{Binding VerticalScrollVisibility}">
<Image Width="800" Height="800" Stretch="UniformToFill" <ToggleSwitch IsChecked="{Binding AreSnapPointsRegular}"
Source="/Assets/delicate-arch-896885_640.jpg" /> OffContent="No"
</ScrollViewer> OnContent="Yes"
</Grid> Content="Are Snap Points regular?" />
</StackPanel> </StackPanel>
<TextBlock TextWrapping="Wrap"
Grid.Row="1"
Margin="0,10"
Classes="h2">Vertical Snapping</TextBlock>
<Border
BorderBrush="Green"
BorderThickness="1"
Padding="0"
Grid.Row="2"
Margin="10, 5">
<ScrollViewer x:Name="VerticalSnapsScrollViewer"
VerticalSnapPointsType="{Binding SnapPointsType}"
VerticalSnapPointsAlignment="{Binding SnapPointsAlignment}"
HorizontalAlignment="Stretch"
Height="350"
HorizontalScrollBarVisibility="Disabled">
<StackPanel AreVerticalSnapPointsRegular="{Binding AreSnapPointsRegular}"
Orientation="Vertical"
HorizontalAlignment="Stretch">
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 1"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 2"/>
</Border>
<Border Padding="5, 20"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 3"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 4"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 5"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 6"/>
</Border>
<Border Padding="5,8"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 7"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 8"/>
</Border>
<Border Padding="5,4"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 9"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 20"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 11"/>
</Border>
<Border Padding="5, 30"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
Text="Child 12"/>
</Border>
</StackPanel>
</ScrollViewer>
</Border>
<TextBlock TextWrapping="Wrap"
Grid.Row="3"
Margin="0,10"
Classes="h2">Horizontal Snapping</TextBlock>
<Border
BorderBrush="Green"
BorderThickness="1"
Padding="0"
Grid.Row="4"
Margin="10, 10">
<ScrollViewer x:Name="HorizontalSnapsScrollViewer"
HorizontalSnapPointsType="{Binding SnapPointsType}"
HorizontalSnapPointsAlignment="{Binding SnapPointsAlignment}"
HorizontalAlignment="Stretch"
Height="350"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<StackPanel AreHorizontalSnapPointsRegular="{Binding AreSnapPointsRegular}"
Orientation="Horizontal"
HorizontalAlignment="Stretch">
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
HorizontalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 1"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 2"/>
</Border>
<Border Padding="5, 20"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 3"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 4"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 5"/>
</Border>
<Border Padding="5, 30"
Width="300"
BorderBrush="Red"
VerticalAlignment="Stretch"
BorderThickness="1">
<TextBlock FontWeight="Bold"
VerticalAlignment="Center"
Text="Child 6"/>
</Border>
</StackPanel>
</ScrollViewer>
</Border>
</Grid>
</StackPanel>
</TabItem>
</TabControl>
</UserControl> </UserControl>

37
samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs

@ -12,6 +12,9 @@ namespace ControlCatalog.Pages
private bool _enableInertia; private bool _enableInertia;
private ScrollBarVisibility _horizontalScrollVisibility; private ScrollBarVisibility _horizontalScrollVisibility;
private ScrollBarVisibility _verticalScrollVisibility; private ScrollBarVisibility _verticalScrollVisibility;
private SnapPointsType _snapPointsType;
private SnapPointsAlignment _snapPointsAlignment;
private bool _areSnapPointsRegular;
public ScrollViewerPageViewModel() public ScrollViewerPageViewModel()
{ {
@ -23,6 +26,20 @@ namespace ControlCatalog.Pages
ScrollBarVisibility.Disabled, ScrollBarVisibility.Disabled,
}; };
AvailableSnapPointsType = new List<SnapPointsType>()
{
SnapPointsType.None,
SnapPointsType.Mandatory,
SnapPointsType.MandatorySingle
};
AvailableSnapPointsAlignment = new List<SnapPointsAlignment>()
{
SnapPointsAlignment.Near,
SnapPointsAlignment.Center,
SnapPointsAlignment.Far,
};
HorizontalScrollVisibility = ScrollBarVisibility.Auto; HorizontalScrollVisibility = ScrollBarVisibility.Auto;
VerticalScrollVisibility = ScrollBarVisibility.Auto; VerticalScrollVisibility = ScrollBarVisibility.Auto;
AllowAutoHide = true; AllowAutoHide = true;
@ -54,6 +71,26 @@ namespace ControlCatalog.Pages
} }
public List<ScrollBarVisibility> AvailableVisibility { get; } public List<ScrollBarVisibility> AvailableVisibility { get; }
public bool AreSnapPointsRegular
{
get => _areSnapPointsRegular;
set => this.RaiseAndSetIfChanged(ref _areSnapPointsRegular, value);
}
public SnapPointsType SnapPointsType
{
get => _snapPointsType;
set => this.RaiseAndSetIfChanged(ref _snapPointsType, value);
}
public SnapPointsAlignment SnapPointsAlignment
{
get => _snapPointsAlignment;
set => this.RaiseAndSetIfChanged(ref _snapPointsAlignment, value);
}
public List<SnapPointsType> AvailableSnapPointsType { get; }
public List<SnapPointsAlignment> AvailableSnapPointsAlignment { get; }
} }
public class ScrollViewerPage : UserControl public class ScrollViewerPage : UserControl

2
samples/ControlCatalog/Pages/TabControlPage.xaml

@ -51,7 +51,7 @@
Text="From DataTemplate"> Text="From DataTemplate">
</TextBlock> </TextBlock>
<TabControl <TabControl
Items="{Binding Tabs}" ItemsSource="{Binding Tabs}"
Margin="0 16" Margin="0 16"
DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}" DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
TabStripPlacement="{Binding TabPlacement}"> TabStripPlacement="{Binding TabPlacement}">

2
samples/ControlCatalog/Pages/TabStripPage.xaml

@ -18,7 +18,7 @@
<Separator Margin="0 16"/> <Separator Margin="0 16"/>
<TextBlock Classes="h1">Dynamically generated</TextBlock> <TextBlock Classes="h1">Dynamically generated</TextBlock>
<TabStrip Items="{Binding Tabs}"> <TabStrip ItemsSource="{Binding Tabs}">
<TabStrip.Styles> <TabStrip.Styles>
<Style Selector="TabStripItem" x:DataType="viewModels:TabControlPageViewModelItem"> <Style Selector="TabStripItem" x:DataType="viewModels:TabControlPageViewModelItem">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/> <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>

20
samples/ControlCatalog/Pages/ThemePage.axaml.cs

@ -1,35 +1,31 @@
using Avalonia; using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Styling; using Avalonia.Styling;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public class ThemePage : UserControl public partial class ThemePage : UserControl
{ {
public static ThemeVariant Pink { get; } = new("Pink", ThemeVariant.Light); public static ThemeVariant Pink { get; } = new("Pink", ThemeVariant.Light);
public ThemePage() public ThemePage()
{ {
AvaloniaXamlLoader.Load(this); InitializeComponent();
var selector = this.FindControl<ComboBox>("Selector")!; Selector.ItemsSource = new[]
var themeVariantScope = this.FindControl<ThemeVariantScope>("ThemeVariantScope")!;
selector.Items = new[]
{ {
ThemeVariant.Default, ThemeVariant.Default,
ThemeVariant.Dark, ThemeVariant.Dark,
ThemeVariant.Light, ThemeVariant.Light,
Pink Pink
}; };
selector.SelectedIndex = 0; Selector.SelectedIndex = 0;
selector.SelectionChanged += (_, _) => Selector.SelectionChanged += (_, _) =>
{ {
if (selector.SelectedItem is ThemeVariant theme) if (Selector.SelectedItem is ThemeVariant theme)
{ {
themeVariantScope.RequestedThemeVariant = theme; ThemeVariantScope.RequestedThemeVariant = theme;
} }
}; };
} }

2
samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml

@ -53,7 +53,7 @@
<StackPanel Margin="5" Spacing="5" Grid.IsSharedSizeScope="True"> <StackPanel Margin="5" Spacing="5" Grid.IsSharedSizeScope="True">
<HeaderedContentControl Header="Select a transition"> <HeaderedContentControl Header="Select a transition">
<ComboBox Items="{Binding PageTransitions}" SelectedItem="{Binding SelectedTransition}" /> <ComboBox ItemsSource="{Binding PageTransitions}" SelectedItem="{Binding SelectedTransition}" />
</HeaderedContentControl> </HeaderedContentControl>
<HeaderedContentControl Header="Duration"> <HeaderedContentControl Header="Duration">
<NumericUpDown Value="{Binding Duration}" Increment="250" Minimum="100" /> <NumericUpDown Value="{Binding Duration}" Increment="250" Minimum="100" />

2
samples/ControlCatalog/Pages/TreeViewPage.xaml

@ -11,7 +11,7 @@
HorizontalAlignment="Center" HorizontalAlignment="Center"
Spacing="16"> Spacing="16">
<StackPanel Orientation="Vertical" Spacing="8"> <StackPanel Orientation="Vertical" Spacing="8">
<TreeView Items="{Binding Items}" SelectedItems="{Binding SelectedItems}" SelectionMode="{Binding SelectionMode}" Width="250" Height="350"> <TreeView ItemsSource="{Binding Items}" SelectedItems="{Binding SelectedItems}" SelectionMode="{Binding SelectionMode}" Width="250" Height="350">
<TreeView.ItemTemplate> <TreeView.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}"> <TreeDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Header}"/> <TextBlock Text="{Binding Header}"/>

22
samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml

@ -5,11 +5,21 @@
xmlns:viewModels="using:ControlCatalog.ViewModels" xmlns:viewModels="using:ControlCatalog.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ControlCatalog.Pages.WindowCustomizationsPage" x:Class="ControlCatalog.Pages.WindowCustomizationsPage"
x:DataType="viewModels:MainWindowViewModel"> x:DataType="viewModels:MainWindowViewModel"
<StackPanel Spacing="10" Margin="25"> x:CompileBindings="True">
<CheckBox Content="Extend Client Area to Decorations" IsChecked="{Binding ExtendClientAreaEnabled}" /> <StackPanel>
<CheckBox Content="Title Bar" IsChecked="{Binding SystemTitleBarEnabled}" /> <StackPanel Spacing="10" Margin="25" IsEnabled="{OnFormFactor false, Desktop=true}">
<CheckBox Content="Prefer System Chrome" IsChecked="{Binding PreferSystemChromeEnabled}" /> <TextBlock Classes="h2" Text="Desktop properties" Margin="4" />
<Slider Minimum="-1" Maximum="200" Value="{Binding TitleBarHeight}" /> <CheckBox Content="Extend Client Area to Decorations" IsChecked="{Binding ExtendClientAreaEnabled}" />
<CheckBox Content="Title Bar" IsChecked="{Binding SystemTitleBarEnabled}" />
<CheckBox Content="Prefer System Chrome" IsChecked="{Binding PreferSystemChromeEnabled}" />
<Slider Minimum="-1" Maximum="200" Value="{Binding TitleBarHeight}" />
</StackPanel>
<StackPanel Spacing="10" Margin="25" IsEnabled="{OnFormFactor false, Mobile=true}">
<TextBlock Classes="h2" Text="Mobile properties" Margin="4" />
<CheckBox Content="Is System Bar Visible" IsChecked="{Binding IsSystemBarVisible}" />
<CheckBox Content="Display Edge To Edge" IsChecked="{Binding DisplayEdgeToEdge}" />
<TextBlock Text="{Binding SafeAreaPadding, StringFormat='Safe Area Padding: {0}'}" />
</StackPanel>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

30
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -6,6 +6,7 @@ using Avalonia.Platform;
using Avalonia.Reactive; using Avalonia.Reactive;
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Avalonia;
using MiniMvvm; using MiniMvvm;
namespace ControlCatalog.ViewModels namespace ControlCatalog.ViewModels
@ -20,6 +21,9 @@ namespace ControlCatalog.ViewModels
private bool _systemTitleBarEnabled; private bool _systemTitleBarEnabled;
private bool _preferSystemChromeEnabled; private bool _preferSystemChromeEnabled;
private double _titleBarHeight; private double _titleBarHeight;
private bool _isSystemBarVisible;
private bool _displayEdgeToEdge;
private Thickness _safeAreaPadding;
public MainWindowViewModel() public MainWindowViewModel()
{ {
@ -78,25 +82,25 @@ namespace ControlCatalog.ViewModels
{ {
get { return _chromeHints; } get { return _chromeHints; }
set { this.RaiseAndSetIfChanged(ref _chromeHints, value); } set { this.RaiseAndSetIfChanged(ref _chromeHints, value); }
} }
public bool ExtendClientAreaEnabled public bool ExtendClientAreaEnabled
{ {
get { return _extendClientAreaEnabled; } get { return _extendClientAreaEnabled; }
set { this.RaiseAndSetIfChanged(ref _extendClientAreaEnabled, value); } set { this.RaiseAndSetIfChanged(ref _extendClientAreaEnabled, value); }
} }
public bool SystemTitleBarEnabled public bool SystemTitleBarEnabled
{ {
get { return _systemTitleBarEnabled; } get { return _systemTitleBarEnabled; }
set { this.RaiseAndSetIfChanged(ref _systemTitleBarEnabled, value); } set { this.RaiseAndSetIfChanged(ref _systemTitleBarEnabled, value); }
} }
public bool PreferSystemChromeEnabled public bool PreferSystemChromeEnabled
{ {
get { return _preferSystemChromeEnabled; } get { return _preferSystemChromeEnabled; }
set { this.RaiseAndSetIfChanged(ref _preferSystemChromeEnabled, value); } set { this.RaiseAndSetIfChanged(ref _preferSystemChromeEnabled, value); }
} }
public double TitleBarHeight public double TitleBarHeight
{ {
@ -122,6 +126,24 @@ namespace ControlCatalog.ViewModels
set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); } set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); }
} }
public bool IsSystemBarVisible
{
get { return _isSystemBarVisible; }
set { this.RaiseAndSetIfChanged(ref _isSystemBarVisible, value); }
}
public bool DisplayEdgeToEdge
{
get { return _displayEdgeToEdge; }
set { this.RaiseAndSetIfChanged(ref _displayEdgeToEdge, value); }
}
public Thickness SafeAreaPadding
{
get { return _safeAreaPadding; }
set { this.RaiseAndSetIfChanged(ref _safeAreaPadding, value); }
}
public MiniCommand AboutCommand { get; } public MiniCommand AboutCommand { get; }
public MiniCommand ExitCommand { get; } public MiniCommand ExitCommand { get; }

7
samples/Generators.Sandbox/App.xaml

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

20
samples/Generators.Sandbox/App.xaml.cs

@ -0,0 +1,20 @@
using Avalonia;
using Avalonia.Markup.Xaml;
using Generators.Sandbox.ViewModels;
namespace Generators.Sandbox;
public class App : Application
{
public override void Initialize() => AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
{
var view = new Views.SignUpView
{
ViewModel = new SignUpViewModel()
};
view.Show();
base.OnFrameworkInitializationCompleted();
}
}

10
samples/Generators.Sandbox/Controls/CustomTextBox.cs

@ -0,0 +1,10 @@
using System;
using Avalonia.Controls;
using Avalonia.Styling;
namespace Generators.Sandbox.Controls;
public class CustomTextBox : TextBox, IStyleable
{
Type IStyleable.StyleKey => typeof(TextBox);
}

45
samples/Generators.Sandbox/Controls/SignUpView.xaml

@ -0,0 +1,45 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Generators.Sandbox.Controls"
x:Class="Generators.Sandbox.Controls.SignUpView">
<StackPanel>
<controls:CustomTextBox Margin="0 10 0 0"
x:Name="UserNameTextBox"
Watermark="Please, enter user name..."
UseFloatingWatermark="True" />
<TextBlock x:Name="UserNameValidation"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="PasswordTextBox"
Watermark="Please, enter your password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="PasswordValidation"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="ConfirmPasswordTextBox"
Watermark="Please, confirm the password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="ConfirmPasswordValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
<TextBlock>
<TextBlock.Inlines>
<InlineCollection>
<Run x:Name="SignUpButtonDescription" />
</InlineCollection>
</TextBlock.Inlines>
</TextBlock>
<Button Margin="0 10 0 5"
Content="Sign up"
x:Name="SignUpButton" />
<TextBlock x:Name="CompoundValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
</StackPanel>
</UserControl>

54
samples/Generators.Sandbox/Controls/SignUpView.xaml.cs

@ -0,0 +1,54 @@
using System;
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using Generators.Sandbox.ViewModels;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using ReactiveUI.Validation.Formatters;
namespace Generators.Sandbox.Controls;
/// <summary>
/// This is a sample view class with typed x:Name references generated using
/// .NET 5 source generators. The class has to be partial because x:Name
/// references are living in a separate partial class file. See also:
/// https://devblogs.microsoft.com/dotnet/new-c-source-generator-samples/
/// </summary>
public partial class SignUpView : ReactiveUserControl<SignUpViewModel>
{
public SignUpView()
{
// The InitializeComponent method is also generated automatically
// and lives in the autogenerated part of the partial class.
InitializeComponent();
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, x => x.UserName, x => x.UserNameTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.Password, x => x.PasswordTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordTextBox.Text)
.DisposeWith(disposables);
this.BindCommand(ViewModel, x => x.SignUp, x => x.SignUpButton)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.UserName, x => x.UserNameValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordValidation.Text)
.DisposeWith(disposables);
var newLineFormatter = new SingleLineFormatter(Environment.NewLine);
this.BindValidation(ViewModel, x => x.CompoundValidation.Text, newLineFormatter)
.DisposeWith(disposables);
// The references to text boxes below are also auto generated.
// Use Ctrl+Click in order to view the generated sources.
UserNameTextBox.Text = "Joseph!";
PasswordTextBox.Text = "1234";
ConfirmPasswordTextBox.Text = "1234";
SignUpButtonDescription.Text = "Press the button below to sign up.";
});
}
}

28
samples/Generators.Sandbox/Generators.Sandbox.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="**\*.xaml"/>
<!-- Note this AdditionalFiles directive. -->
<AdditionalFiles Include="**\*.xaml"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReactiveUI.Validation" Version="3.0.22"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj"/>
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets"/>
<Import Project="..\..\build\SourceGenerators.props"/>
</Project>

15
samples/Generators.Sandbox/Program.cs

@ -0,0 +1,15 @@
using Avalonia;
using Avalonia.ReactiveUI;
namespace Generators.Sandbox;
internal static class Program
{
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
private static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UseReactiveUI()
.UsePlatformDetect()
.LogToTrace();
}

70
samples/Generators.Sandbox/ViewModels/SignUpViewModel.cs

@ -0,0 +1,70 @@
using System.Reactive;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using ReactiveUI.Validation.Helpers;
namespace Generators.Sandbox.ViewModels;
public class SignUpViewModel : ReactiveValidationObject
{
private string _userName = string.Empty;
private string _password = string.Empty;
private string _confirmPassword = string.Empty;
public SignUpViewModel()
{
this.ValidationRule(
vm => vm.UserName,
name => !string.IsNullOrWhiteSpace(name),
"UserName is required.");
this.ValidationRule(
vm => vm.Password,
password => !string.IsNullOrWhiteSpace(password),
"Password is required.");
this.ValidationRule(
vm => vm.Password,
password => password?.Length > 2,
password => $"Password should be longer, current length: {password.Length}");
this.ValidationRule(
vm => vm.ConfirmPassword,
confirmation => !string.IsNullOrWhiteSpace(confirmation),
"Confirm password field is required.");
var passwordsObservable =
this.WhenAnyValue(
x => x.Password,
x => x.ConfirmPassword,
(password, confirmation) =>
password == confirmation);
this.ValidationRule(
vm => vm.ConfirmPassword,
passwordsObservable,
"Passwords must match.");
SignUp = ReactiveCommand.Create(() => {}, this.IsValid());
}
public ReactiveCommand<Unit, Unit> SignUp { get; }
public string UserName
{
get => _userName;
set => this.RaiseAndSetIfChanged(ref _userName, value);
}
public string Password
{
get => _password;
set => this.RaiseAndSetIfChanged(ref _password, value);
}
public string ConfirmPassword
{
get => _confirmPassword;
set => this.RaiseAndSetIfChanged(ref _confirmPassword, value);
}
}

9
samples/Generators.Sandbox/Views/SignUpView.xaml

@ -0,0 +1,9 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Generators.Sandbox.Controls"
x:Class="Generators.Sandbox.Views.SignUpView">
<StackPanel Margin="10">
<TextBlock Text="Sign Up" />
<controls:SignUpView x:Name="SignUpControl" />
</StackPanel>
</Window>

28
samples/Generators.Sandbox/Views/SignUpView.xaml.cs

@ -0,0 +1,28 @@
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using Generators.Sandbox.ViewModels;
using ReactiveUI;
namespace Generators.Sandbox.Views;
/// <summary>
/// This is a sample view class with typed x:Name references generated using
/// .NET 5 source generators. The class has to be partial because x:Name
/// references are living in a separate partial class file. See also:
/// https://devblogs.microsoft.com/dotnet/new-c-source-generator-samples/
/// </summary>
public partial class SignUpView : ReactiveWindow<SignUpViewModel>
{
public SignUpView()
{
// The InitializeComponent method is also generated automatically
// and lives in the autogenerated part of the partial class.
InitializeComponent();
this.WhenActivated(disposables =>
{
this.WhenAnyValue(view => view.ViewModel)
.BindTo(this, view => view.SignUpControl.ViewModel)
.DisposeWith(disposables);
});
}
}

1
samples/GpuInterop/GpuInterop.csproj

@ -15,6 +15,7 @@
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
</ItemGroup> </ItemGroup>

1
samples/IntegrationTestApp/IntegrationTestApp.csproj

@ -19,6 +19,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" /> <Import Project="..\..\build\BuildTargets.targets" />

12
samples/IntegrationTestApp/MainWindow.axaml

@ -25,6 +25,7 @@
<StackPanel DockPanel.Dock="Bottom" Margin="4" Orientation="Horizontal"> <StackPanel DockPanel.Dock="Bottom" Margin="4" Orientation="Horizontal">
<TextBlock Margin="0,0,4,0">WindowState:</TextBlock> <TextBlock Margin="0,0,4,0">WindowState:</TextBlock>
<TextBlock Name="MainWindowState" Text="{Binding WindowState}"/> <TextBlock Name="MainWindowState" Text="{Binding WindowState}"/>
<TextBlock Name="AppOverlayPopups" Margin="8 0"/>
</StackPanel> </StackPanel>
<TabControl TabStripPlacement="Left" Name="MainTabs"> <TabControl TabStripPlacement="Left" Name="MainTabs">
@ -108,7 +109,7 @@
<StackPanel DockPanel.Dock="Bottom"> <StackPanel DockPanel.Dock="Bottom">
<Button Name="ListBoxSelectionClear">Clear Selection</Button> <Button Name="ListBoxSelectionClear">Clear Selection</Button>
</StackPanel> </StackPanel>
<ListBox Name="BasicListBox" Items="{Binding ListBoxItems}" SelectionMode="Multiple"/> <ListBox Name="BasicListBox" ItemsSource="{Binding ListBoxItems}" SelectionMode="Multiple"/>
</DockPanel> </DockPanel>
</TabItem> </TabItem>
@ -150,6 +151,12 @@
<ComboBoxItem Name="ShowWindowStateMaximized">Maximized</ComboBoxItem> <ComboBoxItem Name="ShowWindowStateMaximized">Maximized</ComboBoxItem>
<ComboBoxItem Name="ShowWindowStateFullScreen">FullScreen</ComboBoxItem> <ComboBoxItem Name="ShowWindowStateFullScreen">FullScreen</ComboBoxItem>
</ComboBox> </ComboBox>
<ComboBox Name="ShowWindowSystemDecorations" SelectedIndex="2">
<ComboBoxItem Name="ShowWindowSystemDecorationsNone">None</ComboBoxItem>
<ComboBoxItem Name="ShowWindowSystemDecorationsBorderOnly">BorderOnly</ComboBoxItem>
<ComboBoxItem Name="ShowWindowSystemDecorationsFull">Full</ComboBoxItem>
</ComboBox>
<CheckBox Name="ShowWindowExtendClientAreaToDecorationsHint">ExtendClientAreaToDecorationsHint</CheckBox>
<CheckBox Name="ShowWindowCanResize" IsChecked="True">Can Resize</CheckBox> <CheckBox Name="ShowWindowCanResize" IsChecked="True">Can Resize</CheckBox>
<Button Name="ShowWindow">Show Window</Button> <Button Name="ShowWindow">Show Window</Button>
<Button Name="SendToBack">Send to Back</Button> <Button Name="SendToBack">Send to Back</Button>
@ -166,6 +173,9 @@
<TabItem Header="SliderTab"> <TabItem Header="SliderTab">
<Slider VerticalAlignment="Top" Name="Slider" Value="30"/> <Slider VerticalAlignment="Top" Name="Slider" Value="30"/>
</TabItem> </TabItem>
<TabItem Header="ScrollBarTab">
<ScrollBar Name="MyScrollBar" Orientation="Horizontal" AllowAutoHide="False" Width="200" Height="30" Value="20"/>
</TabItem>
</TabControl> </TabControl>
</DockPanel> </DockPanel>
</Window> </Window>

18
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -1,19 +1,17 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Avalonia; using Avalonia;
using Avalonia.Automation; using Avalonia.Automation;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Avalonia.Controls.Primitives;
using Avalonia.Threading;
using Avalonia.Controls.Primitives.PopupPositioning;
namespace IntegrationTestApp namespace IntegrationTestApp
{ {
@ -25,6 +23,10 @@ namespace IntegrationTestApp
InitializeViewMenu(); InitializeViewMenu();
InitializeGesturesTab(); InitializeGesturesTab();
this.AttachDevTools(); this.AttachDevTools();
var overlayPopups = this.Get<TextBlock>("AppOverlayPopups");
overlayPopups.Text = Program.OverlayPopups ? "Overlay Popups" : "Native Popups";
AddHandler(Button.ClickEvent, OnButtonClick); AddHandler(Button.ClickEvent, OnButtonClick);
ListBoxItems = Enumerable.Range(0, 100).Select(x => "Item " + x).ToList(); ListBoxItems = Enumerable.Range(0, 100).Select(x => "Item " + x).ToList();
DataContext = this; DataContext = this;
@ -66,6 +68,8 @@ namespace IntegrationTestApp
var locationComboBox = this.GetControl<ComboBox>("ShowWindowLocation"); var locationComboBox = this.GetControl<ComboBox>("ShowWindowLocation");
var stateComboBox = this.GetControl<ComboBox>("ShowWindowState"); var stateComboBox = this.GetControl<ComboBox>("ShowWindowState");
var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null; var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null;
var systemDecorations = this.GetControl<ComboBox>("ShowWindowSystemDecorations");
var extendClientArea = this.GetControl<CheckBox>("ShowWindowExtendClientAreaToDecorationsHint");
var canResizeCheckBox = this.GetControl<CheckBox>("ShowWindowCanResize"); var canResizeCheckBox = this.GetControl<CheckBox>("ShowWindowCanResize");
var owner = (Window)this.GetVisualRoot()!; var owner = (Window)this.GetVisualRoot()!;
@ -93,6 +97,8 @@ namespace IntegrationTestApp
} }
sizeTextBox.Text = string.Empty; sizeTextBox.Text = string.Empty;
window.ExtendClientAreaToDecorationsHint = extendClientArea.IsChecked ?? false;
window.SystemDecorations = (SystemDecorations)systemDecorations.SelectedIndex;
window.WindowState = (WindowState)stateComboBox.SelectedIndex; window.WindowState = (WindowState)stateComboBox.SelectedIndex;
switch (modeComboBox.SelectedIndex) switch (modeComboBox.SelectedIndex)
@ -156,7 +162,7 @@ namespace IntegrationTestApp
var popup = new Popup var popup = new Popup
{ {
WindowManagerAddShadowHint = false, WindowManagerAddShadowHint = false,
PlacementMode = PlacementMode.AnchorAndGravity, Placement = PlacementMode.AnchorAndGravity,
PlacementAnchor = PopupAnchor.Top, PlacementAnchor = PopupAnchor.Top,
PlacementGravity = PopupGravity.Bottom, PlacementGravity = PopupGravity.Bottom,
Width= 200, Width= 200,

22
samples/IntegrationTestApp/Program.cs

@ -1,17 +1,31 @@
using System; using System;
using System.Linq;
using Avalonia; using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace IntegrationTestApp namespace IntegrationTestApp
{ {
class Program class Program
{ {
public static bool OverlayPopups { get; private set; }
// Initialization code. Don't use any Avalonia, third-party APIs or any // Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break. // yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp() public static void Main(string[] args)
.StartWithClassicDesktopLifetime(args); {
OverlayPopups = args.Contains("--overlayPopups");
BuildAvaloniaApp()
.With(new Win32PlatformOptions
{
OverlayPopups = OverlayPopups,
})
.With(new AvaloniaNativePlatformOptions
{
OverlayPopups = OverlayPopups,
})
.StartWithClassicDesktopLifetime(args);
}
// Avalonia configuration, don't remove; also used by visual designer. // Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()

87
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -1,41 +1,60 @@
<Window xmlns="https://github.com/avaloniaui" <Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:integrationTestApp="clr-namespace:IntegrationTestApp"
x:Class="IntegrationTestApp.ShowWindowTest" x:Class="IntegrationTestApp.ShowWindowTest"
Name="SecondaryWindow" Name="SecondaryWindow"
x:DataType="Window" x:DataType="Window"
Title="Show Window Test"> Title="Show Window Test">
<Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> <integrationTestApp:MeasureBorder Name="MyBorder">
<Label Grid.Column="0" Grid.Row="1">Client Size</Label> <Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBox Name="ClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True" <Label Grid.Column="0" Grid.Row="1">Client Size</Label>
Text="{Binding ClientSize, Mode=OneWay}"/> <TextBox Name="CurrentClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True"
Text="{Binding ClientSize, Mode=OneWay}" />
<Label Grid.Column="0" Grid.Row="2">Frame Size</Label>
<TextBox Name="FrameSize" Grid.Column="1" Grid.Row="2" IsReadOnly="True" <Label Grid.Column="0" Grid.Row="2">Frame Size</Label>
Text="{Binding FrameSize, Mode=OneWay}"/> <TextBox Name="CurrentFrameSize" Grid.Column="1" Grid.Row="2" IsReadOnly="True"
Text="{Binding FrameSize, Mode=OneWay}" />
<Label Grid.Column="0" Grid.Row="3">Position</Label>
<TextBox Name="Position" Grid.Column="1" Grid.Row="3" IsReadOnly="True"/> <Label Grid.Column="0" Grid.Row="3">Position</Label>
<TextBox Name="CurrentPosition" Grid.Column="1" Grid.Row="3" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="4">Owner Rect</Label>
<TextBox Name="OwnerRect" Grid.Column="1" Grid.Row="4" IsReadOnly="True"/> <Label Grid.Column="0" Grid.Row="4">Owner Rect</Label>
<TextBox Name="CurrentOwnerRect" Grid.Column="1" Grid.Row="4" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="5">Screen Rect</Label>
<TextBox Name="ScreenRect" Grid.Column="1" Grid.Row="5" IsReadOnly="True"/> <Label Grid.Column="0" Grid.Row="5">Screen Rect</Label>
<TextBox Name="CurrentScreenRect" Grid.Column="1" Grid.Row="5" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="6">Scaling</Label>
<TextBox Name="Scaling" Grid.Column="1" Grid.Row="6" IsReadOnly="True"/> <Label Grid.Column="0" Grid.Row="6">Scaling</Label>
<TextBox Name="CurrentScaling" Grid.Column="1" Grid.Row="6" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="7">WindowState</Label>
<ComboBox Name="WindowState" Grid.Column="1" Grid.Row="7" SelectedIndex="{Binding WindowState}"> <Label Grid.Column="0" Grid.Row="7">WindowState</Label>
<ComboBoxItem Name="WindowStateNormal">Normal</ComboBoxItem> <ComboBox Name="CurrentWindowState" Grid.Column="1" Grid.Row="7" SelectedIndex="{Binding WindowState}">
<ComboBoxItem Name="WindowStateMinimized">Minimized</ComboBoxItem> <ComboBoxItem Name="WindowStateNormal">Normal</ComboBoxItem>
<ComboBoxItem Name="WindowStateMaximized">Maximized</ComboBoxItem> <ComboBoxItem Name="WindowStateMinimized">Minimized</ComboBoxItem>
<ComboBoxItem Name="WindowStateFullScreen">FullScreen</ComboBoxItem> <ComboBoxItem Name="WindowStateMaximized">Maximized</ComboBoxItem>
</ComboBox> <ComboBoxItem Name="WindowStateFullScreen">FullScreen</ComboBoxItem>
</ComboBox>
<Label Grid.Column="0" Grid.Row="8">Order (mac)</Label>
<TextBox Name="Order" Grid.Column="1" Grid.Row="8" IsReadOnly="True"/> <Label Grid.Column="0" Grid.Row="8">SystemDecorations</Label>
<ComboBox Name="CurrentSystemDecorations" Grid.Column="1" Grid.Row="8" SelectedIndex="{Binding SystemDecorations}">
<Button Name="HideButton" Grid.Row="9" Command="{Binding $parent[Window].Hide}">Hide</Button> <ComboBoxItem Name="SystemDecorationsNone">None</ComboBoxItem>
</Grid> <ComboBoxItem Name="SystemDecorationsBorderOnly">BorderOnly</ComboBoxItem>
<ComboBoxItem Name="SystemDecorationsFull">Full</ComboBoxItem>
</ComboBox>
<CheckBox Name="CurrentExtendClientAreaToDecorationsHint" Grid.ColumnSpan="2" Grid.Row="9"
IsChecked="{Binding ExtendClientAreaToDecorationsHint}">
ExtendClientAreaToDecorationsHint
</CheckBox>
<Label Grid.Column="0" Grid.Row="10">Order (mac)</Label>
<TextBox Name="CurrentOrder" Grid.Column="1" Grid.Row="10" IsReadOnly="True" />
<Label Grid.Row="11" Content="MeasuredWith:" />
<TextBlock Grid.Column="1" Grid.Row="11" Name="CurrentMeasuredWithText" Text="{Binding #MyBorder.MeasuredWith}" />
<Button Name="HideButton" Grid.Row="12" Command="{Binding $parent[Window].Hide}">Hide</Button>
</Grid>
</integrationTestApp:MeasureBorder>
</Window> </Window>

31
samples/IntegrationTestApp/ShowWindowTest.axaml.cs

@ -7,6 +7,25 @@ using Avalonia.Threading;
namespace IntegrationTestApp namespace IntegrationTestApp
{ {
public class MeasureBorder : Border
{
protected override Size MeasureOverride(Size availableSize)
{
MeasuredWith = availableSize;
return base.MeasureOverride(availableSize);
}
public static readonly StyledProperty<Size> MeasuredWithProperty = AvaloniaProperty.Register<MeasureBorder, Size>(
nameof(MeasuredWith));
public Size MeasuredWith
{
get => GetValue(MeasuredWithProperty);
set => SetValue(MeasuredWithProperty, value);
}
}
public class ShowWindowTest : Window public class ShowWindowTest : Window
{ {
private readonly DispatcherTimer? _timer; private readonly DispatcherTimer? _timer;
@ -16,11 +35,11 @@ namespace IntegrationTestApp
{ {
InitializeComponent(); InitializeComponent();
DataContext = this; DataContext = this;
PositionChanged += (s, e) => this.GetControl<TextBox>("Position").Text = $"{Position}"; PositionChanged += (s, e) => this.GetControl<TextBox>("CurrentPosition").Text = $"{Position}";
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{ {
_orderTextBox = this.GetControl<TextBox>("Order"); _orderTextBox = this.GetControl<TextBox>("CurrentOrder");
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) }; _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
_timer.Tick += TimerOnTick; _timer.Tick += TimerOnTick;
_timer.Start(); _timer.Start();
@ -36,13 +55,13 @@ namespace IntegrationTestApp
{ {
base.OnOpened(e); base.OnOpened(e);
var scaling = PlatformImpl!.DesktopScaling; var scaling = PlatformImpl!.DesktopScaling;
this.GetControl<TextBox>("Position").Text = $"{Position}"; this.GetControl<TextBox>("CurrentPosition").Text = $"{Position}";
this.GetControl<TextBox>("ScreenRect").Text = $"{Screens.ScreenFromVisual(this)?.WorkingArea}"; this.GetControl<TextBox>("CurrentScreenRect").Text = $"{Screens.ScreenFromVisual(this)?.WorkingArea}";
this.GetControl<TextBox>("Scaling").Text = $"{scaling}"; this.GetControl<TextBox>("CurrentScaling").Text = $"{scaling}";
if (Owner is not null) if (Owner is not null)
{ {
var ownerRect = this.GetControl<TextBox>("OwnerRect"); var ownerRect = this.GetControl<TextBox>("CurrentOwnerRect");
var owner = (Window)Owner; var owner = (Window)Owner;
ownerRect.Text = $"{owner.Position}, {PixelSize.FromSize(owner.FrameSize!.Value, scaling)}"; ownerRect.Text = $"{owner.Position}, {PixelSize.FromSize(owner.FrameSize!.Value, scaling)}";
} }

11
samples/IntegrationTestApp/bundle.sh

@ -1,5 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd $(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) cd $(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
dotnet restore -r osx-arm64
dotnet msbuild -t:BundleApp -p:RuntimeIdentifier=osx-arm64 -p:_AvaloniaUseExternalMSBuild=false arch="x64"
if [[ $(uname -m) == 'arm64' ]]; then
arch="arm64"
fi
dotnet restore -r osx-$arch
dotnet msbuild -t:BundleApp -p:RuntimeIdentifier=osx-$arch -p:_AvaloniaUseExternalMSBuild=false

1
samples/MobileSandbox/MobileSandbox.csproj

@ -28,6 +28,7 @@
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
<ProjectReference Include="..\SampleControls\ControlSamples.csproj" /> <ProjectReference Include="..\SampleControls\ControlSamples.csproj" />

1
samples/PlatformSanityChecks/PlatformSanityChecks.csproj

@ -7,6 +7,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" /> <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
</ItemGroup> </ItemGroup>

1
samples/Previewer/Previewer.csproj

@ -10,6 +10,7 @@
<EmbeddedResource Include="**\*.xaml" /> <EmbeddedResource Include="**\*.xaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
</ItemGroup> </ItemGroup>

1
samples/ReactiveUIDemo/ReactiveUIDemo.csproj

@ -7,6 +7,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" /> <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
</ItemGroup> </ItemGroup>

2
samples/RenderDemo/Pages/RenderTargetBitmapPage.cs

@ -29,7 +29,7 @@ namespace RenderDemo.Pages
public override void Render(DrawingContext context) public override void Render(DrawingContext context)
{ {
using (var ctx = _bitmap.CreateDrawingContext()) using (var ctx = _bitmap.CreateDrawingContext())
using (ctx.PushPostTransform(Matrix.CreateTranslation(-100, -100) using (ctx.PushTransform(Matrix.CreateTranslation(-100, -100)
* Matrix.CreateRotation(_st.Elapsed.TotalSeconds) * Matrix.CreateRotation(_st.Elapsed.TotalSeconds)
* Matrix.CreateTranslation(100, 100))) * Matrix.CreateTranslation(100, 100)))
{ {

1
samples/RenderDemo/RenderDemo.csproj

@ -12,6 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />

2
samples/SampleControls/HamburgerMenu/HamburgerMenu.cs

@ -57,7 +57,7 @@ namespace ControlSamples
{ {
if (_splitView is not null && _splitView.DisplayMode == SplitViewDisplayMode.Overlay) if (_splitView is not null && _splitView.DisplayMode == SplitViewDisplayMode.Overlay)
{ {
_splitView.SetValue(SplitView.IsPaneOpenProperty, false, Avalonia.Data.BindingPriority.Animation); _splitView.SetCurrentValue(SplitView.IsPaneOpenProperty, false);
} }
} }
} }

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

Loading…
Cancel
Save