Browse Source

Merge branch 'master' into fix-combobox-issues

pull/10863/head
Steven Kirk 3 years ago
committed by GitHub
parent
commit
63c5ed0020
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      .editorconfig
  2. 5
      .ncrunch/SafeAreaDemo.Android.v3.ncrunchproject
  3. 5
      .ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject
  4. 5
      .ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject
  5. 5
      .ncrunch/SafeAreaDemo.v3.ncrunchproject
  6. 4
      .nuke/build.schema.json
  7. 7
      Avalonia.Desktop.slnf
  8. 103
      Avalonia.sln
  9. 2
      Directory.Build.targets
  10. 2
      build/DevAnalyzers.props
  11. 32
      build/ExternalConsumers.props
  12. 5
      dirs.proj
  13. 108
      native/Avalonia.Native/src/OSX/AvnView.mm
  14. 2
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  15. 14
      nukebuild/Build.cs
  16. 24
      nukebuild/Helpers.cs
  17. 177
      nukebuild/RefAssemblyGenerator.cs
  18. 15
      nukebuild/_build.csproj
  19. 5
      nukebuild/numerge.config
  20. 21
      packages/Avalonia/Avalonia.csproj
  21. 2
      packages/Avalonia/Avalonia.props
  22. 63
      readme.md
  23. 8
      samples/AppWithoutLifetime/App.axaml
  24. 12
      samples/AppWithoutLifetime/App.axaml.cs
  25. 21
      samples/AppWithoutLifetime/AppWithoutLifetime.csproj
  26. 13
      samples/AppWithoutLifetime/MainWindow.axaml
  27. 30
      samples/AppWithoutLifetime/MainWindow.axaml.cs
  28. 28
      samples/AppWithoutLifetime/Program.cs
  29. 9
      samples/AppWithoutLifetime/Sub.axaml
  30. 24
      samples/AppWithoutLifetime/Sub.axaml.cs
  31. 18
      samples/AppWithoutLifetime/app.manifest
  32. 2
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  33. 6
      samples/ControlCatalog.NetCore/Properties/launchSettings.json
  34. 2
      samples/ControlCatalog/App.xaml
  35. 48
      samples/ControlCatalog/MainView.xaml.cs
  36. 4
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  37. 15
      samples/ControlCatalog/Pages/ComboBoxPage.xaml
  38. 2
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml
  39. 11
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  40. 2
      samples/ControlCatalog/Pages/DataGridPage.xaml
  41. 4
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  42. 4
      samples/ControlCatalog/Pages/DialogsPage.xaml
  43. 2
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
  44. 2
      samples/ControlCatalog/Pages/TextBlockPage.xaml
  45. 15
      samples/ControlCatalog/ViewModels/ComboBoxPageViewModel.cs
  46. 1
      samples/IntegrationTestApp/IntegrationTestApp.csproj
  47. 17
      samples/IntegrationTestApp/MainWindow.axaml
  48. 6
      samples/IntegrationTestApp/MainWindow.axaml.cs
  49. 2
      samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj
  50. 40
      samples/RenderDemo/Pages/AnimationsPage.xaml
  51. 4
      samples/RenderDemo/Pages/CustomSkiaPage.cs
  52. 2
      samples/RenderDemo/Pages/WriteableBitmapPage.cs
  53. BIN
      samples/SafeAreaDemo.Android/Icon.png
  54. 11
      samples/SafeAreaDemo.Android/MainActivity.cs
  55. 5
      samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml
  56. 13
      samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml
  57. 4
      samples/SafeAreaDemo.Android/Resources/values/colors.xml
  58. 17
      samples/SafeAreaDemo.Android/Resources/values/styles.xml
  59. 24
      samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
  60. 30
      samples/SafeAreaDemo.Android/SplashActivity.cs
  61. 21
      samples/SafeAreaDemo.Desktop/Program.cs
  62. 24
      samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
  63. 18
      samples/SafeAreaDemo.Desktop/app.manifest
  64. 17
      samples/SafeAreaDemo.iOS/AppDelegate.cs
  65. 5
      samples/SafeAreaDemo.iOS/Entitlements.plist
  66. 47
      samples/SafeAreaDemo.iOS/Info.plist
  67. 15
      samples/SafeAreaDemo.iOS/Main.cs
  68. 43
      samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib
  69. 18
      samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj
  70. 15
      samples/SafeAreaDemo/App.xaml
  71. 36
      samples/SafeAreaDemo/App.xaml.cs
  72. BIN
      samples/SafeAreaDemo/Assets/avalonia-logo.ico
  73. 27
      samples/SafeAreaDemo/SafeAreaDemo.csproj
  74. 31
      samples/SafeAreaDemo/ViewLocator.cs
  75. 112
      samples/SafeAreaDemo/ViewModels/MainViewModel.cs
  76. 52
      samples/SafeAreaDemo/Views/MainView.xaml
  77. 25
      samples/SafeAreaDemo/Views/MainView.xaml.cs
  78. 12
      samples/SafeAreaDemo/Views/MainWindow.xaml
  79. 13
      samples/SafeAreaDemo/Views/MainWindow.xaml.cs
  80. 11
      samples/Sandbox/MainWindow.axaml.cs
  81. 2
      samples/Sandbox/Sandbox.csproj
  82. 14
      samples/VirtualizationDemo/App.axaml
  83. 20
      samples/VirtualizationDemo/App.axaml.cs
  84. 21
      samples/VirtualizationDemo/App.xaml.cs
  85. 190
      samples/VirtualizationDemo/Assets/chat.json
  86. 20
      samples/VirtualizationDemo/MainWindow.axaml
  87. 15
      samples/VirtualizationDemo/MainWindow.axaml.cs
  88. 64
      samples/VirtualizationDemo/MainWindow.xaml
  89. 22
      samples/VirtualizationDemo/MainWindow.xaml.cs
  90. 23
      samples/VirtualizationDemo/Models/Chat.cs
  91. 19
      samples/VirtualizationDemo/Program.cs
  92. 17
      samples/VirtualizationDemo/ViewModels/ChatPageViewModel.cs
  93. 21
      samples/VirtualizationDemo/ViewModels/ExpanderItemViewModel.cs
  94. 17
      samples/VirtualizationDemo/ViewModels/ExpanderPageViewModel.cs
  95. 26
      samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
  96. 164
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  97. 17
      samples/VirtualizationDemo/ViewModels/PlaygroundItemViewModel.cs
  98. 95
      samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs
  99. 39
      samples/VirtualizationDemo/Views/ChatPageView.axaml
  100. 11
      samples/VirtualizationDemo/Views/ChatPageView.axaml.cs

21
.editorconfig

