Browse Source

Merge remote-tracking branch 'origin/master' into xunit-ext

# Conflicts:
#	src/Headless/Avalonia.Headless/HeadlessPlatformStubs.cs
#	src/Headless/Avalonia.Headless/HeadlessPlatformThreadingInterface.cs
#	src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
pull/10473/head
Max Katz 3 years ago
parent
commit
2d7c55ccdc
  1. 1
      .gitignore
  2. 5
      .ncrunch/Avalonia.Generators.Tests.v3.ncrunchproject
  3. 5
      .ncrunch/Generators.Sandbox.v3.ncrunchproject
  4. 5
      .ncrunch/SafeAreaDemo.Android.v3.ncrunchproject
  5. 5
      .ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject
  6. 5
      .ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject
  7. 5
      .ncrunch/SafeAreaDemo.v3.ncrunchproject
  8. 4
      .nuke/build.schema.json
  9. 12
      Avalonia.Desktop.slnf
  10. 55
      Avalonia.sln
  11. 2
      Directory.Build.targets
  12. 1
      azure-pipelines-integrationtests.yml
  13. 17
      build/SourceGenerators.props
  14. 12
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  15. 46
      native/Avalonia.Native/src/OSX/AvnTextInputMethod.h
  16. 41
      native/Avalonia.Native/src/OSX/AvnTextInputMethod.mm
  17. 20
      native/Avalonia.Native/src/OSX/AvnTextInputMethodDelegate.h
  18. 6
      native/Avalonia.Native/src/OSX/AvnView.h
  19. 120
      native/Avalonia.Native/src/OSX/AvnView.mm
  20. 2
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  21. 6
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  22. 10
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  23. 2
      native/Avalonia.Native/src/OSX/WindowImpl.h
  24. 12
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  25. 341
      native/Avalonia.Native/src/OSX/platformthreading.mm
  26. 14
      nukebuild/Build.cs
  27. 24
      nukebuild/Helpers.cs
  28. 171
      nukebuild/RefAssemblyGenerator.cs
  29. 13
      nukebuild/_build.csproj
  30. 5
      nukebuild/numerge.config
  31. 10
      packages/Avalonia/Avalonia.csproj
  32. 1
      packages/Avalonia/Avalonia.props
  33. 4
      readme.md
  34. 4
      samples/BindingDemo/MainWindow.xaml
  35. 2
      samples/ControlCatalog.Android/MainActivity.cs
  36. 2
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  37. 4
      samples/ControlCatalog.Android/Resources/values-night/colors.xml
  38. 14
      samples/ControlCatalog/ControlCatalog.csproj
  39. 5
      samples/ControlCatalog/MainView.xaml
  40. 4
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  41. 74
      samples/ControlCatalog/Pages/ClipboardPage.xaml.cs
  42. 35
      samples/ControlCatalog/Pages/ColorPickerPage.xaml
  43. 2
      samples/ControlCatalog/Pages/ComboBoxPage.xaml.cs
  44. 2
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  45. 4
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml
  46. 5
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs
  47. 4
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  48. 2
      samples/ControlCatalog/Pages/CursorPage.xaml
  49. 8
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  50. 2
      samples/ControlCatalog/Pages/DataGridPage.xaml
  51. 4
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  52. 4
      samples/ControlCatalog/Pages/DialogsPage.xaml
  53. 16
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  54. 8
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  55. 18
      samples/ControlCatalog/Pages/FlyoutsPage.axaml
  56. 8
      samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs
  57. 2
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
  58. 11
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  59. 2
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  60. 6
      samples/ControlCatalog/Pages/MenuPage.xaml
  61. 8
      samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs
  62. 6
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  63. 2
      samples/ControlCatalog/Pages/RefreshContainerPage.axaml
  64. 14
      samples/ControlCatalog/Pages/RefreshContainerPage.axaml.cs
  65. 13
      samples/ControlCatalog/Pages/RelativePanelPage.axaml.cs
  66. 222
      samples/ControlCatalog/Pages/ScrollSnapPage.xaml
  67. 68
      samples/ControlCatalog/Pages/ScrollSnapPage.xaml.cs
  68. 290
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml
  69. 37
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs
  70. 2
      samples/ControlCatalog/Pages/TabControlPage.xaml
  71. 2
      samples/ControlCatalog/Pages/TabStripPage.xaml
  72. 20
      samples/ControlCatalog/Pages/ThemePage.axaml.cs
  73. 2
      samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml
  74. 2
      samples/ControlCatalog/Pages/TreeViewPage.xaml
  75. 7
      samples/Generators.Sandbox/App.xaml
  76. 20
      samples/Generators.Sandbox/App.xaml.cs
  77. 10
      samples/Generators.Sandbox/Controls/CustomTextBox.cs
  78. 45
      samples/Generators.Sandbox/Controls/SignUpView.xaml
  79. 54
      samples/Generators.Sandbox/Controls/SignUpView.xaml.cs
  80. 28
      samples/Generators.Sandbox/Generators.Sandbox.csproj
  81. 15
      samples/Generators.Sandbox/Program.cs
  82. 70
      samples/Generators.Sandbox/ViewModels/SignUpViewModel.cs
  83. 9
      samples/Generators.Sandbox/Views/SignUpView.xaml
  84. 28
      samples/Generators.Sandbox/Views/SignUpView.xaml.cs
  85. 26
      samples/IntegrationTestApp/MainWindow.axaml
  86. 8
      samples/IntegrationTestApp/MainWindow.axaml.cs
  87. 24
      samples/IntegrationTestApp/ShowWindowTest.axaml
  88. 40
      samples/RenderDemo/Pages/AnimationsPage.xaml
  89. 2
      samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
  90. BIN
      samples/SafeAreaDemo.Android/Icon.png
  91. 11
      samples/SafeAreaDemo.Android/MainActivity.cs
  92. 5
      samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml
  93. 13
      samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml
  94. 4
      samples/SafeAreaDemo.Android/Resources/values/colors.xml
  95. 17
      samples/SafeAreaDemo.Android/Resources/values/styles.xml
  96. 24
      samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
  97. 30
      samples/SafeAreaDemo.Android/SplashActivity.cs
  98. 21
      samples/SafeAreaDemo.Desktop/Program.cs
  99. 24
      samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
  100. 18
      samples/SafeAreaDemo.Desktop/app.manifest

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>