@ -177,7 +177,9 @@ dotnet_diagnostic.CA1828.severity = warning
dotnet_diagnostic.CA1829.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning
#CACA2211:Non-constant fields should not be visible
#CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
dotnet_diagnostic.CA1854.severity = warning
#CA2211:Non-constant fields should not be visible
dotnet_diagnostic.CA2211.severity = error
# Wrapping preferences
@ -186,6 +188,23 @@ csharp_wrap_before_ternary_opsigns = false
# Avalonia DevAnalyzer preferences
dotnet_diagnostic.AVADEV2001.severity = error
# Avalonia PublicAnalyzer preferences
dotnet_diagnostic.AVP1000.severity = error
dotnet_diagnostic.AVP1001.severity = error
dotnet_diagnostic.AVP1002.severity = error
dotnet_diagnostic.AVP1010.severity = error
dotnet_diagnostic.AVP1011.severity = error
dotnet_diagnostic.AVP1012.severity = warning
dotnet_diagnostic.AVP1013.severity = error
dotnet_diagnostic.AVP1020.severity = error
dotnet_diagnostic.AVP1021.severity = error
dotnet_diagnostic.AVP1022.severity = error
dotnet_diagnostic.AVP1030.severity = error
dotnet_diagnostic.AVP1031.severity = error
dotnet_diagnostic.AVP1032.severity = error
dotnet_diagnostic.AVP1040.severity = error
dotnet_diagnostic.AVA2001.severity = error
# Xaml files
[*.{xaml,axaml}]
indent_size = 2

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

@ -101,10 +101,6 @@
"type": "boolean",
"description": "skip-tests"
},
"Solution": {
"type": "string",
"description": "Path to a solution file that is automatically loaded. Default is Avalonia.sln"
},
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",

7
Avalonia.Desktop.slnf

@ -3,6 +3,7 @@
"path": "Avalonia.sln",
"projects": [
"packages\\Avalonia\\Avalonia.csproj",
"samples\\AppWithoutLifetime\\AppWithoutLifetime.csproj",
"samples\\ControlCatalog.NetCore\\ControlCatalog.NetCore.csproj",
"samples\\ControlCatalog\\ControlCatalog.csproj",
"samples\\GpuInterop\\GpuInterop.csproj",
@ -23,8 +24,6 @@
"src\\Avalonia.Dialogs\\Avalonia.Dialogs.csproj",
"src\\Avalonia.Fonts.Inter\\Avalonia.Fonts.Inter.csproj",
"src\\Avalonia.FreeDesktop\\Avalonia.FreeDesktop.csproj",
"src\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
"src\\Avalonia.Headless\\Avalonia.Headless.csproj",
"src\\Avalonia.MicroCom\\Avalonia.MicroCom.csproj",
"src\\Avalonia.Native\\Avalonia.Native.csproj",
"src\\Avalonia.OpenGL\\Avalonia.OpenGL.csproj",
@ -33,6 +32,8 @@
"src\\Avalonia.Themes.Fluent\\Avalonia.Themes.Fluent.csproj",
"src\\Avalonia.Themes.Simple\\Avalonia.Themes.Simple.csproj",
"src\\Avalonia.X11\\Avalonia.X11.csproj",
"src\\Headless\\Avalonia.Headless.Vnc\\Avalonia.Headless.Vnc.csproj",
"src\\Headless\\Avalonia.Headless\\Avalonia.Headless.csproj",
"src\\Linux\\Avalonia.LinuxFramebuffer\\Avalonia.LinuxFramebuffer.csproj",
"src\\Markup\\Avalonia.Markup.Xaml.Loader\\Avalonia.Markup.Xaml.Loader.csproj",
"src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
@ -65,4 +66,4 @@
"tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj"
]
}
}
}

103
Avalonia.sln

@ -181,9 +181,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Fluent", "src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj", "{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Headless\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.Vnc", "src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj", "{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.Vnc", "src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj", "{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.Loader", "src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj", "{909A8CBD-7D0E-42FD-B841-022AD8925820}"
EndProject
@ -233,7 +233,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\R
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
ProjectSection(SolutionItems) = preProject
@ -244,13 +244,32 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepe
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}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
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}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppWithoutLifetime", "samples\AppWithoutLifetime\AppWithoutLifetime.csproj", "{F8928267-688E-4A51-989C-612A72446D33}"
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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit", "src\Headless\Avalonia.Headless.NUnit\Avalonia.Headless.NUnit.csproj", "{ED976634-B118-43F8-8B26-0279C7A7044F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit.UnitTests", "tests\Avalonia.Headless.NUnit.UnitTests\Avalonia.Headless.NUnit.UnitTests.csproj", "{2999D79E-3C20-4A90-B651-CA7E0AC92D35}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit.UnitTests", "tests\Avalonia.Headless.XUnit.UnitTests\Avalonia.Headless.XUnit.UnitTests.csproj", "{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -583,18 +602,62 @@ Global
{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.Build.0 = Debug|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.Build.0 = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
{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
{F8928267-688E-4A51-989C-612A72446D33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8928267-688E-4A51-989C-612A72446D33}.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
{ED976634-B118-43F8-8B26-0279C7A7044F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED976634-B118-43F8-8B26-0279C7A7044F}.Release|Any CPU.Build.0 = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Release|Any CPU.Build.0 = Release|Any CPU
{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Release|Any CPU.Build.0 = Release|Any CPU
{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -639,6 +702,8 @@ Global
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
@ -661,10 +726,22 @@ Global
{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F8928267-688E-4A51-989C-612A72446D33} = {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}
{ED976634-B118-43F8-8B26-0279C7A7044F} = {FF237916-7150-496B-89ED-6CA3292896E7}
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{2999D79E-3C20-4A90-B651-CA7E0AC92D35} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

2
Directory.Build.targets

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

2
build/DevAnalyzers.props

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

32
build/ExternalConsumers.props

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

5
dirs.proj

@ -9,10 +9,11 @@
<ProjectReference Remove="**/*.shproj" />
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/**/*.*proj" />
<!-- Exclude iOS, Android and Web samples from build -->
<!-- Exclude iOS, Android and Browser samples from build -->
<ProjectReference Remove="samples/*.iOS/*.csproj" />
<ProjectReference Remove="samples/*.Android/*.csproj" />
<ProjectReference Remove="samples/*.Web/*.csproj" />
<ProjectReference Remove="samples/*.Browser/*.csproj" />
<ProjectReference Remove="samples/*.Blazor/*.csproj" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />

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

@ -12,7 +12,6 @@
{
ComPtr<WindowBaseImpl> _parent;
NSTrackingArea* _area;
NSMutableAttributedString* _markedText;
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed;
AvnInputModifiers _modifierState;
NSEvent* _lastMouseDownEvent;
@ -22,8 +21,9 @@
AvnPlatformResizeReason _resizeReason;
AvnAccessibilityElement* _accessibilityChild;
NSRect _cursorRect;
NSMutableString* _text;
NSRange _selection;
NSMutableAttributedString* _text;
NSRange _selectedRange;
NSRange _markedRange;
}
- (void)onClosed
@ -59,6 +59,11 @@
[self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]];
_modifierState = AvnInputModifiersNone;
_text = [[NSMutableAttributedString alloc] initWithString:@""];
_markedRange = NSMakeRange(0, 0);
_selectedRange = NSMakeRange(0, 0);
return self;
}
@ -270,7 +275,7 @@
delta.Y = [event deltaY];
}
uint32 timestamp = static_cast<uint32>([event timestamp] * 1000);
uint64_t timestamp = static_cast<uint64_t>([event timestamp] * 1000);
auto modifiers = [self getModifiers:[event modifierFlags]];
if(type != Move ||
@ -439,7 +444,7 @@
auto key = s_KeyMap[[event keyCode]];
uint32_t timestamp = static_cast<uint32_t>([event timestamp] * 1000);
uint64_t timestamp = static_cast<uint64_t>([event timestamp] * 1000);
auto modifiers = [self getModifiers:[event modifierFlags]];
if(_parent != nullptr)
@ -521,9 +526,13 @@
- (void)keyDown:(NSEvent *)event
{
[self keyboardEvent:event withType:KeyDown];
_lastKeyHandled = [[self inputContext] handleEvent:event];
[super keyDown:event];
_lastKeyHandled = false;
[[self inputContext] handleEvent:event];
if(!_lastKeyHandled){
[self keyboardEvent:event withType:KeyDown];
}
}
- (void)keyUp:(NSEvent *)event
@ -532,6 +541,10 @@
[super keyUp:event];
}
- (void) doCommandBySelector:(SEL)selector{
}
- (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod
{
unsigned int rv = 0;
@ -561,50 +574,52 @@
- (BOOL)hasMarkedText
{
return [_markedText length] > 0;
return _markedRange.length > 0;
}
- (NSRange)markedRange
{
if([_markedText length] > 0)
return NSMakeRange(0, [_markedText length] - 1);
return NSMakeRange(NSNotFound, 0);
return _markedRange;
}
- (NSRange)selectedRange
{
return _selection;
return _selectedRange;
}
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{
_lastKeyHandled = true;
NSString* markedText;
if([string isKindOfClass:[NSAttributedString class]])
{
_markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
markedText = [string string];
}
else
{
_markedText = [[NSMutableAttributedString alloc] initWithString:string];
markedText = (NSString*) string;
}
if(!_parent->InputMethod->IsActive()){
return;
_markedRange = NSMakeRange(_selectedRange.location, [markedText length]);
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]);
}
_parent->InputMethod->Client->SetPreeditText((char*)[_markedText.string UTF8String]);
}
- (void)unmarkText
{
[[_markedText mutableString] setString:@""];
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText(nullptr);
}
[[self inputContext] discardMarkedText];
_markedRange = NSMakeRange(_selectedRange.location, 0);
if(!_parent->InputMethod->IsActive()){
return;
if([self inputContext]) {
[[self inputContext] discardMarkedText];
}
_parent->InputMethod->Client->SetPreeditText(nullptr);
}
- (NSArray<NSString *> *)validAttributesForMarkedText
@ -614,19 +629,38 @@
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{
return nullptr;
if(actualRange){
range = *actualRange;
}
NSAttributedString* subString = [_text attributedSubstringFromRange:range];
return subString;
}
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{
[self unmarkText];
if(_parent != nullptr)
if(_parent == nullptr){
return;
}
NSString* text;
if([string isKindOfClass:[NSAttributedString class]])
{
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]);
text = [string string];
}
else
{
text = (NSString*) string;
}
[[self inputContext] invalidateCharacterCoordinates];
[self unmarkText];
uint64_t timestamp = static_cast<uint64_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]);
}
- (NSUInteger)characterIndexForPoint:(NSPoint)point
@ -746,15 +780,11 @@
}
- (void) setText:(NSString *)text{
[_text setString:text];
[[self inputContext] discardMarkedText];
[[_text mutableString] setString:text];
}
- (void) setSelection:(int)start :(int)end{
_selection = NSMakeRange(start, end - start);
[[self inputContext] invalidateCharacterCoordinates];
_selectedRange = NSMakeRange(start, end - start);
}
- (void) setCursorRect:(AvnRect)rect{
@ -766,7 +796,9 @@
_cursorRect = windowRectOnScreen;
[[self inputContext] invalidateCharacterCoordinates];
if([self inputContext]) {
[[self inputContext] invalidateCharacterCoordinates];
}
}
@end

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

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