5
.ncrunch/SafeAreaDemo.Android.v3.ncrunchproject

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

5
.ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject

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

5
.ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject

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

5
.ncrunch/SafeAreaDemo.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"
] ]
} }

12
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",
@ -38,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",
@ -63,4 +65,4 @@
"tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj" "tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj"
] ]
} }
} }

55
Avalonia.sln

@ -244,7 +244,21 @@ 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.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Desktop", "samples\SafeAreaDemo.Desktop\SafeAreaDemo.Desktop.csproj", "{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples\SafeAreaDemo.iOS\SafeAreaDemo.iOS.csproj", "{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
EndProject EndProject
@ -579,6 +593,14 @@ 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
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDA28789-C21A-4654-86CE-D01E81F095C5}.Release|Any CPU.ActiveCfg = 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.ActiveCfg = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
@ -591,6 +613,30 @@ Global
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.Build.0 = Release|Any CPU {3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.Build.0 = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.Build.0 = Release|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.Build.0 = Release|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Deploy.0 = Release|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.Build.0 = Release|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Build.0 = Release|Any CPU
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -662,6 +708,13 @@ Global
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7} {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7} {F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {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}

2
Directory.Build.targets

@ -1,5 +1,5 @@
<Project> <Project>
<PropertyGroup Condition="$(NETCoreSdkVersion.StartsWith('7.0'))"> <PropertyGroup Condition="$([MSBuild]::VersionGreaterThanOrEquals($(NETCoreSdkVersion), '7.0'))">
<DefineConstants>$(DefineConstants);NET7SDK</DefineConstants> <DefineConstants>$(DefineConstants);NET7SDK</DefineConstants>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

1
azure-pipelines-integrationtests.yml

@ -24,6 +24,7 @@ jobs:
fi fi
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
pkill node pkill node
pkill testmanagerd
appium > appium.out & appium > appium.out &
pkill IntegrationTestApp pkill IntegrationTestApp
./build.sh CompileNative ./build.sh CompileNative

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

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

@ -20,6 +20,10 @@
NSObject<IRenderTarget>* _renderTarget; NSObject<IRenderTarget>* _renderTarget;
AvnPlatformResizeReason _resizeReason; AvnPlatformResizeReason _resizeReason;
AvnAccessibilityElement* _accessibilityChild; AvnAccessibilityElement* _accessibilityChild;
NSRect _cursorRect;
NSMutableAttributedString* _text;
NSRange _selectedRange;
NSRange _markedRange;
} }
- (void)onClosed - (void)onClosed
@ -55,6 +59,11 @@
[self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]]; [self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]];
_modifierState = AvnInputModifiersNone; _modifierState = AvnInputModifiersNone;
_text = [[NSMutableAttributedString alloc] initWithString:@""];
_markedRange = NSMakeRange(0, 0);
_selectedRange = NSMakeRange(0, 0);
return self; return self;
} }
@ -517,9 +526,13 @@
- (void)keyDown:(NSEvent *)event - (void)keyDown:(NSEvent *)event
{ {
[self keyboardEvent:event withType:KeyDown]; _lastKeyHandled = false;
[[self inputContext] handleEvent:event]; [[self inputContext] handleEvent:event];
[super keyDown:event];
if(!_lastKeyHandled){
[self keyboardEvent:event withType:KeyDown];
}
} }
- (void)keyUp:(NSEvent *)event - (void)keyUp:(NSEvent *)event
@ -528,6 +541,10 @@
[super keyUp:event]; [super keyUp:event];
} }
- (void) doCommandBySelector:(SEL)selector{
}
- (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod - (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod
{ {
unsigned int rv = 0; unsigned int rv = 0;
@ -557,27 +574,52 @@
- (BOOL)hasMarkedText - (BOOL)hasMarkedText
{ {
return _lastKeyHandled; return _markedRange.length > 0;
} }
- (NSRange)markedRange - (NSRange)markedRange
{ {
return NSMakeRange(NSNotFound, 0); return _markedRange;
} }
- (NSRange)selectedRange - (NSRange)selectedRange
{ {
return NSMakeRange(NSNotFound, 0); return _selectedRange;
} }
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange - (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{ {
_lastKeyHandled = true;
NSString* markedText;
if([string isKindOfClass:[NSAttributedString class]])
{
markedText = [string string];
}
else
{
markedText = (NSString*) string;
}
_markedRange = NSMakeRange(_selectedRange.location, [markedText length]);
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]);
}
} }
- (void)unmarkText - (void)unmarkText
{ {
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText(nullptr);
}
_markedRange = NSMakeRange(_selectedRange.location, 0);
if([self inputContext]) {
[[self inputContext] discardMarkedText];
}
} }
- (NSArray<NSString *> *)validAttributesForMarkedText - (NSArray<NSString *> *)validAttributesForMarkedText
@ -587,30 +629,52 @@
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{ {
return [NSAttributedString new]; if(actualRange){
range = *actualRange;
}
NSAttributedString* subString = [_text attributedSubstringFromRange:range];
return subString;
} }
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{ {
if(!_lastKeyHandled) if(_parent == nullptr){
return;
}
NSString* text;
if([string isKindOfClass:[NSAttributedString class]])
{ {
if(_parent != nullptr) text = [string string];
{ }
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]); else
} {
text = (NSString*) string;
} }
[self unmarkText];
uint32_t timestamp = static_cast<uint32_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]);
} }
- (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
@ -715,4 +779,26 @@
return [[self accessibilityChild] accessibilityFocusedUIElement]; return [[self accessibilityChild] accessibilityFocusedUIElement];
} }
- (void) setText:(NSString *)text{
[[_text mutableString] setString:text];
}
- (void) setSelection:(int)start :(int)end{
_selectedRange = NSMakeRange(start, end - start);
}
- (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;
if([self inputContext]) {
[[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

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;
}; };

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

@ -15,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() {
@ -29,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 };
@ -605,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;

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

@ -281,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;
@ -611,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];
@ -622,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()
{ {

14
nukebuild/Build.cs

@ -221,16 +221,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 => _ => _
@ -272,12 +274,14 @@ partial class Build : NukeBuild
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config, if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
new NumergeNukeLogger())) new NumergeNukeLogger()))
throw new Exception("Package merge failed"); throw new Exception("Package merge failed");
RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
Parameters.Version + ".nupkg");
}); });
Target RunTests => _ => _ Target RunTests => _ => _
.DependsOn(RunCoreLibsTests) .DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests) .DependsOn(RunRenderTests)
.DependsOn(RunDesignerTests) .DependsOn(RunToolsTests)
.DependsOn(RunHtmlPreviewerTests) .DependsOn(RunHtmlPreviewerTests)
.DependsOn(RunLeakTests); .DependsOn(RunLeakTests);