14
nukebuild/Build.cs

@ -35,8 +35,6 @@ using MicroCom.CodeGenerator;
partial class Build : NukeBuild
{
[Solution("Avalonia.sln")] readonly Solution Solution;
BuildParameters Parameters { get; set; }
protected override void OnBuildInitialized()
{
@ -143,10 +141,12 @@ partial class Build : NukeBuild
void RunCoreTest(string projectName)
{
Information($"Running tests from {projectName}");
var project = Solution.GetProject(projectName).NotNull("project != null");
var project = RootDirectory.GlobFiles(@$"**\{projectName}.csproj").FirstOrDefault()
?? throw new InvalidOperationException($"Project {projectName} doesn't exist");
// Nuke and MSBuild tools have build-in helpers to get target frameworks from the project.
// Unfortunately, it gets broken with every second SDK update, so we had to do it manually.
var fileXml = XDocument.Parse(File.ReadAllText(project.Path));
var fileXml = XDocument.Parse(File.ReadAllText(project));
var targetFrameworks = fileXml.Descendants("TargetFrameworks")
.FirstOrDefault()?.Value.Split(';').Select(f => f.Trim());
if (targetFrameworks is null)
@ -212,6 +212,8 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests");
RunCoreTest("Avalonia.Headless.NUnit.UnitTests");
RunCoreTest("Avalonia.Headless.XUnit.UnitTests");
});
Target RunRenderTests => _ => _
@ -273,6 +275,8 @@ partial class Build : NukeBuild
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
new NumergeNukeLogger()))
throw new Exception("Package merge failed");
RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
Parameters.Version + ".nupkg");
});
Target RunTests => _ => _
@ -308,7 +312,7 @@ partial class Build : NukeBuild
public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Execute<Build>(x => x.Package)
? Execute<Build>(x => x.RunToolsTests)
: Execute<Build>(x => x.RunTests);
}

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

177
nukebuild/RefAssemblyGenerator.cs

@ -0,0 +1,177 @@
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.FirstOrDefault(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, ICustomAttribute unstableAttribute)
{
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
return;
unstableAttribute = def.CustomAttributes.FirstOrDefault(a =>
a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute") ?? unstableAttribute;
if (unstableAttribute is null)
return;
var message = unstableAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString();
if (string.IsNullOrEmpty(message))
{
message = "This is a part of unstable API and can be changed in minor releases. Consider replacing it with alternatives or reach out developers on GitHub.";
}
def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
{
ConstructorArguments =
{
new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String, message)
}
});
}
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}");
}
}
}
}

15
nukebuild/_build.csproj

@ -15,7 +15,7 @@
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
<PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" />
<!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
<PackageReference Include="xunit.runner.console" Version="2.4.2">
@ -31,18 +31,11 @@
<!-- Common build related files -->
<Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Numerge\Numerge.Console\" />
</ItemGroup>
</Project>

5
nukebuild/numerge.config

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

21
packages/Avalonia/Avalonia.csproj

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

2
packages/Avalonia/Avalonia.props

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

63
readme.md

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

8
samples/VirtualizationDemo/App.xaml → samples/AppWithoutLifetime/App.axaml

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

12
samples/AppWithoutLifetime/App.axaml.cs

@ -0,0 +1,12 @@
using Avalonia;
using Avalonia.Markup.Xaml;
namespace AppWithoutLifetime;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
}

21
samples/AppWithoutLifetime/AppWithoutLifetime.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

13
samples/AppWithoutLifetime/MainWindow.axaml