24
nukebuild/Helpers.cs

@ -0,0 +1,24 @@
using System;
using System.IO;
using Nuke.Common.Utilities;
class Helpers
{
public static IDisposable UseTempDir(out string dir)
{
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(path);
dir = path;
return DelegateDisposable.CreateBracket(null, () =>
{
try
{
Directory.Delete(path, true);
}
catch
{
// ignore
}
});
}
}

171
nukebuild/RefAssemblyGenerator.cs

@ -0,0 +1,171 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using ILRepacking;
using Mono.Cecil;
using Mono.Cecil.Cil;
public class RefAssemblyGenerator
{
class Resolver : DefaultAssemblyResolver, IAssemblyResolver
{
private readonly string _dir;
Dictionary<string, AssemblyDefinition> _cache = new();
public Resolver(string dir)
{
_dir = dir;
}
public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (_cache.TryGetValue(name.Name, out var asm))
return asm;
var path = Path.Combine(_dir, name.Name + ".dll");
if (File.Exists(path))
return _cache[name.Name] = AssemblyDefinition.ReadAssembly(path, parameters);
return base.Resolve(name, parameters);
}
}
public static void PatchRefAssembly(string file)
{
var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk");
var snk = new byte[reader.Length];
reader.Read(snk, 0, snk.Length);
var def = AssemblyDefinition.ReadAssembly(file, new ReaderParameters
{
ReadWrite = true,
InMemory = true,
ReadSymbols = true,
SymbolReaderProvider = new DefaultSymbolReaderProvider(false),
AssemblyResolver = new Resolver(Path.GetDirectoryName(file))
});
var obsoleteAttribute = def.MainModule.ImportReference(new TypeReference("System", "ObsoleteAttribute", def.MainModule,
def.MainModule.TypeSystem.CoreLibrary));
var obsoleteCtor = def.MainModule.ImportReference(new MethodReference(".ctor",
def.MainModule.TypeSystem.Void, obsoleteAttribute)
{
Parameters = { new ParameterDefinition(def.MainModule.TypeSystem.String) }
});
foreach(var t in def.MainModule.Types)
ProcessType(t, obsoleteCtor);
def.Write(file, new WriterParameters()
{
StrongNameKeyBlob = snk,
WriteSymbols = def.MainModule.HasSymbols,
SymbolWriterProvider = new EmbeddedPortablePdbWriterProvider(),
DeterministicMvid = def.MainModule.HasSymbols
});
}
static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor)
{
foreach (var nested in type.NestedTypes)
ProcessType(nested, obsoleteCtor);
if (type.IsInterface)
{
var hideMethods = type.Name.EndsWith("Impl")
|| (type.HasCustomAttributes && type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.PrivateApiAttribute"));
var injectMethod = hideMethods
|| type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute");
if (hideMethods)
{
foreach (var m in type.Methods)
{
var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
}
}
if(injectMethod)
{
type.Methods.Add(new MethodDefinition("NotClientImplementable",
MethodAttributes.Assembly
| MethodAttributes.Abstract
| MethodAttributes.NewSlot
| MethodAttributes.HideBySig, type.Module.TypeSystem.Void));
}
var forceUnstable = type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute");
foreach (var m in type.Methods)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
foreach (var m in type.Properties)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
foreach (var m in type.Events)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
}
}
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, bool force)
{
if (!force && (
def.HasCustomAttributes == false
|| def.CustomAttributes.All(a => a.AttributeType.FullName != "Avalonia.Metadata.UnstableAttribute")))
return;
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
return;
def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
{
ConstructorArguments =
{
new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String,
"This is a part of unstable API and can be changed in minor releases. You have been warned")
}
});
}
public static void GenerateRefAsmsInPackage(string packagePath)
{
using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
ZipArchiveMode.Update))
{
foreach (var entry in archive.Entries.ToList())
{
if (entry.FullName.StartsWith("ref/"))
entry.Delete();
}
foreach (var entry in archive.Entries.ToList())
{
if (entry.FullName.StartsWith("lib/") && entry.Name.EndsWith(".xml"))
{
var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
CompressionLevel.Optimal);
using (var src = entry.Open())
using (var dst = newEntry.Open())
src.CopyTo(dst);
}
}
var libs = archive.Entries.Where(e => e.FullName.StartsWith("lib/") && e.FullName.EndsWith(".dll"))
.Select((e => new { s = e.FullName.Split('/'), e = e }))
.Select(e => new { Tfm = e.s[1], Name = e.s[2], Entry = e.e })
.GroupBy(x => x.Tfm);
foreach(var tfm in libs)
using (Helpers.UseTempDir(out var temp))
{
foreach (var l in tfm)
l.Entry.ExtractToFile(Path.Combine(temp, l.Name));
foreach (var l in tfm)
PatchRefAssembly(Path.Combine(temp, l.Name));
foreach (var l in tfm)
archive.CreateEntryFromFile(Path.Combine(temp, l.Name), $"ref/{l.Tfm}/{l.Name}");
}
}
}
}