@ -0,0 +1,13 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AppWithoutLifetime.MainWindow"
Title="AppWithoutLifetime">
<StackPanel>
<TextBlock Text="Welcome to Avalonia!"/>
<CheckBox Content="Welcome to Avalonia!"/>
<Button Click="Open" Content="Open"/>
</StackPanel>
</Window>

30
samples/AppWithoutLifetime/MainWindow.axaml.cs

@ -0,0 +1,30 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace AppWithoutLifetime;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
protected override void OnLoaded()
{
this.AttachDevTools();
base.OnLoaded();
}
public void Open(object sender, RoutedEventArgs e)
{
new Sub().Show(this);
}
}

28
samples/AppWithoutLifetime/Program.cs

@ -0,0 +1,28 @@
using Avalonia;
using Avalonia.Controls;
using System;
namespace AppWithoutLifetime;
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().Start(AppMain, args);
}
private static void AppMain(Application app, string[] args)
{
app.Run(new MainWindow());
}
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
}

9
samples/AppWithoutLifetime/Sub.axaml

@ -0,0 +1,9 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AppWithoutLifetime.Sub"
Title="Window1">
Welcome to Avalonia Sub!
</Window>

24
samples/AppWithoutLifetime/Sub.axaml.cs

@ -0,0 +1,24 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace AppWithoutLifetime;
public partial class Sub : Window
{
public Sub()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
protected override void OnLoaded()
{
this.AttachDevTools();
base.OnLoaded();
}
}

18
samples/AppWithoutLifetime/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="AppWithoutLifetime"/>
<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>

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

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

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

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

2
samples/ControlCatalog/App.xaml

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

48
samples/ControlCatalog/MainView.xaml.cs

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

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

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

15
samples/ControlCatalog/Pages/ComboBoxPage.xaml

@ -98,6 +98,21 @@
<ComboBoxItem>Inline Item 3</ComboBoxItem>
<ComboBoxItem>Inline Item 4</ComboBoxItem>
</ComboBox>
<ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" DisplayMemberBinding="{Binding Name}">
</ComboBox>
<ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBlock Text="{Binding Id}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</WrapPanel>
<CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>

2
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml

@ -67,7 +67,7 @@
</Style>
</Border.Styles>
<Border.ContextFlyout>
<MenuFlyout Items="{Binding MenuItems}" />
<MenuFlyout ItemsSource="{Binding MenuItems}" />
</Border.ContextFlyout>
<TextBlock Text="Dynamically Generated"/>
</Border>

11
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

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

2
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -94,7 +94,7 @@
<Grid RowDefinitions="*,Auto">
<!-- Example of columns inheriting the data type from the Items source -->
<DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0"
Items="{Binding DataGrid3Source}">
ItemsSource="{Binding DataGrid3Source}">
<DataGrid.Columns>
<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}" />

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

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

4
samples/ControlCatalog/Pages/DialogsPage.xaml

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

2
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml

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

2
samples/ControlCatalog/Pages/TextBlockPage.xaml

@ -118,7 +118,7 @@
</StackPanel>
</Border>
<Border>
<SelectableTextBlock SelectionBrush="LightBlue" Margin="10" TextWrapping="Wrap">
<SelectableTextBlock Margin="10" TextWrapping="Wrap">
This <Span FontWeight="Bold">is</Span> a
<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
with <Span TextDecorations="Underline">several</Span>

15
samples/ControlCatalog/ViewModels/ComboBoxPageViewModel.cs

@ -16,5 +16,20 @@ namespace ControlCatalog.ViewModels
get => _wrapSelection;
set => this.RaiseAndSetIfChanged(ref _wrapSelection, value);
}
public ObservableCollection<IdAndName> Values { get; set; } = new ObservableCollection<IdAndName>
{
new IdAndName(){ Id = "Id 1", Name = "Name 1" },
new IdAndName(){ Id = "Id 2", Name = "Name 2" },
new IdAndName(){ Id = "Id 3", Name = "Name 3" },
new IdAndName(){ Id = "Id 4", Name = "Name 4" },
new IdAndName(){ Id = "Id 5", Name = "Name 5" },
};
}
public class IdAndName
{
public string Id { get; set; }
public string Name { get; set; }
}
}

1
samples/IntegrationTestApp/IntegrationTestApp.csproj

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

17
samples/IntegrationTestApp/MainWindow.axaml

@ -170,10 +170,21 @@
</StackPanel>
</Grid>
</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="ScrollBarTab">
<TabItem Header="ScrollBar">
<ScrollBar Name="MyScrollBar" Orientation="Horizontal" AllowAutoHide="False" Width="200" Height="30" Value="20"/>
</TabItem>
</TabControl>

6
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -202,7 +202,7 @@ namespace IntegrationTestApp
{
var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
foreach (var window in lifetime.Windows)
foreach (var window in lifetime.Windows.ToArray())
{
window.Activate();
}
@ -212,7 +212,7 @@ namespace IntegrationTestApp
{
var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
foreach (var window in lifetime.Windows)
foreach (var window in lifetime.Windows.ToArray())
{
window.Show();
if (window.WindowState == WindowState.Minimized)
@ -270,6 +270,8 @@ namespace IntegrationTestApp
this.Get<ListBox>("BasicListBox").SelectedIndex = -1;
if (source?.Name == "MenuClickedMenuItemReset")
this.Get<TextBlock>("ClickedMenuItem").Text = "None";
if (source?.Name == "ResetSliders")
this.Get<Slider>("HorizontalSlider").Value = 50;
if (source?.Name == "ShowTransparentWindow")
ShowTransparentWindow();
if (source?.Name == "ShowTransparentPopup")

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

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

40
samples/RenderDemo/Pages/AnimationsPage.xaml

@ -308,6 +308,41 @@
</Animation>
</Style.Animations>
</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>
</UserControl.Styles>
<Grid>
@ -332,6 +367,11 @@
<Border Classes="Test Rect8" Child="{x:Null}" />
<Border Classes="Test Rect9" 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>
</StackPanel>
</Grid>

4
samples/RenderDemo/Pages/CustomSkiaPage.cs

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

2
samples/RenderDemo/Pages/WriteableBitmapPage.cs

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

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\Headless\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>

17
samples/SafeAreaDemo.iOS/AppDelegate.cs

@ -0,0 +1,17 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.iOS;
using Avalonia.Media;
using Foundation;
using UIKit;
namespace SafeAreaDemo.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : AvaloniaAppDelegate<App>
{
}
}

5
samples/SafeAreaDemo.iOS/Entitlements.plist

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

47
samples/SafeAreaDemo.iOS/Info.plist

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>SafeAreaDemo</string>
<key>CFBundleIdentifier</key>
<string>companyName.SafeAreaDemo</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>10.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

15
samples/SafeAreaDemo.iOS/Main.cs

@ -0,0 +1,15 @@
using UIKit;
namespace SafeAreaDemo.iOS
{
public class Application
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}

43
samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207" />
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1" />
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" />
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder" />
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480" />
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" />
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2022 " textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines"
minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21" />
<fontDescription key="fontDescription" type="system" pointSize="17" />
<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
<nil key="highlightedColor" />
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SafeAreaDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines"
minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43" />
<fontDescription key="fontDescription" type="boldSystem" pointSize="36" />
<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
<nil key="highlightedColor" />
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite" />
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC" />
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk" />
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l" />
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0" />
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9" />
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g" />
</constraints>
<nil key="simulatedStatusBarMetrics" />
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics" />
<point key="canvasLocation" x="548" y="455" />
</view>
</objects>
</document>

18
samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-ios</TargetFramework>
<SupportedOSPlatformVersion>10.0</SupportedOSPlatformVersion>
<ProvisioningType>manual</ProvisioningType>
<Nullable>enable</Nullable>
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
<!-- These properties need to be set in order to run on a real iDevice -->
<!--<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>-->
<!--<CodesignKey></CodesignKey>-->
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
<ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" />
</ItemGroup>
</Project>

15
samples/SafeAreaDemo/App.xaml

@ -0,0 +1,15 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SafeAreaDemo"
x:Class="SafeAreaDemo.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

36
samples/SafeAreaDemo/App.xaml.cs

@ -0,0 +1,36 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using SafeAreaDemo.ViewModels;
using SafeAreaDemo.Views;
namespace SafeAreaDemo
{
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainViewModel()
};
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
{
singleViewPlatform.MainView = new MainView
{
DataContext = new MainViewModel()
};
}
base.OnFrameworkInitializationCompleted();
}
}
}

BIN
samples/SafeAreaDemo/Assets/avalonia-logo.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

27
samples/SafeAreaDemo/SafeAreaDemo.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

31
samples/SafeAreaDemo/ViewLocator.cs

@ -0,0 +1,31 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using MiniMvvm;
namespace SafeAreaDemo
{
public class ViewLocator : IDataTemplate
{
public Control? Build(object? data)
{
if (data is null)
return null;
var name = data.GetType().FullName!.Replace("ViewModel", "View");
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}
}

112
samples/SafeAreaDemo/ViewModels/MainViewModel.cs

@ -0,0 +1,112 @@
using Avalonia;
using Avalonia.Controls.Platform;
using MiniMvvm;
namespace SafeAreaDemo.ViewModels
{
public class MainViewModel : ViewModelBase
{
private bool _useSafeArea = true;
private bool _fullscreen;
private IInsetsManager? _insetsManager;
private bool _hideSystemBars;
public Thickness SafeAreaPadding
{
get
{
return _insetsManager?.SafeAreaPadding ?? default;
}
}
public Thickness ViewPadding
{
get
{
return _useSafeArea ? SafeAreaPadding : default;
}
}
public bool UseSafeArea
{
get => _useSafeArea;
set
{
_useSafeArea = value;
this.RaisePropertyChanged();
RaiseSafeAreaChanged();
}
}
public bool Fullscreen
{
get => _fullscreen;
set
{
_fullscreen = value;
if (_insetsManager != null)
{
_insetsManager.DisplayEdgeToEdge = value;
}
this.RaisePropertyChanged();
RaiseSafeAreaChanged();
}
}
public bool HideSystemBars
{
get => _hideSystemBars;
set
{
_hideSystemBars = value;
if (_insetsManager != null)
{
_insetsManager.IsSystemBarVisible = !value;
}
this.RaisePropertyChanged();
RaiseSafeAreaChanged();
}
}
internal IInsetsManager? InsetsManager
{
get => _insetsManager;
set
{
if (_insetsManager != null)
{
_insetsManager.SafeAreaChanged -= InsetsManager_SafeAreaChanged;
}
_insetsManager = value;
if (_insetsManager != null)
{
_insetsManager.SafeAreaChanged += InsetsManager_SafeAreaChanged;
_insetsManager.DisplayEdgeToEdge = _fullscreen;
_insetsManager.IsSystemBarVisible = !_hideSystemBars;
}
}
}
private void InsetsManager_SafeAreaChanged(object? sender, SafeAreaChangedArgs e)
{
RaiseSafeAreaChanged();
}
private void RaiseSafeAreaChanged()
{
this.RaisePropertyChanged(nameof(SafeAreaPadding));
this.RaisePropertyChanged(nameof(ViewPadding));
}
}
}

52
samples/SafeAreaDemo/Views/MainView.xaml

@ -0,0 +1,52 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SafeAreaDemo.ViewModels"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
x:Class="SafeAreaDemo.Views.MainView"
x:DataType="vm:MainViewModel">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Border BorderBrush="Red"
Margin="{Binding ViewPadding}"
BorderThickness="1">
<Grid>
<Label Margin="5"
Foreground="Red"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Right">View Bounds</Label>
<Label Margin="5"
Foreground="Red"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Right">View Bounds</Label>
</Grid>
</Border>
<Border BorderBrush="LimeGreen"
Margin="{Binding SafeAreaPadding}"
BorderThickness="1">
<DockPanel>
<Label Margin="5"
Foreground="LimeGreen"
DockPanel.Dock="Bottom"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" >Safe Area</Label>
<Grid DockPanel.Dock="Bottom"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Label HorizontalAlignment="Left">Options:</Label>
<CheckBox IsChecked="{Binding Fullscreen}">Fullscreen</CheckBox>
<CheckBox IsChecked="{Binding UseSafeArea}">Use Safe Area</CheckBox>
<CheckBox IsChecked="{Binding HideSystemBars}">Hide System Bars</CheckBox>
<TextBox Width="200" Watermark="Tap to Show Keyboard"/>
</StackPanel>
</Grid>
</DockPanel>
</Border>
</Grid>
</UserControl>

25
samples/SafeAreaDemo/Views/MainView.xaml.cs

@ -0,0 +1,25 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using SafeAreaDemo.ViewModels;
namespace SafeAreaDemo.Views
{
public partial class MainView : UserControl
{
public MainView()
{
AvaloniaXamlLoader.Load(this);
}
protected override void OnLoaded()
{
base.OnLoaded();
var insetsManager = TopLevel.GetTopLevel(this)?.InsetsManager;
if (insetsManager != null && DataContext is MainViewModel viewModel)
{
viewModel.InsetsManager = insetsManager;
}
}
}
}

12
samples/SafeAreaDemo/Views/MainWindow.xaml

@ -0,0 +1,12 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:SafeAreaDemo.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:SafeAreaDemo.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SafeAreaDemo.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Title="SafeAreaDemo">
<views:MainView />
</Window>

13
samples/SafeAreaDemo/Views/MainWindow.xaml.cs

@ -0,0 +1,13 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace SafeAreaDemo.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
AvaloniaXamlLoader.Load(this);
}
}
}

11
samples/Sandbox/MainWindow.axaml.cs

@ -1,22 +1,17 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Input.TextInput;
using Avalonia.Markup.Xaml;
using Avalonia.Win32.WinRT.Composition;
namespace Sandbox
{
public class MainWindow : Window
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.AttachDevTools();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
InitializeComponent();
}
}
}

2
samples/Sandbox/Sandbox.csproj

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

14
samples/VirtualizationDemo/App.axaml

@ -0,0 +1,14 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="VirtualizationDemo.App">
<Application.Styles>
<FluentTheme/>
</Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://ControlSamples/HamburgerMenu/HamburgerMenu.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

20
samples/VirtualizationDemo/App.axaml.cs

@ -0,0 +1,20 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace VirtualizationDemo;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
}

21
samples/VirtualizationDemo/App.xaml.cs

@ -1,21 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace VirtualizationDemo
{
public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
}
}

190
samples/VirtualizationDemo/Assets/chat.json