13
nukebuild/_build.csproj

@ -31,18 +31,11 @@
<!-- Common build related files --> <!-- Common build related files -->
<Compile Remove="Numerge/**/*.*" /> <Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" /> <Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup> <EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Remove="il-repack\ILRepack\Application.cs" /> <Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Numerge\Numerge.Console\" />
</ItemGroup>
</Project> </Project>

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>

1
packages/Avalonia/Avalonia.props

@ -6,6 +6,7 @@
<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 --> <!-- Allow loading the AvaloniaVS extension when referencing the Avalonia nuget package -->
<ItemGroup> <ItemGroup>

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.

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>

14
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">
@ -35,14 +36,5 @@
</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>

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

@ -114,7 +114,7 @@ namespace ControlCatalog.Pages
foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox")) foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox"))
{ {
box.Items = States; box.ItemsSource = States;
} }
var converter = new FuncMultiValueConverter<string, string>(parts => var converter = new FuncMultiValueConverter<string, string>(parts =>
@ -132,7 +132,7 @@ namespace ControlCatalog.Pages
asyncBox.AsyncPopulator = PopulateAsync; asyncBox.AsyncPopulator = PopulateAsync;
var customAutocompleteBox = this.Get<AutoCompleteBox>("CustomAutocompleteBox"); var customAutocompleteBox = this.Get<AutoCompleteBox>("CustomAutocompleteBox");
customAutocompleteBox.Items = Sentences.SelectMany(x => x); customAutocompleteBox.ItemsSource = Sentences.SelectMany(x => x);
customAutocompleteBox.TextFilter = LastWordContains; customAutocompleteBox.TextFilter = LastWordContains;
customAutocompleteBox.TextSelector = AppendWord; customAutocompleteBox.TextSelector = AppendWord;
} }

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.SystemFonts; 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();
} }