@ -0,0 +1,190 @@
{
"chat": [
{
"sender": "Alice",
"message": "Hey Bob! How was your weekend?",
"timestamp": "2023-04-01T10:00:00"
},
{
"sender": "Bob",
"message": "It was great, thanks for asking. I went on a camping trip with some friends. How about you?",
"timestamp": "2023-04-01T10:01:00"
},
{
"sender": "Alice",
"message": "My weekend was pretty chill. I just stayed home and caught up on some TV shows.",
"timestamp": "2023-04-01T10:03:00"
},
{
"sender": "Bob",
"message": "That sounds relaxing. What shows did you watch?",
"timestamp": "2023-04-01T10:05:00"
},
{
"sender": "Alice",
"message": "I watched the new season of 'Stranger Things' and started watching 'Ozark'. Have you seen them?",
"timestamp": "2023-04-01T10:07:00"
},
{
"sender": "Bob",
"message": "Yeah, I've seen both of those. They're really good! What do you think of them so far?",
"timestamp": "2023-04-01T10:10:00"
},
{
"sender": "Alice",
"message": "I'm really enjoying 'Stranger Things', but 'Ozark' is a bit darker than I expected. I'm only a few episodes in though, so we'll see how it goes.",
"timestamp": "2023-04-01T10:12:00"
},
{
"sender": "Bob",
"message": "Yeah, 'Ozark' can be intense at times, but it's really well done. Keep watching, it gets even better.",
"timestamp": "2023-04-01T10:15:00"
},
{
"sender": "Alice",
"message": "Thanks for the recommendation, I'll definitely keep watching. So, how's work been for you lately?",
"timestamp": "2023-04-01T10:20:00"
},
{
"sender": "Bob",
"message": "It's been pretty busy, but I'm managing. How about you?",
"timestamp": "2023-04-01T10:22:00"
},
{
"sender": "Alice",
"message": "Same here, things have been pretty hectic. But it keeps us on our toes, right?",
"timestamp": "2023-04-01T10:25:00"
},
{
"sender": "Bob",
"message": "Absolutely. Hey, have you heard about the new project we're starting next week?",
"timestamp": "2023-04-01T10:30:00"
},
{
"sender": "Alice",
"message": "No, I haven't. What's it about?",
"timestamp": "2023-04-01T10:32:00"
},
{
"sender": "Bob",
"message": "It's a big project for a new client, and it's going to require a lot of extra hours from all of us. But the pay is going to be great,so it's definitely worth the extra effort. I'll fill you in on the details later, but for now, let's just enjoy our coffee break, shall we?",
"timestamp": "2023-04-01T10:35:00"
},
{
"sender": "Alice",
"message": "Sounds good to me. I could use a break right about now.",
"timestamp": "2023-04-01T10:40:00"
},
{
"sender": "Bob",
"message": "Me too. So, have you tried the new caf� down the street yet?",
"timestamp": "2023-04-01T10:45:00"
},
{
"sender": "Alice",
"message": "No, I haven't. Is it any good?",
"timestamp": "2023-04-01T10:47:00"
},
{
"sender": "Bob",
"message": "It's really good! They have the best croissants I've ever tasted.",
"timestamp": "2023-04-01T10:50:00"
},
{
"sender": "Alice",
"message": "Hmm, I'll have to try it out sometime. Do they have any vegan options?",
"timestamp": "2023-04-01T10:52:00"
},
{
"sender": "Bob",
"message": "I'm not sure, but I think they do. You should ask them the next time you go there.",
"timestamp": "2023-04-01T10:55:00"
},
{
"sender": "Alice",
"message": "Thanks for the suggestion. I'm always looking for good vegan options around here.",
"timestamp": "2023-04-01T11:00:00"
},
{
"sender": "Bob",
"message": "No problem. So, have you made any plans for the weekend yet?",
"timestamp": "2023-04-01T11:05:00"
},
{
"sender": "Alice",
"message": "Not yet. I was thinking of maybe going for a hike or something. What about you?",
"timestamp": "2023-04-01T11:07:00"
},
{
"sender": "Bob",
"message": "I haven't made any plans either. Maybe we could do something together?",
"timestamp": "2023-04-01T11:10:00"
},
{
"sender": "Alice",
"message": "That sounds like a great idea! Let's plan on it.",
"timestamp": "2023-04-01T11:12:00"
},
{
"sender": "Bob",
"message": "Awesome. I'll check out some hiking trails and let you know which ones look good.",
"timestamp": "2023-04-01T11:15:00"
},
{
"sender": "Alice",
"message": "Sounds good. I can't wait!",
"timestamp": "2023-04-01T11:20:00"
},
{
"sender": "John",
"message": "Hey Lisa, how was your day?",
"timestamp": "2023-04-01T18:00:00"
},
{
"sender": "Lisa",
"message": "It was good, thanks for asking. How about you?",
"timestamp": "2023-04-01T18:05:00"
},
{
"sender": "John",
"message": "Eh, it was alright. Work was pretty busy, but nothing too crazy.",
"timestamp": "2023-04-01T18:10:00"
},
{
"sender": "Lisa",
"message": "Yeah, I know what you mean. My boss has been on my case lately about meeting our deadlines.",
"timestamp": "2023-04-01T18:15:00"
},
{
"sender": "John",
"message": "That sucks. Are you feeling stressed out?",
"timestamp": "2023-04-01T18:20:00"
},
{
"sender": "Lisa",
"message": "A little bit, yeah. But I'm trying to stay positive and focus on getting my work done.",
"timestamp": "2023-04-01T18:25:00"
},
{
"sender": "John",
"message": "That's a good attitude to have. Have you tried doing some meditation or other relaxation techniques?",
"timestamp": "2023-04-01T18:30:00"
},
{
"sender": "Lisa",
"message": "I haven't, but I've been thinking about it. Do you have any suggestions?",
"timestamp": "2023-04-01T18:35:00"
},
{
"sender": "John",
"message": "Sure, I could send you some links to guided meditations that I've found helpful. And there are also some great apps out there that can help you with relaxation.",
"timestamp": "2023-04-01T18:40:00"
},
{
"sender": "Lisa",
"message": "That would be awesome, thanks so much!",
"timestamp": "2023-04-01T18:45:00"
}
]
}

20
samples/VirtualizationDemo/MainWindow.axaml

@ -0,0 +1,20 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ControlSamples"
xmlns:vm="using:VirtualizationDemo.ViewModels"
xmlns:views="using:VirtualizationDemo.Views"
x:Class="VirtualizationDemo.MainWindow"
Title="AvaloniaUI Virtualization Demo"
x:DataType="vm:MainWindowViewModel">
<controls:HamburgerMenu>
<TabItem Header="Playground" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<views:PlaygroundPageView DataContext="{Binding Playground}"/>
</TabItem>
<TabItem Header="Chat" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<views:ChatPageView DataContext="{Binding Chat}"/>
</TabItem>
<TabItem Header="Expanders" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<views:ExpanderPageView DataContext="{Binding Expanders}"/>
</TabItem>
</controls:HamburgerMenu>
</Window>

15
samples/VirtualizationDemo/MainWindow.axaml.cs

@ -0,0 +1,15 @@
using Avalonia;
using Avalonia.Controls;
using VirtualizationDemo.ViewModels;
namespace VirtualizationDemo;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.AttachDevTools();
DataContext = new MainWindowViewModel();
}
}

64
samples/VirtualizationDemo/MainWindow.xaml

@ -1,64 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="using:VirtualizationDemo.ViewModels"
x:Class="VirtualizationDemo.MainWindow"
Title="AvaloniaUI Virtualization Test"
Width="800"
Height="600"
x:DataType="viewModels:MainWindowViewModel">
<DockPanel LastChildFill="True" Margin="16">
<StackPanel DockPanel.Dock="Right"
Margin="16 0 0 0"
Width="150"
Spacing="4">
<ComboBox ItemsSource="{Binding Orientations}"
SelectedItem="{Binding Orientation}"/>
<TextBox Watermark="Item Count"
UseFloatingWatermark="True"
Text="{Binding ItemCount}"/>
<TextBox Watermark="Extent"
UseFloatingWatermark="True"
Text="{Binding #listBox.Scroll.Extent, Mode=OneWay}"/>
<TextBox Watermark="Offset"
UseFloatingWatermark="True"
Text="{Binding #listBox.Scroll.Offset, Mode=OneWay}"/>
<TextBox Watermark="Viewport"
UseFloatingWatermark="True"
Text="{Binding #listBox.Scroll.Viewport, Mode=OneWay}"/>
<TextBlock>Horiz. ScrollBar</TextBlock>
<ComboBox ItemsSource="{Binding ScrollBarVisibilities}"
SelectedItem="{Binding HorizontalScrollBarVisibility}"/>
<TextBlock>Vert. ScrollBar</TextBlock>
<ComboBox ItemsSource="{Binding ScrollBarVisibilities}"
SelectedItem="{Binding VerticalScrollBarVisibility}"/>
<TextBox Watermark="Item to Create"
UseFloatingWatermark="True"
Text="{Binding NewItemString}"/>
<Button Command="{Binding AddItemCommand}">Add Item</Button>
<Button Command="{Binding RemoveItemCommand}">Remove Item</Button>
<Button Command="{Binding RecreateCommand}">Recreate</Button>
<Button Command="{Binding SelectFirstCommand}">Select First</Button>
<Button Command="{Binding SelectLastCommand}">Select Last</Button>
<Button Command="{Binding RandomizeSize}">Randomize Size</Button>
<Button Command="{Binding ResetSize}">Reset Size</Button>
</StackPanel>
<ListBox Name="listBox"
ItemsSource="{Binding Items}"
Selection="{Binding Selection}"
SelectionMode="Multiple"
ScrollViewer.HorizontalScrollBarVisibility="{Binding HorizontalScrollBarVisibility, Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="{Binding VerticalScrollBarVisibility, Mode=TwoWay}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="{Binding Orientation}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" Height="{Binding Height}" TextWrapping="Wrap"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Window>

22
samples/VirtualizationDemo/MainWindow.xaml.cs

@ -1,22 +0,0 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using VirtualizationDemo.ViewModels;
namespace VirtualizationDemo
{
public class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.AttachDevTools();
DataContext = new MainWindowViewModel();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

23
samples/VirtualizationDemo/Models/Chat.cs

@ -0,0 +1,23 @@
using System;
using System.IO;
using System.Text.Json;
namespace VirtualizationDemo.Models;
public class ChatFile
{
public ChatMessage[]? Chat { get; set; }
public static ChatFile Load(string path)
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
using var s = File.OpenRead(path);
return JsonSerializer.Deserialize<ChatFile>(s, options)!;
}
}
public record ChatMessage(string Sender, string Message, DateTimeOffset Timestamp);

19
samples/VirtualizationDemo/Program.cs