4
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml

@ -61,13 +61,13 @@
<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>
</Border.Styles> </Border.Styles>
<Border.ContextFlyout> <Border.ContextFlyout>
<MenuFlyout Items="{Binding MenuItems}" /> <MenuFlyout ItemsSource="{Binding MenuItems}" />
</Border.ContextFlyout> </Border.ContextFlyout>
<TextBlock Text="Dynamically Generated"/> <TextBlock Text="Dynamically Generated"/>
</Border> </Border>

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"/>

8
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

@ -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

2
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -94,7 +94,7 @@
<Grid RowDefinitions="*,Auto"> <Grid RowDefinitions="*,Auto">
<!-- Example of columns inheriting the data type from the Items source --> <!-- Example of columns inheriting the data type from the Items source -->
<DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0" <DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0"
Items="{Binding DataGrid3Source}"> ItemsSource="{Binding DataGrid3Source}">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" /> <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" /> <DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />

4
samples/ControlCatalog/Pages/DataGridPage.xaml.cs

@ -36,7 +36,7 @@ namespace ControlCatalog.Pages
collectionView1.SortDescriptions.Add(dataGridSortDescription); collectionView1.SortDescriptions.Add(dataGridSortDescription);
} }
}; };
dg1.Items = collectionView1; dg1.ItemsSource = collectionView1;
var dg2 = this.Get<DataGrid>("dataGridGrouping"); var dg2 = this.Get<DataGrid>("dataGridGrouping");
dg2.IsReadOnly = true; dg2.IsReadOnly = true;
@ -44,7 +44,7 @@ namespace ControlCatalog.Pages
var collectionView2 = new DataGridCollectionView(Countries.All); var collectionView2 = new DataGridCollectionView(Countries.All);
collectionView2.GroupDescriptions.Add(new DataGridPathGroupDescription("Region")); collectionView2.GroupDescriptions.Add(new DataGridPathGroupDescription("Region"));
dg2.Items = collectionView2; dg2.ItemsSource = collectionView2;
var dg3 = this.Get<DataGrid>("dataGridEdit"); var dg3 = this.Get<DataGrid>("dataGridEdit");
dg3.IsReadOnly = false; dg3.IsReadOnly = false;