@ -1,15 +1,14 @@
using Avalonia;
namespace VirtualizationDemo
namespace VirtualizationDemo;
class Program
{
class Program
{
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}

17
samples/VirtualizationDemo/ViewModels/ChatPageViewModel.cs

@ -0,0 +1,17 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using VirtualizationDemo.Models;
namespace VirtualizationDemo.ViewModels;
public class ChatPageViewModel
{
public ChatPageViewModel()
{
var chat = ChatFile.Load(Path.Combine("Assets", "chat.json"));
Messages = new(chat.Chat ?? Array.Empty<ChatMessage>());
}
public ObservableCollection<ChatMessage> Messages { get; }
}

21
samples/VirtualizationDemo/ViewModels/ExpanderItemViewModel.cs

@ -0,0 +1,21 @@
using MiniMvvm;
namespace VirtualizationDemo.ViewModels;
public class ExpanderItemViewModel : ViewModelBase
{
private string? _header;
private bool _isExpanded;
public string? Header
{
get => _header;
set => RaiseAndSetIfChanged(ref _header, value);
}
public bool IsExpanded
{
get => _isExpanded;
set => RaiseAndSetIfChanged(ref _isExpanded, value);
}
}

17
samples/VirtualizationDemo/ViewModels/ExpanderPageViewModel.cs

@ -0,0 +1,17 @@
using System.Collections.ObjectModel;
using System.Linq;
namespace VirtualizationDemo.ViewModels;
internal class ExpanderPageViewModel
{
public ExpanderPageViewModel()
{
Items = new(Enumerable.Range(0, 100).Select(x => new ExpanderItemViewModel
{
Header = $"Item {x}",
}));
}
public ObservableCollection<ExpanderItemViewModel> Items { get; set; }
}

26
samples/VirtualizationDemo/ViewModels/ItemViewModel.cs

@ -1,26 +0,0 @@
using System;
using MiniMvvm;
namespace VirtualizationDemo.ViewModels
{
internal class ItemViewModel : ViewModelBase
{
private string _prefix;
private int _index;
private double _height = double.NaN;
public ItemViewModel(int index, string prefix = "Item")
{
_prefix = prefix;
_index = index;
}
public string Header => $"{_prefix} {_index}";
public double Height
{
get => _height;
set => this.RaiseAndSetIfChanged(ref _height, value);
}
}
}

164
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@ -1,160 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.Controls.Selection;
using MiniMvvm;
using MiniMvvm;
namespace VirtualizationDemo.ViewModels
{
internal class MainWindowViewModel : ViewModelBase
{
private int _itemCount = 200;
private string _newItemString = "New Item";
private int _newItemIndex;
private AvaloniaList<ItemViewModel> _items;
private string _prefix = "Item";
private ScrollBarVisibility _horizontalScrollBarVisibility = ScrollBarVisibility.Auto;
private ScrollBarVisibility _verticalScrollBarVisibility = ScrollBarVisibility.Auto;
private Orientation _orientation = Orientation.Vertical;
public MainWindowViewModel()
{
this.WhenAnyValue(x => x.ItemCount).Subscribe(ResizeItems);
RecreateCommand = MiniCommand.Create(() => Recreate());
AddItemCommand = MiniCommand.Create(() => AddItem());
RemoveItemCommand = MiniCommand.Create(() => Remove());
SelectFirstCommand = MiniCommand.Create(() => SelectItem(0));
SelectLastCommand = MiniCommand.Create(() => SelectItem(Items.Count - 1));
}
public string NewItemString
{
get { return _newItemString; }
set { this.RaiseAndSetIfChanged(ref _newItemString, value); }
}
public int ItemCount
{
get { return _itemCount; }
set { this.RaiseAndSetIfChanged(ref _itemCount, value); }
}
public SelectionModel<ItemViewModel> Selection { get; } = new SelectionModel<ItemViewModel>();
public AvaloniaList<ItemViewModel> Items
{
get { return _items; }
private set { this.RaiseAndSetIfChanged(ref _items, value); }
}
public Orientation Orientation
{
get { return _orientation; }
set { this.RaiseAndSetIfChanged(ref _orientation, value); }
}
public IEnumerable<Orientation> Orientations =>
Enum.GetValues(typeof(Orientation)).Cast<Orientation>();
public ScrollBarVisibility HorizontalScrollBarVisibility
{
get { return _horizontalScrollBarVisibility; }
set { this.RaiseAndSetIfChanged(ref _horizontalScrollBarVisibility, value); }
}
namespace VirtualizationDemo.ViewModels;
public ScrollBarVisibility VerticalScrollBarVisibility
{
get { return _verticalScrollBarVisibility; }
set { this.RaiseAndSetIfChanged(ref _verticalScrollBarVisibility, value); }
}
public IEnumerable<ScrollBarVisibility> ScrollBarVisibilities =>
Enum.GetValues(typeof(ScrollBarVisibility)).Cast<ScrollBarVisibility>();
public MiniCommand AddItemCommand { get; private set; }
public MiniCommand RecreateCommand { get; private set; }
public MiniCommand RemoveItemCommand { get; private set; }
public MiniCommand SelectFirstCommand { get; private set; }
public MiniCommand SelectLastCommand { get; private set; }
public void RandomizeSize()
{
var random = new Random();
foreach (var i in Items)
{
i.Height = random.Next(240) + 10;
}
}
public void ResetSize()
{
foreach (var i in Items)
{
i.Height = double.NaN;
}
}
private void ResizeItems(int count)
{
if (Items == null)
{
var items = Enumerable.Range(0, count)
.Select(x => new ItemViewModel(x));
Items = new AvaloniaList<ItemViewModel>(items);
}
else if (count > Items.Count)
{
var items = Enumerable.Range(Items.Count, count - Items.Count)
.Select(x => new ItemViewModel(x));
Items.AddRange(items);
}
else if (count < Items.Count)
{
Items.RemoveRange(count, Items.Count - count);
}
}
private void AddItem()
{
var index = Items.Count;
if (Selection.SelectedItems.Count > 0)
{
index = Selection.SelectedIndex;
}
Items.Insert(index, new ItemViewModel(_newItemIndex++, NewItemString));
}
private void Remove()
{
if (Selection.SelectedItems.Count > 0)
{
Items.RemoveAll(Selection.SelectedItems.ToList());
}
}
private void Recreate()
{
_prefix = _prefix == "Item" ? "Recreated" : "Item";
var items = Enumerable.Range(0, _itemCount)
.Select(x => new ItemViewModel(x, _prefix));
Items = new AvaloniaList<ItemViewModel>(items);
}
private void SelectItem(int index)
{
Selection.SelectedIndex = index;
}
}
internal class MainWindowViewModel : ViewModelBase
{
public PlaygroundPageViewModel Playground { get; } = new();
public ChatPageViewModel Chat { get; } = new();
public ExpanderPageViewModel Expanders { get; } = new();
}

17
samples/VirtualizationDemo/ViewModels/PlaygroundItemViewModel.cs

@ -0,0 +1,17 @@
using MiniMvvm;
namespace VirtualizationDemo.ViewModels;
public class PlaygroundItemViewModel : ViewModelBase
{
private string? _header;
public PlaygroundItemViewModel(int index) => Header = $"Item {index}";
public PlaygroundItemViewModel(string? header) => Header = header;
public string? Header
{
get => _header;
set => RaiseAndSetIfChanged(ref _header, value);
}
}

95
samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs

@ -0,0 +1,95 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
using MiniMvvm;
namespace VirtualizationDemo.ViewModels;
public class PlaygroundPageViewModel : ViewModelBase
{
private SelectionMode _selectionMode = SelectionMode.Multiple;
private int _scrollToIndex = 500;
private string? _newItemHeader = "New Item 1";
public PlaygroundPageViewModel()
{
Items = new(Enumerable.Range(0, 1000).Select(x => new PlaygroundItemViewModel(x)));
Selection = new();
}
public ObservableCollection<PlaygroundItemViewModel> Items { get; }
public bool Multiple
{
get => _selectionMode.HasAnyFlag(SelectionMode.Multiple);
set => SetSelectionMode(SelectionMode.Multiple, value);
}
public bool Toggle
{
get => _selectionMode.HasAnyFlag(SelectionMode.Toggle);
set => SetSelectionMode(SelectionMode.Toggle, value);
}
public bool AlwaysSelected
{
get => _selectionMode.HasAnyFlag(SelectionMode.AlwaysSelected);
set => SetSelectionMode(SelectionMode.AlwaysSelected, value);
}
public SelectionModel<PlaygroundItemViewModel> Selection { get; }
public SelectionMode SelectionMode
{
get => _selectionMode;
set => RaiseAndSetIfChanged(ref _selectionMode, value);
}
public int ScrollToIndex
{
get => _scrollToIndex;
set => RaiseAndSetIfChanged(ref _scrollToIndex, value);
}
public string? NewItemHeader
{
get => _newItemHeader;
set => RaiseAndSetIfChanged(ref _newItemHeader, value);
}
public void ExecuteScrollToIndex()
{
Selection.Select(ScrollToIndex);
}
public void RandomizeScrollToIndex()
{
var rnd = new Random();
ScrollToIndex = rnd.Next(Items.Count);
}
public void AddAtSelectedIndex()
{
if (Selection.SelectedIndex == -1)
return;
Items.Insert(Selection.SelectedIndex, new(NewItemHeader));
}
public void DeleteSelectedItem()
{
var count = Selection.Count;
for (var i = count - 1; i >= 0; i--)
Items.RemoveAt(Selection.SelectedIndexes[i]);
}
private void SetSelectionMode(SelectionMode mode, bool value)
{
if (value)
SelectionMode |= mode;
else
SelectionMode &= ~mode;
}
}

39
samples/VirtualizationDemo/Views/ChatPageView.axaml

@ -0,0 +1,39 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:VirtualizationDemo.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="VirtualizationDemo.Views.ChatPageView"
x:DataType="vm:ChatPageViewModel">
<ListBox ItemsSource="{Binding Messages}">
<ListBox.ItemContainerTheme>
<ControlTheme TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="Padding" Value="8"/>
</ControlTheme>
</ListBox.ItemContainerTheme>
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="8"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
TextElement.Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"
Padding="6"
HorizontalAlignment="Left"
MaxWidth="280">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
Text="{Binding Sender}"
FontWeight="Bold"/>
<TextBlock DockPanel.Dock="Bottom"
Text="{Binding Timestamp}"
FontSize="10"
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
TextAlignment="Right"
Margin="0 4 0 0"/>
<TextBlock Text="{Binding Message}" TextWrapping="Wrap"/>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>

11
samples/VirtualizationDemo/Views/ChatPageView.axaml.cs

@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace VirtualizationDemo.Views;
public partial class ChatPageView : UserControl
{
public ChatPageView()
{
InitializeComponent();
}
}

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

Loading…
Cancel
Save