4
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -45,7 +45,7 @@
</Expander> </Expander>
<AutoCompleteBox x:Name="CurrentFolderBox" Watermark="Write full path/uri or well known folder name"> <AutoCompleteBox x:Name="CurrentFolderBox" Watermark="Write full path/uri or well known folder name">
<AutoCompleteBox.Items> <AutoCompleteBox.ItemsSource>
<generic:List x:TypeArguments="storage:WellKnownFolder"> <generic:List x:TypeArguments="storage:WellKnownFolder">
<storage:WellKnownFolder>Desktop</storage:WellKnownFolder> <storage:WellKnownFolder>Desktop</storage:WellKnownFolder>
<storage:WellKnownFolder>Documents</storage:WellKnownFolder> <storage:WellKnownFolder>Documents</storage:WellKnownFolder>
@ -54,7 +54,7 @@
<storage:WellKnownFolder>Videos</storage:WellKnownFolder> <storage:WellKnownFolder>Videos</storage:WellKnownFolder>
<storage:WellKnownFolder>Music</storage:WellKnownFolder> <storage:WellKnownFolder>Music</storage:WellKnownFolder>
</generic:List> </generic:List>
</AutoCompleteBox.Items> </AutoCompleteBox.ItemsSource>
</AutoCompleteBox> </AutoCompleteBox>
<TextBlock x:Name="PickerLastResultsVisible" <TextBlock x:Name="PickerLastResultsVisible"

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");

2
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml

@ -66,7 +66,7 @@
<ScrollViewer Name="scroller" <ScrollViewer Name="scroller"
HorizontalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"> VerticalScrollBarVisibility="Auto">
<ItemsRepeater Name="repeater" Background="Transparent" Items="{Binding Items}" <ItemsRepeater Name="repeater" Background="Transparent" ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource elementFactory}"/> ItemTemplate="{StaticResource elementFactory}"/>
</ScrollViewer> </ScrollViewer>
</Border> </Border>

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>

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}"/>

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);
});
}
}

26
samples/IntegrationTestApp/MainWindow.axaml

@ -109,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>
@ -151,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>
@ -164,8 +170,22 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
</TabItem> </TabItem>
<TabItem Header="SliderTab">
<Slider VerticalAlignment="Top" Name="Slider" Value="30"/> <TabItem Header="Slider">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<TextBox Name="HorizontalSliderValue"
DockPanel.Dock="Right"
Text="{Binding #HorizontalSlider.Value, Mode=OneWay, StringFormat=\{0:0\}}"
VerticalAlignment="Top"/>
<Slider Name="HorizontalSlider" Value="50"/>
</DockPanel>
<Button Name="ResetSliders">Reset</Button>
</DockPanel>
</TabItem>
<TabItem Header="ScrollBar">
<ScrollBar Name="MyScrollBar" Orientation="Horizontal" AllowAutoHide="False" Width="200" Height="30" Value="20"/>
</TabItem> </TabItem>
</TabControl> </TabControl>
</DockPanel> </DockPanel>

8
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -68,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()!;
@ -95,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)
@ -158,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,
@ -266,6 +270,8 @@ namespace IntegrationTestApp
this.Get<ListBox>("BasicListBox").SelectedIndex = -1; this.Get<ListBox>("BasicListBox").SelectedIndex = -1;
if (source?.Name == "MenuClickedMenuItemReset") if (source?.Name == "MenuClickedMenuItemReset")
this.Get<TextBlock>("ClickedMenuItem").Text = "None"; this.Get<TextBlock>("ClickedMenuItem").Text = "None";
if (source?.Name == "ResetSliders")
this.Get<Slider>("HorizontalSlider").Value = 50;
if (source?.Name == "ShowTransparentWindow") if (source?.Name == "ShowTransparentWindow")
ShowTransparentWindow(); ShowTransparentWindow();
if (source?.Name == "ShowTransparentPopup") if (source?.Name == "ShowTransparentPopup")

24
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -6,7 +6,7 @@
x:DataType="Window" x:DataType="Window"
Title="Show Window Test"> Title="Show Window Test">
<integrationTestApp:MeasureBorder Name="MyBorder"> <integrationTestApp:MeasureBorder Name="MyBorder">
<Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> <Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Label Grid.Column="0" Grid.Row="1">Client Size</Label> <Label Grid.Column="0" Grid.Row="1">Client Size</Label>
<TextBox Name="CurrentClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True" <TextBox Name="CurrentClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True"
Text="{Binding ClientSize, Mode=OneWay}" /> Text="{Binding ClientSize, Mode=OneWay}" />
@ -35,13 +35,25 @@
<ComboBoxItem Name="WindowStateFullScreen">FullScreen</ComboBoxItem> <ComboBoxItem Name="WindowStateFullScreen">FullScreen</ComboBoxItem>
</ComboBox> </ComboBox>
<Label Grid.Column="0" Grid.Row="8">Order (mac)</Label> <Label Grid.Column="0" Grid.Row="8">SystemDecorations</Label>
<TextBox Name="CurrentOrder" Grid.Column="1" Grid.Row="8" IsReadOnly="True" /> <ComboBox Name="CurrentSystemDecorations" Grid.Column="1" Grid.Row="8" SelectedIndex="{Binding SystemDecorations}">
<ComboBoxItem Name="SystemDecorationsNone">None</ComboBoxItem>
<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="9" Content="MeasuredWith:" /> <Label Grid.Row="11" Content="MeasuredWith:" />
<TextBlock Grid.Column="1" Grid.Row="9" Name="CurrentMeasuredWithText" Text="{Binding #MyBorder.MeasuredWith}" /> <TextBlock Grid.Column="1" Grid.Row="11" Name="CurrentMeasuredWithText" Text="{Binding #MyBorder.MeasuredWith}" />
<Button Name="HideButton" Grid.Row="10" Command="{Binding $parent[Window].Hide}">Hide</Button> <Button Name="HideButton" Grid.Row="12" Command="{Binding $parent[Window].Hide}">Hide</Button>
</Grid> </Grid>
</integrationTestApp:MeasureBorder> </integrationTestApp:MeasureBorder>

40
samples/RenderDemo/Pages/AnimationsPage.xaml

@ -308,6 +308,41 @@
</Animation> </Animation>
</Style.Animations> </Style.Animations>
</Style> </Style>
<Style Selector="Border.Blur">
<Style.Animations>
<Animation Duration="0:0:3"
IterationCount="Infinite"
PlaybackDirection="Alternate">
<KeyFrame Cue="0%">
<Setter Property="Effect" Value="blur(0)"/>
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Effect" Value="blur(10)"/>
</KeyFrame>
</Animation>
</Style.Animations>
<Setter Property="Child" Value="{StaticResource Acorn}"/>
</Style>
<Style Selector="Border.DropShadow">
<Style.Animations>
<Animation Duration="0:0:3"
IterationCount="Infinite"
PlaybackDirection="Alternate">
<KeyFrame Cue="0%">
<Setter Property="Effect" Value="drop-shadow(0 0 0)"/>
</KeyFrame>
<KeyFrame Cue="35%">
<Setter Property="Effect" Value="drop-shadow(5 5 0 Green)"/>
</KeyFrame>
<KeyFrame Cue="70%">
<Setter Property="Effect" Value="drop-shadow(5 5 5 Red)"/>
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Effect" Value="drop-shadow(20 -5 5 Blue)"/>
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</Styles> </Styles>
</UserControl.Styles> </UserControl.Styles>
<Grid> <Grid>
@ -332,6 +367,11 @@
<Border Classes="Test Rect8" Child="{x:Null}" /> <Border Classes="Test Rect8" Child="{x:Null}" />
<Border Classes="Test Rect9" Child="{x:Null}" /> <Border Classes="Test Rect9" Child="{x:Null}" />
<Border Classes="Test Rect10" Child="{x:Null}" /> <Border Classes="Test Rect10" Child="{x:Null}" />
<Border Classes="Test Blur" Background="#ffa0a0a0" BorderThickness="4" BorderBrush="Yellow" Padding="10"/>
<Border Classes="Test DropShadow" Background="Transparent" BorderThickness="4" BorderBrush="Yellow">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Drop
Shadow</TextBlock>
</Border>
</WrapPanel> </WrapPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>

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)))
{ {

BIN
samples/SafeAreaDemo.Android/Icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

11
samples/SafeAreaDemo.Android/MainActivity.cs

@ -0,0 +1,11 @@
using Android.App;
using Android.Content.PM;
using Avalonia.Android;
namespace SafeAreaDemo.Android
{
[Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
public class MainActivity : AvaloniaMainActivity
{
}
}

5
samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="SafeAreaDemo" android:icon="@drawable/Icon" />
</manifest>

13
samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/splash_background"/>
</item>
<item android:drawable="@drawable/icon"
android:width="120dp"
android:height="120dp"
android:gravity="center" />
</layer-list>

4
samples/SafeAreaDemo.Android/Resources/values/colors.xml

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

17
samples/SafeAreaDemo.Android/Resources/values/styles.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MyTheme">
</style>
<style name="MyTheme.NoActionBar" parent="@style/Theme.AppCompat.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="MyTheme.Splash" parent ="MyTheme.NoActionBar">
<item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:windowContentOverlay">@null</item>
</style>
</resources>

24
samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ApplicationId>com.avalonia.safeareademo</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
</PropertyGroup>
<ItemGroup>
<AndroidResource Include="Icon.png">
<Link>Resources\drawable\Icon.png</Link>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" />
</ItemGroup>
</Project>

30
samples/SafeAreaDemo.Android/SplashActivity.cs

@ -0,0 +1,30 @@
using Android.App;
using Android.Content;
using Android.OS;
using Avalonia;
using Avalonia.Android;
using Application = Android.App.Application;
namespace SafeAreaDemo.Android
{
[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : AvaloniaSplashActivity<App>
{
protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
{
return base.CustomizeAppBuilder(builder);
}
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
protected override void OnResume()
{
base.OnResume();
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}
}
}

21
samples/SafeAreaDemo.Desktop/Program.cs

@ -0,0 +1,21 @@
using Avalonia;
using System;
namespace SafeAreaDemo.Desktop
{
internal class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
}
}

24
samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<!--If you are willing to use Windows/MacOS native APIs you will need to create 3 projects.
One for Windows with net7.0-windows TFM, one for MacOS with net7.0-macos and one with net7.0 TFM for Linux.-->
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
</Project>

18
samples/SafeAreaDemo.Desktop/app.manifest

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="SafeAreaDemo.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

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

Loading…
Cancel
Save