Browse Source

Merge branch 'master' into SetterTargetType

pull/8572/head
Max Katz 4 years ago
committed by GitHub
parent
commit
d4030ddc2a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      .editorconfig
  2. 1
      .github/FUNDING.yml
  3. 2
      .github/PULL_REQUEST_TEMPLATE.md
  4. 4
      .gitignore
  5. 3
      .gitmodules
  6. 0
      .nuke
  7. 148
      .nuke/build.schema.json
  8. 4
      .nuke/parameters.json
  9. 65
      Avalonia.sln
  10. 4
      NOTICE.md
  11. 20
      azure-pipelines-integrationtests.yml
  12. 44
      azure-pipelines.yml
  13. 7
      build.cmd
  14. 50
      build.ps1
  15. 60
      build.sh
  16. 6
      build/HarfBuzzSharp.props
  17. 5
      build/NetAnalyzers.props
  18. 2
      build/ReactiveUI.props
  19. 2
      build/SharedVersion.props
  20. 6
      build/SkiaSharp.props
  21. 12
      dirs.proj
  22. 2
      global.json
  23. 4
      native/Avalonia.Native/src/OSX/Screens.mm
  24. 4
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  25. 110
      nukebuild/Build.cs
  26. 8
      nukebuild/BuildParameters.cs
  27. 12
      nukebuild/BuildTasksPatcher.cs
  28. 57
      nukebuild/DotNetConfigHelper.cs
  29. 14
      nukebuild/MicroComGen.cs
  30. 15
      nukebuild/Shims.cs
  31. 41
      nukebuild/_build.csproj
  32. 1
      nukebuild/il-repack
  33. 3
      packages/Avalonia/AvaloniaBuildTasks.targets
  34. 12
      samples/ControlCatalog.Android/MainActivity.cs
  35. 13
      samples/ControlCatalog.Android/SplashActivity.cs
  36. 0
      samples/ControlCatalog.Blazor.Web/App.razor
  37. 17
      samples/ControlCatalog.Blazor.Web/App.razor.cs
  38. 29
      samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj
  39. 0
      samples/ControlCatalog.Blazor.Web/Pages/Index.razor
  40. 29
      samples/ControlCatalog.Blazor.Web/Program.cs
  41. 0
      samples/ControlCatalog.Blazor.Web/Properties/launchSettings.json
  42. 0
      samples/ControlCatalog.Blazor.Web/Shared/MainLayout.razor
  43. 3
      samples/ControlCatalog.Blazor.Web/_Imports.razor
  44. 0
      samples/ControlCatalog.Blazor.Web/wwwroot/css/app.css
  45. 0
      samples/ControlCatalog.Blazor.Web/wwwroot/favicon.ico
  46. 1
      samples/ControlCatalog.Blazor.Web/wwwroot/index.html
  47. 1
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  48. 4
      samples/ControlCatalog.NetCore/Program.cs
  49. 19
      samples/ControlCatalog.Web/App.razor.cs
  50. 69
      samples/ControlCatalog.Web/ControlCatalog.Web.csproj
  51. 32
      samples/ControlCatalog.Web/EmbedSample.Browser.cs
  52. 5
      samples/ControlCatalog.Web/Logo.svg
  53. 37
      samples/ControlCatalog.Web/Program.cs
  54. 7
      samples/ControlCatalog.Web/Roots.xml
  55. 49
      samples/ControlCatalog.Web/app.css
  56. 5
      samples/ControlCatalog.Web/embed.js
  57. BIN
      samples/ControlCatalog.Web/favicon.ico
  58. 31
      samples/ControlCatalog.Web/index.html
  59. 19
      samples/ControlCatalog.Web/main.js
  60. 11
      samples/ControlCatalog.Web/runtimeconfig.template.json
  61. 3
      samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
  62. 34
      samples/ControlCatalog/Converter/HexConverter.cs
  63. 2
      samples/ControlCatalog/DecoratedWindow.xaml
  64. 3
      samples/ControlCatalog/MainView.xaml
  65. 11
      samples/ControlCatalog/MainView.xaml.cs
  66. 6
      samples/ControlCatalog/MainWindow.xaml
  67. 8
      samples/ControlCatalog/Models/Person.cs
  68. 66
      samples/ControlCatalog/Pages/AdornerLayerPage.xaml
  69. 48
      samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs
  70. 2
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  71. 24
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  72. 25
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
  73. 2
      samples/ControlCatalog/Pages/ButtonsPage.xaml.cs
  74. 2
      samples/ControlCatalog/Pages/CarouselPage.xaml.cs
  75. 70
      samples/ControlCatalog/Pages/ClipboardPage.xaml.cs
  76. 20
      samples/ControlCatalog/Pages/ColorPickerPage.xaml
  77. 16
      samples/ControlCatalog/Pages/ColorPickerPage.xaml.cs
  78. 2
      samples/ControlCatalog/Pages/ComboBoxPage.xaml.cs
  79. 20
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  80. 22
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs
  81. 23
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  82. 4
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  83. 24
      samples/ControlCatalog/Pages/DateTimePickerPage.xaml
  84. 13
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  85. 20
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  86. 2
      samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs
  87. 10
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  88. 16
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  89. 6
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs
  90. 6
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  91. 4
      samples/ControlCatalog/Pages/PointerCanvas.cs
  92. 33
      samples/ControlCatalog/Pages/PointersPage.xaml.cs
  93. 16
      samples/ControlCatalog/Pages/ScreenPage.cs
  94. 8
      samples/ControlCatalog/ViewModels/ContextPageViewModel.cs
  95. 7
      samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
  96. 6
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  97. 27
      samples/IntegrationTestApp/MacOSIntegration.cs
  98. 50
      samples/IntegrationTestApp/MainWindow.axaml.cs
  99. 7
      samples/IntegrationTestApp/ShowWindowTest.axaml
  100. 28
      samples/IntegrationTestApp/ShowWindowTest.axaml.cs

17
.editorconfig

@ -134,9 +134,26 @@ csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
space_within_single_line_array_initializer_braces = true
#Net Analyzer
dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed.
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
# CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers
dotnet_diagnostic.CA1821.severity = warning
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning
# Wrapping preferences
csharp_wrap_before_ternary_opsigns = false
# Avalonia DevAnalyzer preferences
dotnet_diagnostic.AVADEV2001.severity = error
# Xaml files
[*.{xaml,axaml}]
indent_size = 2

1
.github/FUNDING.yml

@ -1 +1,2 @@
github: avaloniaui
open_collective: avalonia

2
.github/PULL_REQUEST_TEMPLATE.md

@ -21,7 +21,7 @@
- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Documentation with user documentation
## Breaking changes
<!--- List any breaking changes here. When the PR is merged please add an entry to https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes -->
<!--- List any breaking changes here. -->
## Obsoletions / Deprecations
<!--- Obsolete and Deprecated attributes on APIs MUST only be included when discussed with Core team. @grokys, @kekekeks & @danwalmsley -->

4
.gitignore

@ -212,3 +212,7 @@ coc-settings.json
*.map
src/Web/Avalonia.Web.Blazor/wwwroot/*.js
src/Web/Avalonia.Web.Blazor/Interop/Typescript/*.js
node_modules
src/Web/Avalonia.Web.Blazor/webapp/package-lock.json
src/Web/Avalonia.Web.Blazor/wwwroot
src/Web/Avalonia.Web/wwwroot

3
.gitmodules

@ -4,3 +4,6 @@
[submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"]
path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
url = https://github.com/kekekeks/XamlX.git
[submodule "nukebuild/il-repack"]
path = nukebuild/il-repack
url = https://github.com/Gillibald/il-repack

0
.nuke

148
.nuke/build.schema.json

@ -0,0 +1,148 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Build Schema",
"$ref": "#/definitions/build",
"definitions": {
"build": {
"type": "object",
"properties": {
"Configuration": {
"type": "string",
"description": "configuration"
},
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
},
"ForceNugetVersion": {
"type": "string",
"description": "force-nuget-version"
},
"Help": {
"type": "boolean",
"description": "Shows the help text for this build assembly"
},
"Host": {
"type": "string",
"description": "Host for execution. Default is 'automatic'",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
},
"NoLogo": {
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
"Partition": {
"type": "string",
"description": "Partition to use on CI"
},
"Plan": {
"type": "boolean",
"description": "Shows the execution plan (HTML)"
},
"Profile": {
"type": "array",
"description": "Defines the profiles to load",
"items": {
"type": "string"
}
},
"Root": {
"type": "string",
"description": "Root directory during build execution"
},
"Skip": {
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
"type": "string",
"enum": [
"CiAzureLinux",
"CiAzureOSX",
"CiAzureWindows",
"Clean",
"Compile",
"CompileHtmlPreviewer",
"CompileNative",
"CreateIntermediateNugetPackages",
"CreateNugetPackages",
"GenerateCppHeaders",
"Package",
"RunCoreLibsTests",
"RunDesignerTests",
"RunHtmlPreviewerTests",
"RunLeakTests",
"RunRenderTests",
"RunTests",
"ZipFiles"
]
}
},
"SkipPreviewer": {
"type": "boolean",
"description": "skip-previewer"
},
"SkipTests": {
"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}'",
"items": {
"type": "string",
"enum": [
"CiAzureLinux",
"CiAzureOSX",
"CiAzureWindows",
"Clean",
"Compile",
"CompileHtmlPreviewer",
"CompileNative",
"CreateIntermediateNugetPackages",
"CreateNugetPackages",
"GenerateCppHeaders",
"Package",
"RunCoreLibsTests",
"RunDesignerTests",
"RunHtmlPreviewerTests",
"RunLeakTests",
"RunRenderTests",
"RunTests",
"ZipFiles"
]
}
},
"Verbosity": {
"type": "string",
"description": "Logging verbosity during build execution. Default is 'Normal'",
"enum": [
"Minimal",
"Normal",
"Quiet",
"Verbose"
]
}
}
}
}
}

4
.nuke/parameters.json

@ -0,0 +1,4 @@
{
"$schema": "./build.schema.json",
"Solution": ""
}

65
Avalonia.sln

@ -90,6 +90,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject
build\ApiDiff.props = build\ApiDiff.props
build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props
build\Base.props = build\Base.props
build\Binding.props = build\Binding.props
build\CoreLibraries.props = build\CoreLibraries.props
@ -102,8 +103,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\Microsoft.CSharp.props = build\Microsoft.CSharp.props
build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
build\Moq.props = build\Moq.props
build\NetAnalyzers.props = build\NetAnalyzers.props
build\NetCore.props = build\NetCore.props
build\NetFX.props = build\NetFX.props
build\NullableEnable.props = build\NullableEnable.props
build\ReactiveUI.props = build\ReactiveUI.props
build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
build\Rx.props = build\Rx.props
@ -198,8 +201,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{86A3F706-DC3
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web.Blazor", "src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj", "{25831348-EB2A-483E-9576-E8F6528674A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{C08E9894-AA92-426E-BF56-033E262CAD3E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}"
@ -212,7 +213,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ColorPick
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{EABE2161-989B-42BF-BD8D-1E34B20C21F1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevGenerators", "src\tools\DevGenerators\DevGenerators.csproj", "{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevGenerators", "src\tools\DevGenerators\DevGenerators.csproj", "{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web", "src\Web\Avalonia.Web\Avalonia.Web.csproj", "{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox", "samples\MobileSandbox\MobileSandbox.csproj", "{3B8519C1-2F51-4F12-A348-120AB91D4532}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Android", "samples\MobileSandbox.Android\MobileSandbox.Android.csproj", "{C90FE60B-B01E-4F35-91D6-379D6966030F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.iOS", "samples\MobileSandbox.iOS\MobileSandbox.iOS.csproj", "{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Blazor.Web", "samples\ControlCatalog.Blazor.Web\ControlCatalog.Blazor.Web.csproj", "{6A710364-AE6D-40BD-968B-024311527AC2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{8B3E8405-DE18-4048-A459-9CA4AC3319A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -399,9 +414,7 @@ Global
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.Build.0 = Release|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -470,10 +483,6 @@ Global
{25831348-EB2A-483E-9576-E8F6528674A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.Build.0 = Release|Any CPU
{C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|Any CPU.Build.0 = Release|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -502,6 +511,34 @@ Global
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.Build.0 = Release|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Release|Any CPU.Build.0 = Release|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Release|Any CPU.Build.0 = Release|Any CPU
{C90FE60B-B01E-4F35-91D6-379D6966030F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C90FE60B-B01E-4F35-91D6-379D6966030F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C90FE60B-B01E-4F35-91D6-379D6966030F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C90FE60B-B01E-4F35-91D6-379D6966030F}.Release|Any CPU.Build.0 = Release|Any CPU
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}.Release|Any CPU.Build.0 = Release|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Release|Any CPU.Build.0 = Release|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A710364-AE6D-40BD-968B-024311527AC2}.Release|Any CPU.Build.0 = Release|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -545,6 +582,7 @@ Global
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{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}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
@ -552,14 +590,19 @@ Global
{676D6BFD-029D-4E43-BFC7-3892265CE251} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{25831348-EB2A-483E-9576-E8F6528674A5} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{C08E9894-AA92-426E-BF56-033E262CAD3E} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{EABE2161-989B-42BF-BD8D-1E34B20C21F1} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{76D39FF6-6B4F-46C4-93CD-E6FC4665739E} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{3B8519C1-2F51-4F12-A348-120AB91D4532} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C90FE60B-B01E-4F35-91D6-379D6966030F} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{62D392C9-81CF-487F-92E8-598B2AF3FDCE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{6A710364-AE6D-40BD-968B-024311527AC2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{8B3E8405-DE18-4048-A459-9CA4AC3319A2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

4
NOTICE.md

@ -111,7 +111,7 @@ DEALINGS IN THE SOFTWARE.
# Metsys.Bson
Copyright (c) 2010, Karl Seguin - http://www.openmymind.net/
Copyright (c) 2010, Karl Seguin - https://www.openmymind.net/
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -302,4 +302,4 @@ https://github.com/chromium/chromium
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

20
azure-pipelines-integrationtests.yml

@ -12,6 +12,16 @@ jobs:
name: 'AvaloniaMacPool'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.401'
inputs:
version: 6.0.401
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs:
version: 7.0.100-rc.2.22477.23
- script: system_profiler SPDisplaysDataType |grep Resolution
- script: |
@ -41,9 +51,14 @@ jobs:
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.202'
displayName: 'Use .NET Core SDK 6.0.401'
inputs:
version: 6.0.401
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs:
version: 6.0.202
version: 7.0.100-rc.2.22477.23
- task: Windows Application Driver@0
inputs:
@ -57,6 +72,7 @@ jobs:
projects: 'samples/IntegrationTestApp/IntegrationTestApp.csproj'
- task: DotNetCoreCLI@2
retryCountOnTaskFailure: 3
inputs:
command: 'test'
projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj'

44
azure-pipelines.yml

@ -6,7 +6,6 @@ jobs:
variables:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: PowerShell@2
displayName: Get PR Number
inputs:
@ -31,14 +30,20 @@ jobs:
vmImage: 'ubuntu-20.04'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418'
displayName: 'Use .NET Core SDK 6.0.401'
inputs:
version: 3.1.418
version: 6.0.401
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.202'
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs:
version: 7.0.100-rc.2.22477.23
- task: CmdLine@2
displayName: 'Install Workloads'
inputs:
version: 6.0.202
script: |
dotnet workload install wasm-tools wasm-experimental
- task: CmdLine@2
displayName: 'Run Build'
@ -62,22 +67,21 @@ jobs:
vmImage: 'macos-12'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418'
displayName: 'Use .NET Core SDK 6.0.401'
inputs:
version: 3.1.418
version: 6.0.401
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.202'
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs:
version: 6.0.202
version: 7.0.100-rc.2.22477.23
- task: CmdLine@2
displayName: 'Install Mono 5.18'
displayName: 'Install Workloads'
inputs:
script: |
curl -o ./mono.pkg https://download.mono-project.com/archive/5.18.0/macos-10-universal/MonoFramework-MDK-5.18.0.225.macos10.xamarin.universal.pkg
sudo installer -verbose -pkg ./mono.pkg -target /
dotnet workload install wasm-tools wasm-experimental
- task: CmdLine@2
displayName: 'Generate avalonia-native'
inputs:
@ -134,26 +138,26 @@ jobs:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418'
displayName: 'Use .NET Core SDK 6.0.401'
inputs:
version: 3.1.418
version: 6.0.401
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.202'
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs:
version: 6.0.202
version: 7.0.100-rc.2.22477.23
- task: CmdLine@2
displayName: 'Install Workloads'
inputs:
script: |
dotnet workload install android ios
dotnet workload install android ios wasm-tools wasm-experimental
- task: CmdLine@2
displayName: 'Install Nuke'
inputs:
script: |
dotnet tool install --global Nuke.GlobalTool --version 0.24.0
dotnet tool install --global Nuke.GlobalTool --version 6.2.1
- task: CmdLine@2
displayName: 'Run Nuke'

7
build.cmd

@ -0,0 +1,7 @@
:; set -eo pipefail
:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
:; ${SCRIPT_DIR}/build.sh "$@"
:; exit $?
@ECHO OFF
powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*

50
build.ps1

@ -1,13 +1,12 @@
[CmdletBinding()]
Param(
#[switch]$CustomParam,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$BuildArguments
)
Write-Output "Windows PowerShell $($Host.Version)"
Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 }
Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################
@ -15,15 +14,15 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################
$BuildProjectFile = "$PSScriptRoot\nukebuild\_build.csproj"
$TempDirectory = "$PSScriptRoot\\.tmp"
$TempDirectory = "$PSScriptRoot\\.nuke\temp"
$DotNetGlobalFile = "$PSScriptRoot\\global.json"
$DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "Current"
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
$env:NUGET_XMLDOC_MODE = "skip"
$env:DOTNET_MULTILEVEL_LOOKUP = 0
###########################################################################
# EXECUTION
@ -34,38 +33,37 @@ function ExecSafe([scriptblock] $cmd) {
if ($LASTEXITCODE) { exit $LASTEXITCODE }
}
# If global.json exists, load expected version
if (Test-Path $DotNetGlobalFile) {
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
$DotNetVersion = $DotNetGlobal.sdk.version
}
}
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
# If dotnet CLI is installed globally and it matches requested version, use for execution
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
(!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) {
$(dotnet --version) -and $LASTEXITCODE -eq 0) {
$env:DOTNET_EXE = (Get-Command "dotnet").Path
}
else {
$DotNetDirectory = "$TempDirectory\dotnet-win"
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
# Download install script
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
mkdir -force $TempDirectory > $null
New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
# If global.json exists, load expected version
if (Test-Path $DotNetGlobalFile) {
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
$DotNetVersion = $DotNetGlobal.sdk.version
}
}
# Install by channel or version
$DotNetDirectory = "$TempDirectory\dotnet-win"
if (!(Test-Path variable:DotNetVersion)) {
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
} else {
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
}
$env:PATH="$DotNetDirectory;$env:PATH"
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
}
Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile -- $BuildArguments }
ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }

60
build.sh

@ -1,16 +1,6 @@
#!/usr/bin/env bash
echo $(bash --version 2>&1 | head -n 1)
#CUSTOMPARAM=0
BUILD_ARGUMENTS=()
for i in "$@"; do
case $(echo $1 | awk '{print tolower($0)}') in
# -custom-param) CUSTOMPARAM=1;;
*) BUILD_ARGUMENTS+=("$1") ;;
esac
shift
done
bash --version 2>&1 | head -n 1
set -eo pipefail
SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
@ -20,11 +10,53 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
###########################################################################
BUILD_PROJECT_FILE="$SCRIPT_DIR/nukebuild/_build.csproj"
TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
DOTNET_CHANNEL="Current"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export NUGET_XMLDOC_MODE="skip"
export DOTNET_MULTILEVEL_LOOKUP=0
dotnet --info
###########################################################################
# EXECUTION
###########################################################################
dotnet run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]}
function FirstJsonValue {
perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
}
# If dotnet CLI is installed globally and it matches requested version, use for execution
if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
export DOTNET_EXE="$(command -v dotnet)"
else
# Download install script
DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
mkdir -p "$TEMP_DIRECTORY"
curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
chmod +x "$DOTNET_INSTALL_FILE"
# If global.json exists, load expected version
if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
if [[ "$DOTNET_VERSION" == "" ]]; then
unset DOTNET_VERSION
fi
fi
# Install by channel or version
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
if [[ -z ${DOTNET_VERSION+x} ]]; then
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
else
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
fi
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
fi
echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"

6
build/HarfBuzzSharp.props

@ -1,7 +1,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="HarfBuzzSharp" Version="2.8.2" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2" />
<PackageReference Include="HarfBuzzSharp" Version="2.8.2.1-preview.108" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2.1-preview.108" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2.1-preview.108" />
</ItemGroup>
</Project>

5
build/NetAnalyzers.props

@ -0,0 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
</Project>

2
build/ReactiveUI.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="ReactiveUI" Version="13.2.10" />
<PackageReference Include="ReactiveUI" Version="18.3.1" />
</ItemGroup>
</Project>

2
build/SharedVersion.props

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Product>Avalonia</Product>
<Version>0.10.999</Version>
<Version>11.0.999</Version>
<Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>

6
build/SkiaSharp.props

@ -1,7 +1,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1-preview.1" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.1-preview.1" />
<PackageReference Include="SkiaSharp" Version="2.88.1" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.1" />
</ItemGroup>
</Project>

12
dirs.proj

@ -9,17 +9,17 @@
<ProjectReference Remove="**/*.shproj" />
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/**/*.*proj" />
<ProjectReference Remove="tests/Avalonia.ReactiveUI.Events.UnitTests/Avalonia.ReactiveUI.Events.UnitTests.csproj" />
<ProjectReference Remove="samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj" />
<ProjectReference Remove="samples/ControlCatalog.iOS.Legacy/ControlCatalog.iOS.Legacy.csproj" />
<ProjectReference Remove="samples/ControlCatalog.Android/ControlCatalog.Android.csproj" />
<ProjectReference Remove="src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj" />
<!-- Exclude iOS, Android and Web samples from build -->
<ProjectReference Remove="samples/*.iOS/*.csproj" />
<ProjectReference Remove="samples/*.Android/*.csproj" />
<ProjectReference Remove="samples/*.Web/*.csproj" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />
<ProjectReference Remove="samples/interop/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<!-- Build android and iOS projects only on Windows, where we have installed android workload -->
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows'))">
<ProjectReference Remove="src/Android/**/*.*proj" />
@ -27,6 +27,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SlnGen" Version="2.0.40" PrivateAssets="all" />
<PackageReference Include="Microsoft.VisualStudio.SlnGen" Version="8.5.17" PrivateAssets="all" />
</ItemGroup>
</Project>

2
global.json

@ -1,6 +1,6 @@
{
"sdk": {
"version": "6.0.202",
"version": "7.0.100-rc.2.22477.23",
"rollForward": "latestFeature"
},
"msbuild-sdks": {

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

@ -41,9 +41,9 @@ public:
ret->WorkingArea.X = [screen visibleFrame].origin.x;
ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height;
ret->PixelDensity = [screen backingScaleFactor];
ret->Scaling = [screen backingScaleFactor];
ret->Primary = index == 0;
ret->IsPrimary = index == 0;
return S_OK;
}

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

@ -91,8 +91,6 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
if(_parent != nullptr)
{
_parent->_children.remove(this);
_parent->BringToFront();
}
auto cparent = dynamic_cast<WindowImpl *>(parent);
@ -121,7 +119,7 @@ void WindowImpl::BringToFront()
{
if(Window != nullptr)
{
if (![Window isMiniaturized])
if ([Window isVisible] && ![Window isMiniaturized])
{
if(IsDialog())
{

110
nukebuild/Build.cs

@ -23,6 +23,7 @@ using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
using static Nuke.Common.Tools.Xunit.XunitTasks;
using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
using MicroCom.CodeGenerator;
/*
Before editing this file, install support plugin for your IDE,
@ -36,25 +37,6 @@ partial class Build : NukeBuild
{
[Solution("Avalonia.sln")] readonly Solution Solution;
static Lazy<string> MsBuildExe = new Lazy<string>(() =>
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return null;
var msBuildDirectory = VSWhere("-latest -nologo -property installationPath -format value -prerelease").FirstOrDefault().Text;
if (!string.IsNullOrWhiteSpace(msBuildDirectory))
{
string msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\Current\Bin\MSBuild.exe");
if (!System.IO.File.Exists(msBuildExe))
msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\15.0\Bin\MSBuild.exe");
return msBuildExe;
}
return null;
}, false);
BuildParameters Parameters { get; set; }
protected override void OnBuildInitialized()
{
@ -89,25 +71,28 @@ partial class Build : NukeBuild
}
ExecWait("dotnet version:", "dotnet", "--info");
ExecWait("dotnet workloads:", "dotnet", "workload list");
Information("Processor count: " + Environment.ProcessorCount);
Information("Available RAM: " + GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 0x100000 + "MB");
}
IReadOnlyCollection<Output> MsBuildCommon(
string projectFile,
Configure<MSBuildSettings> configurator = null)
DotNetConfigHelper ApplySettingCore(DotNetConfigHelper c)
{
return MSBuild(c => c
.SetProjectFile(projectFile)
// This is required for VS2019 image on Azure Pipelines
.When(Parameters.IsRunningOnWindows &&
Parameters.IsRunningOnAzure, _ => _
.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64")))
.AddProperty("PackageVersion", Parameters.Version)
if (Parameters.IsRunningOnAzure)
c.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64"));
c.AddProperty("PackageVersion", Parameters.Version)
.AddProperty("iOSRoslynPathHackRequired", true)
.SetProcessToolPath(MsBuildExe.Value)
.SetConfiguration(Parameters.Configuration)
.SetVerbosity(MSBuildVerbosity.Minimal)
.Apply(configurator));
.SetVerbosity(DotNetVerbosity.Minimal);
return c;
}
DotNetBuildSettings ApplySetting(DotNetBuildSettings c, Configure<DotNetBuildSettings> configurator = null) =>
ApplySettingCore(c).Build.Apply(configurator);
DotNetPackSettings ApplySetting(DotNetPackSettings c, Configure<DotNetPackSettings> configurator = null) =>
ApplySettingCore(c).Pack.Apply(configurator);
DotNetTestSettings ApplySetting(DotNetTestSettings c, Configure<DotNetTestSettings> configurator = null) =>
ApplySettingCore(c).Test.Apply(configurator);
Target Clean => _ => _.Executes(() =>
{
@ -149,20 +134,11 @@ partial class Build : NukeBuild
Target Compile => _ => _
.DependsOn(Clean, CompileNative)
.DependsOn(CompileHtmlPreviewer)
.Executes(async () =>
.Executes(() =>
{
if (Parameters.IsRunningOnWindows)
MsBuildCommon(Parameters.MSBuildSolution, c => c
.SetProcessArgumentConfigurator(a => a.Add("/r"))
.AddTargets("Build")
);
else
DotNetBuild(c => c
.SetProjectFile(Parameters.MSBuildSolution)
.AddProperty("PackageVersion", Parameters.Version)
.SetConfiguration(Parameters.Configuration)
);
DotNetBuild(c => ApplySetting(c)
.SetProjectFile(Parameters.MSBuildSolution)
);
});
void RunCoreTest(string projectName)
@ -182,14 +158,13 @@ partial class Build : NukeBuild
Information($"Running for {projectName} ({fw}) ...");
DotNetTest(c => c
DotNetTest(c => ApplySetting(c)
.SetProjectFile(project)
.SetConfiguration(Parameters.Configuration)
.SetFramework(fw)
.EnableNoBuild()
.EnableNoRestore()
.When(Parameters.PublishTestResults, _ => _
.SetLogger("trx")
.SetLoggers("trx")
.SetResultsDirectory(Parameters.TestResultsRoot)));
}
}
@ -241,8 +216,6 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.DesignerSupport.Tests");
});
[PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
Target RunLeakTests => _ => _
.OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile)
@ -250,12 +223,9 @@ partial class Build : NukeBuild
{
void DoMemoryTest()
{
var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll";
DotMemoryUnit(
$"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}",
timeout: 120_000);
RunCoreTest("Avalonia.LeakTests");
}
ControlFlow.ExecuteWithRetry(DoMemoryTest, waitInSeconds: 3);
ControlFlow.ExecuteWithRetry(DoMemoryTest, delay: TimeSpan.FromMilliseconds(3));
});
Target ZipFiles => _ => _
@ -263,19 +233,7 @@ partial class Build : NukeBuild
.Executes(() =>
{
var data = Parameters;
var pathToProjectSource = RootDirectory / "samples" / "ControlCatalog.NetCore";
var pathToPublish = pathToProjectSource / "bin" / data.Configuration / "publish";
DotNetPublish(c => c
.SetProject(pathToProjectSource / "ControlCatalog.NetCore.csproj")
.EnableNoBuild()
.SetConfiguration(data.Configuration)
.AddProperty("PackageVersion", data.Version)
.AddProperty("PublishDir", pathToPublish));
Zip(data.ZipCoreArtifacts, data.BinRoot);
Zip(data.ZipNuGetArtifacts, data.NugetRoot);
Zip(data.ZipTargetControlCatalogNetCoreDir, pathToPublish);
});
Target CreateIntermediateNugetPackages => _ => _
@ -283,15 +241,7 @@ partial class Build : NukeBuild
.After(RunTests)
.Executes(() =>
{
if (Parameters.IsRunningOnWindows)
MsBuildCommon(Parameters.MSBuildSolution, c => c
.AddTargets("Pack"));
else
DotNetPack(c => c
.SetProject(Parameters.MSBuildSolution)
.SetConfiguration(Parameters.Configuration)
.AddProperty("PackageVersion", Parameters.Version));
DotNetPack(c => ApplySetting(c).SetProject(Parameters.MSBuildSolution));
});
Target CreateNugetPackages => _ => _
@ -329,6 +279,14 @@ partial class Build : NukeBuild
.DependsOn(Package)
.DependsOn(ZipFiles);
Target GenerateCppHeaders => _ => _.Executes(() =>
{
var file = MicroComCodeGenerator.Parse(
File.ReadAllText(RootDirectory / "src" / "Avalonia.Native" / "avn.idl"));
File.WriteAllText(RootDirectory / "native" / "Avalonia.Native" / "inc" / "avalonia-native.h",
file.GenerateCppHeader());
});
public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)

8
nukebuild/BuildParameters.cs

@ -51,14 +51,12 @@ public partial class Build
public AbsolutePath NugetIntermediateRoot { get; }
public AbsolutePath NugetRoot { get; }
public AbsolutePath ZipRoot { get; }
public AbsolutePath BinRoot { get; }
public AbsolutePath TestResultsRoot { get; }
public string DirSuffix { get; }
public List<string> BuildDirs { get; }
public string FileZipSuffix { get; }
public AbsolutePath ZipCoreArtifacts { get; }
public AbsolutePath ZipNuGetArtifacts { get; }
public AbsolutePath ZipTargetControlCatalogNetCoreDir { get; }
public BuildParameters(Build b)
@ -76,11 +74,11 @@ public partial class Build
MSBuildSolution = RootDirectory / "dirs.proj";
// PARAMETERS
IsLocalBuild = Host == HostType.Console;
IsLocalBuild = NukeBuild.IsLocalBuild;
IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix ||
Environment.OSVersion.Platform == PlatformID.MacOSX;
IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
IsRunningOnAzure = Host == HostType.AzurePipelines ||
IsRunningOnAzure = Host is AzurePipelines ||
Environment.GetEnvironmentVariable("LOGNAME") == "vsts";
if (IsRunningOnAzure)
@ -121,14 +119,12 @@ public partial class Build
NugetRoot = ArtifactsDir / "nuget";
NugetIntermediateRoot = RootDirectory / "build-intermediate" / "nuget";
ZipRoot = ArtifactsDir / "zip";
BinRoot = ArtifactsDir / "bin";
TestResultsRoot = ArtifactsDir / "test-results";
BuildDirs = GlobDirectories(RootDirectory, "**bin").Concat(GlobDirectories(RootDirectory, "**obj")).ToList();
DirSuffix = Configuration;
FileZipSuffix = Version + ".zip";
ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix);
ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix);
ZipTargetControlCatalogNetCoreDir = ZipRoot / ("ControlCatalog.NetCore-" + FileZipSuffix);
}
string GetVersion()

12
nukebuild/BuildTasksPatcher.cs

@ -17,8 +17,12 @@ public class BuildTasksPatcher
{
if (entry.Name == "Avalonia.Build.Tasks.dll")
{
var temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".dll");
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);
var temp = Path.Combine(tempDir, Guid.NewGuid() + ".dll");
var output = temp + ".output";
File.Copy(typeof(Microsoft.Build.Framework.ITask).Assembly.GetModules()[0].FullyQualifiedName,
Path.Combine(tempDir, "Microsoft.Build.Framework.dll"));
var patched = new MemoryStream();
try
{
@ -57,10 +61,8 @@ public class BuildTasksPatcher
{
try
{
if (File.Exists(temp))
File.Delete(temp);
if (File.Exists(output))
File.Delete(output);
if(Directory.Exists(tempDir))
Directory.Delete(tempDir, true);
}
catch
{

57
nukebuild/DotNetConfigHelper.cs

@ -0,0 +1,57 @@
using System.Globalization;
using JetBrains.Annotations;
using Nuke.Common.Tools.DotNet;
// ReSharper disable ReturnValueOfPureMethodIsNotUsed
public class DotNetConfigHelper
{
public DotNetBuildSettings Build;
public DotNetPackSettings Pack;
public DotNetTestSettings Test;
public DotNetConfigHelper(DotNetBuildSettings s)
{
Build = s;
}
public DotNetConfigHelper(DotNetPackSettings s)
{
Pack = s;
}
public DotNetConfigHelper(DotNetTestSettings s)
{
Test = s;
}
public DotNetConfigHelper AddProperty(string key, bool value) =>
AddProperty(key, value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
public DotNetConfigHelper AddProperty(string key, string value)
{
Build = Build?.AddProperty(key, value);
Pack = Pack?.AddProperty(key, value);
Test = Test?.AddProperty(key, value);
return this;
}
public DotNetConfigHelper SetConfiguration(string configuration)
{
Build = Build?.SetConfiguration(configuration);
Pack = Pack?.SetConfiguration(configuration);
Test = Test?.SetConfiguration(configuration);
return this;
}
public DotNetConfigHelper SetVerbosity(DotNetVerbosity verbosity)
{
Build = Build?.SetVerbosity(verbosity);
Pack = Pack?.SetVerbosity(verbosity);
Test = Test?.SetVerbosity(verbosity);
return this;
}
public static implicit operator DotNetConfigHelper(DotNetBuildSettings s) => new DotNetConfigHelper(s);
public static implicit operator DotNetConfigHelper(DotNetPackSettings s) => new DotNetConfigHelper(s);
public static implicit operator DotNetConfigHelper(DotNetTestSettings s) => new DotNetConfigHelper(s);
}

14
nukebuild/MicroComGen.cs

@ -1,14 +0,0 @@
using System.IO;
using MicroCom.CodeGenerator;
using Nuke.Common;
partial class Build : NukeBuild
{
Target GenerateCppHeaders => _ => _.Executes(() =>
{
var file = MicroComCodeGenerator.Parse(
File.ReadAllText(RootDirectory / "src" / "Avalonia.Native" / "avn.idl"));
File.WriteAllText(RootDirectory / "native" / "Avalonia.Native" / "inc" / "avalonia-native.h",
file.GenerateCppHeader());
});
}

15
nukebuild/Shims.cs

@ -49,7 +49,11 @@ public partial class Build
{
if (fsEntry is FileInfo)
{
#if NET6
var relPath = Path.GetRelativePath(rootPath, fsEntry.FullName);
#else
var relPath = GetRelativePath(rootPath, fsEntry.FullName);
#endif
AddFile(fsEntry.FullName, relPath);
}
}
@ -78,6 +82,17 @@ public partial class Build
}
}
private static string GetRelativePath(string relativeTo, string path)
{
var uri = new Uri(relativeTo);
var rel = Uri.UnescapeDataString(uri.MakeRelativeUri(new Uri(path)).ToString()).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
if (rel.Contains(Path.DirectorySeparatorChar.ToString()) == false)
{
rel = $".{Path.DirectorySeparatorChar}{rel}";
}
return rel;
}
class NumergeNukeLogger : INumergeLogger
{
public void Log(NumergeLogLevel level, string message)

41
nukebuild/_build.csproj

@ -1,41 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace></RootNamespace>
<IsPackable>False</IsPackable>
<NoWarn>CS0649;CS0169</NoWarn>
<NoWarn>CS0649;CS0169;SYSLIB0011</NoWarn>
<NukeTelemetryVersion>1</NukeTelemetryVersion>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<Import Project="..\build\JetBrains.dotMemoryUnit.props" />
<ItemGroup>
<PackageReference Include="Nuke.Common" Version="5.0.0" />
<PackageReference Include="xunit.runner.console" Version="2.3.1" />
<PackageReference Include="Nuke.Common" Version="6.2.1" />
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
<PackageReference Include="ILRepack.NETStandard" Version="2.0.4" />
<PackageReference Include="MicroCom.CodeGenerator" Version="0.10.4" />
<!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.1" PrivateAssets="All" />
<PackageReference Include="xunit.runner.console" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" />
<NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
<None Remove="*.csproj.DotSettings;*.ref.*.txt" />
<!-- Common build related files -->
<None Include="..\build.ps1" />
<None Include="..\build.sh" />
<None Include="..\.nuke" />
<None Include="..\global.json" Condition="Exists('..\global.json')" />
<None Include="..\nuget.config" Condition="Exists('..\nuget.config')" />
<None Include="..\Jenkinsfile" Condition="Exists('..\Jenkinsfile')" />
<None Include="..\appveyor.yml" Condition="Exists('..\appveyor.yml')" />
<None Include="..\.travis.yml" Condition="Exists('..\.travis.yml')" />
<None Include="..\GitVersion.yml" Condition="Exists('..\GitVersion.yml')" />
<Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Numerge\Numerge.Console\" />
</ItemGroup>
</Project>

1
nukebuild/il-repack

@ -0,0 +1 @@
Subproject commit 892f079ea8cb0c178f0a68f53a7a7eac13acdda9

3
packages/Avalonia/AvaloniaBuildTasks.targets

@ -3,7 +3,6 @@
<_AvaloniaUseExternalMSBuild>$(AvaloniaUseExternalMSBuild)</_AvaloniaUseExternalMSBuild>
<_AvaloniaUseExternalMSBuild Condition="'$(_AvaloniaForceInternalMSBuild)' == 'true'">false</_AvaloniaUseExternalMSBuild>
<AvaloniaXamlReportImportance Condition="'$(AvaloniaXamlReportImportance)' == ''">low</AvaloniaXamlReportImportance>
<_AvaloniaPatchComInterop Condition="'$(_AvaloniaPatchComInterop)' == ''">false</_AvaloniaPatchComInterop>
<_AvaloniaSkipXamlCompilation Condition="'$(_AvaloniaSkipXamlCompilation)' == ''">false</_AvaloniaSkipXamlCompilation>
</PropertyGroup>
@ -71,7 +70,6 @@
Output="$(AvaloniaResourcesTemporaryFilePath)"
Root="$(MSBuildProjectDirectory)"
Resources="@(AvaloniaResource)"
EmbeddedResources="@(EmbeddedResources)"
ReportImportance="$(AvaloniaXamlReportImportance)"/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
@ -106,7 +104,6 @@
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
SignAssembly="$(SignAssembly)"
DelaySign="$(DelaySign)"
EnableComInteropPatching="$(_AvaloniaPatchComInterop)"
SkipXamlCompilation="$(_AvaloniaSkipXamlCompilation)"
DebuggerLaunch="$(AvaloniaXamlIlDebuggerLaunch)"
/>

12
samples/ControlCatalog.Android/MainActivity.cs

@ -5,16 +5,8 @@ using Avalonia.Android;
namespace ControlCatalog.Android
{
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
public class MainActivity : AvaloniaActivity<App>
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
public class MainActivity : AvaloniaMainActivity
{
protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
{
return base.CustomizeAppBuilder(builder)
.AfterSetup(_ =>
{
Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
});
}
}
}

13
samples/ControlCatalog.Android/SplashActivity.cs

@ -1,12 +1,23 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Avalonia.Android;
namespace ControlCatalog.Android
{
[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : Activity
public class SplashActivity : AvaloniaSplashActivity<App>
{
protected override Avalonia.AppBuilder CustomizeAppBuilder(Avalonia.AppBuilder builder)
{
return base.CustomizeAppBuilder(builder)
.AfterSetup(_ =>
{
Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
});
}
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);

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

17
samples/ControlCatalog.Blazor.Web/App.razor.cs

@ -0,0 +1,17 @@
using Avalonia;
using Avalonia.Web.Blazor;
namespace ControlCatalog.Blazor.Web;
public partial class App
{
protected override void OnParametersSet()
{
AppBuilder.Configure<ControlCatalog.App>()
.UseBlazor()
// .With(new SkiaOptions { CustomGpuFactory = null }) // uncomment to disable GPU/GL rendering
.SetupWithSingleViewLifetime();
base.OnParametersSet();
}
}

29
samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<Nullable>enable</Nullable>
<EmccTotalMemory>16777216</EmccTotalMemory>
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
<BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0-rc.1.22427.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0-rc.1.22427.2" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.props" />
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.targets" />
</Project>

0
samples/ControlCatalog.Web/Pages/Index.razor → samples/ControlCatalog.Blazor.Web/Pages/Index.razor

29
samples/ControlCatalog.Blazor.Web/Program.cs

@ -0,0 +1,29 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using ControlCatalog.Blazor.Web;
public class Program
{
public static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
public static WebAssemblyHostBuilder CreateHostBuilder(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
return builder;
}
}

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

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

3
samples/ControlCatalog.Web/_Imports.razor → samples/ControlCatalog.Blazor.Web/_Imports.razor

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

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

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

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

1
samples/ControlCatalog.Web/wwwroot/index.html → samples/ControlCatalog.Blazor.Web/wwwroot/index.html

@ -17,7 +17,6 @@
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="js/app.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

1
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -5,6 +5,7 @@
<TargetFramework>net6.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeFrameworkVersion>6.0.9</RuntimeFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(RunNativeAotCompilation)' == 'true'">

4
samples/ControlCatalog.NetCore/Program.cs

@ -115,10 +115,6 @@ namespace ControlCatalog.NetCore
UseDBusMenu = true,
EnableIme = true
})
.With(new Win32PlatformOptions
{
EnableMultitouch = true
})
.UseSkia()
.AfterSetup(builder =>
{

19
samples/ControlCatalog.Web/App.razor.cs

@ -1,19 +0,0 @@
using Avalonia.Web.Blazor;
namespace ControlCatalog.Web;
public partial class App
{
protected override void OnParametersSet()
{
WebAppBuilder.Configure<ControlCatalog.App>()
.AfterSetup(_ =>
{
ControlCatalog.Pages.EmbedSample.Implementation = new EmbedSampleWeb();
})
//.With(new SkiaOptions { CustomGpuFactory = null }) // uncomment to disable GPU/GL rendering
.SetupWithSingleViewLifetime();
base.OnParametersSet();
}
}

69
samples/ControlCatalog.Web/ControlCatalog.Web.csproj

@ -1,57 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<!--Temporal hack that fixes compilation in VS-->
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<EmccTotalMemory>16777216</EmccTotalMemory>
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
<BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<WasmMainJSPath>main.js</WasmMainJSPath>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<WasmBuildNative>true</WasmBuildNative>
<EmccFlags>-sVERBOSE -sERROR_ON_UNDEFINED_SYMBOLS=0</EmccFlags>
</PropertyGroup>
<!-- In debug, make builds faster by reducing optimizations -->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<WasmNativeStrip>false</WasmNativeStrip>
<EmccCompileOptimizationFlag>-O1</EmccCompileOptimizationFlag>
<RunAOTCompilation>false</RunAOTCompilation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<Optimize>true</Optimize>
<WasmNativeStrip>true</WasmNativeStrip>
<EmccCompileOptimizationFlag>-O3</EmccCompileOptimizationFlag>
<EmccLinkOptimizationFlag>-O3</EmccLinkOptimizationFlag>
<RunAOTCompilation>false</RunAOTCompilation>
<DebuggerSupport>false</DebuggerSupport>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
<EventSourceSupport>false</EventSourceSupport>
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<InvariantGlobalization>true</InvariantGlobalization>
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
<UseNativeHttpHandler>true</UseNativeHttpHandler>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<RunAOTCompilation>true</RunAOTCompilation>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>
<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
<TrimMode>full</TrimMode>
<WasmBuildNative>true</WasmBuildNative>
<InvariantGlobalization>true</InvariantGlobalization>
<EmccCompileOptimizationFlag>-O2</EmccCompileOptimizationFlag>
<EmccLinkOptimizationFlag>-O2</EmccLinkOptimizationFlag>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.0" PrivateAssets="all" />
<TrimmerRootDescriptor Include="Roots.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj" />
<ProjectReference Include="..\..\src\Web\Avalonia.Web\Avalonia.Web.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.targets" />
<Import Project="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.CompilationTuning.props" />
<ItemGroup>
<WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraFilesToDeploy Include="main.js" />
<WasmExtraFilesToDeploy Include="embed.js" />
<WasmExtraFilesToDeploy Include="favicon.ico" />
<WasmExtraFilesToDeploy Include="Logo.svg" />
<WasmExtraFilesToDeploy Include="app.css" />
</ItemGroup>
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.props" />
<Import Project="..\..\src\Web\Avalonia.Web\Avalonia.Web.targets" />
</Project>

32
samples/ControlCatalog.Web/EmbedSample.Browser.cs

@ -1,34 +1,42 @@
using System;
using Avalonia;
using System.Runtime.InteropServices.JavaScript;
using Avalonia.Platform;
using Avalonia.Web.Blazor;
using Avalonia.Web;
using ControlCatalog.Pages;
using Microsoft.JSInterop;
namespace ControlCatalog.Web;
public class EmbedSampleWeb : INativeDemoControl
{
public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault)
{
var runtime = AvaloniaLocator.Current.GetRequiredService<IJSInProcessRuntime>();
if (isSecond)
{
var iframe = runtime.Invoke<IJSInProcessObjectReference>("document.createElement", "iframe");
iframe.InvokeVoid("setAttribute", "src", "https://www.youtube.com/embed/kZCIporjJ70");
var iframe = EmbedInterop.CreateElement("iframe");
iframe.SetProperty("src", "https://www.youtube.com/embed/kZCIporjJ70");
return new JSObjectControlHandle(iframe);
}
else
{
// window.createAppButton source is defined in "app.js" file.
var button = runtime.Invoke<IJSInProcessObjectReference>("window.createAppButton");
var defaultHandle = (JSObjectControlHandle)createDefault();
_ = JSHost.ImportAsync("embed.js", "./embed.js").ContinueWith(_ =>
{
EmbedInterop.AddAppButton(defaultHandle.Object);
});
return new JSObjectControlHandle(button);
return defaultHandle;
}
}
}
internal static partial class EmbedInterop
{
[JSImport("globalThis.document.createElement")]
public static partial JSObject CreateElement(string tagName);
[JSImport("addAppButton", "embed.js")]
public static partial void AddAppButton(JSObject parentObject);
}

5
samples/ControlCatalog.Web/Logo.svg

@ -0,0 +1,5 @@
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M30.4661 34.928C30.5364 34.928 30.6052 34.928 30.6754 34.928C32.8596 34.928 34.654 33.2918 34.9053 31.1752L34.9356 16.9955C34.6872 7.56697 26.9662 0 17.4777 0C7.83263 0 0.0137329 7.8189 0.0137329 17.464C0.0137329 27.0059 7.66618 34.7631 17.1687 34.928H30.4661Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.5239 5.948C12.0268 5.948 7.42967 9.80117 6.286 14.954C7.38092 15.2609 8.18385 16.2664 8.18385 17.4593C8.18385 18.6523 7.38092 19.6577 6.286 19.9647C7.42966 25.1175 12.0268 28.9706 17.5239 28.9706C19.525 28.9706 21.4068 28.4601 23.0462 27.562V28.8927H29.0352V17.9365C29.0407 17.7908 29.0352 17.6063 29.0352 17.4593C29.0352 11.1018 23.8814 5.948 17.5239 5.948ZM12.0098 17.4593C12.0098 14.414 14.4786 11.9452 17.5239 11.9452C20.5693 11.9452 23.038 14.414 23.038 17.4593C23.038 20.5047 20.5693 22.9734 17.5239 22.9734C14.4786 22.9734 12.0098 20.5047 12.0098 17.4593Z" fill="#8B44AC"/>
<path d="M7.36841 17.4517C7.36841 18.4691 6.54368 19.2938 5.52631 19.2938C4.50894 19.2938 3.6842 18.4691 3.6842 17.4517C3.6842 16.4343 4.50894 15.6096 5.52631 15.6096C6.54368 15.6096 7.36841 16.4343 7.36841 17.4517Z" fill="#8B44AC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

37
samples/ControlCatalog.Web/Program.cs

@ -1,29 +1,22 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Runtime.Versioning;
using Avalonia;
using Avalonia.Web;
using ControlCatalog;
using ControlCatalog.Web;
public class Program
[assembly:SupportedOSPlatform("browser")]
internal partial class Program
{
public static async Task Main(string[] args)
private static void Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
BuildAvaloniaApp()
.AfterSetup(_ =>
{
ControlCatalog.Pages.EmbedSample.Implementation = new EmbedSampleWeb();
}).SetupBrowserApp("out");
}
public static WebAssemblyHostBuilder CreateHostBuilder(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
return builder;
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>();
}

7
samples/ControlCatalog.Web/Roots.xml

@ -0,0 +1,7 @@
<linker>
<assembly fullname="ControlCatalog" preserve="All" />
<assembly fullname="ControlCatalog.Web" preserve="All" />
<assembly fullname="Avalonia.Themes.Fluent" preserve="All" />
<assembly fullname="Avalonia.Themes.Simple" preserve="All" />
<assembly fullname="Avalonia.Controls.ColorPicker" preserve="All" />
</linker>

49
samples/ControlCatalog.Web/app.css

@ -0,0 +1,49 @@
#out {
height: 100vh;
width: 100vw
}
#avalonia-splash {
position: relative;
height: 100%;
width: 100%;
color: whitesmoke;
background: #171C2C;
font-family: 'Nunito', sans-serif;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
#avalonia-splash a{
color: whitesmoke;
text-decoration: none;
}
.center {
display: flex;
justify-content: center;
height: 250px;
}
.splash-close {
animation: slide 0.5s linear 1s forwards;
}
@keyframes slide {
0% {
top: 0%;
}
50% {
opacity: 80%;
}
100% {
top: 100%;
overflow: hidden;
opacity: 0;
display: none;
visibility: collapse;
}
}

5
samples/ControlCatalog.Web/wwwroot/js/app.js → samples/ControlCatalog.Web/embed.js

@ -1,10 +1,11 @@
window.createAppButton = function () {
var button = document.createElement('button');
export function addAppButton(parent) {
var button = globalThis.document.createElement('button');
button.innerText = 'Hello world';
var clickCount = 0;
button.onclick = () => {
clickCount++;
button.innerText = 'Click count ' + clickCount;
};
parent.appendChild(button);
return button;
}

BIN
samples/ControlCatalog.Web/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

31
samples/ControlCatalog.Web/index.html

@ -0,0 +1,31 @@
<!DOCTYPE html>
<!-- Licensed to the .NET Foundation under one or more agreements. -->
<!-- The .NET Foundation licenses this file to you under the MIT license. -->
<html>
<head>
<title>AvaloniaUI - ControlCatalog</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="modulepreload" href="./main.js" />
<link rel="modulepreload" href="./dotnet.js" />
<link rel="modulepreload" href="./avalonia.js" />
<link rel="stylesheet" href="./app.css" />
</head>
<body style="margin: 0px">
<div id="out">
<div id="avalonia-splash">
<div class="center">
<h2>Powered by</h2>
<a class="navbar-brand" href="https://www.avaloniaui.net/" target="_blank">
<img src="Logo.svg" alt="Avalonia Logo" width="30" height="24" />
Avalonia
</a>
</div>
</div>
</div>
<script type='module' src="./main.js"></script>
</body>
</html>

19
samples/ControlCatalog.Web/main.js

@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
import { dotnet } from './dotnet.js'
import { registerAvaloniaModule } from './avalonia.js';
const is_browser = typeof window != "undefined";
if (!is_browser) throw new Error(`Expected to be running in a browser`);
const dotnetRuntime = await dotnet
.withDiagnosticTracing(false)
.withApplicationArgumentsFromQuery()
.create();
await registerAvaloniaModule(dotnetRuntime);
const config = dotnetRuntime.getConfig();
await dotnetRuntime.runMainAndExit(config.mainAssemblyName, ["dotnet", "is", "great!"]);

11
samples/ControlCatalog.Web/runtimeconfig.template.json

@ -0,0 +1,11 @@
{
"wasmHostProperties": {
"perHostConfig": [
{
"name": "browser",
"html-path": "index.html",
"Host": "browser"
}
]
}
}

3
samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj

@ -9,6 +9,9 @@
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
<!-- <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>-->
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodesignKey>iPhone Developer</CodesignKey>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />

34
samples/ControlCatalog/Converter/HexConverter.cs

@ -0,0 +1,34 @@
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Data.Converters;
namespace ControlCatalog.Converter;
public class HexConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var str = value?.ToString();
if (str == null)
return AvaloniaProperty.UnsetValue;
if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int x))
return (decimal)x;
return AvaloniaProperty.UnsetValue;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
try
{
if (value is decimal d)
return ((int)d).ToString("X8");
return AvaloniaProperty.UnsetValue;
}
catch
{
return AvaloniaProperty.UnsetValue;
}
}
}

2
samples/ControlCatalog/DecoratedWindow.xaml

@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.DecoratedWindow"
Title="Avalonia Control Gallery"
xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False" Name="Window">
xmlns:local="clr-namespace:ControlCatalog" SystemDecorations="None" Name="Window">
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="Decorated">

3
samples/ControlCatalog/MainView.xaml

@ -19,6 +19,9 @@
<TabItem Header="Acrylic">
<pages:AcrylicPage />
</TabItem>
<TabItem Header="AdornerLayer">
<pages:AdornerLayerPage />
</TabItem>
<TabItem Header="AutoCompleteBox">
<pages:AutoCompleteBoxPage />
</TabItem>

11
samples/ControlCatalog/MainView.xaml.cs

@ -2,10 +2,10 @@ using System;
using System.Collections;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.Themes.Fluent;
using ControlCatalog.Models;
using ControlCatalog.Pages;
@ -20,15 +20,14 @@ namespace ControlCatalog
var sideBar = this.Get<TabControl>("Sidebar");
if (AvaloniaLocator.Current?.GetService<IRuntimePlatform>()?.GetRuntimeInfo().IsDesktop == true)
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime)
{
IList tabItems = ((IList)sideBar.Items);
tabItems.Add(new TabItem()
var tabItems = (sideBar.Items as IList);
tabItems?.Add(new TabItem()
{
Header = "Screens",
Content = new ScreenPage()
});
}
var themes = this.Get<ComboBox>("Themes");
@ -36,7 +35,7 @@ namespace ControlCatalog
{
if (themes.SelectedItem is CatalogTheme theme)
{
var themeStyle = Application.Current.Styles[0];
var themeStyle = Application.Current!.Styles[0];
if (theme == CatalogTheme.FluentLight)
{
if (App.Fluent.Mode != FluentThemeMode.Light)

6
samples/ControlCatalog/MainWindow.xaml

@ -18,15 +18,15 @@
<NativeMenu>
<NativeMenuItem Header="File">
<NativeMenu>
<NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Clicked="OnOpenClicked" Gesture="Ctrl+O"/>
<NativeMenuItemSeperator/><!-- Uses incorrect spelling to demonstrate backwards compatibility -->
<NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Click="OnOpenClicked" Gesture="Ctrl+O"/>
<NativeMenuItemSeparator/>
<NativeMenuItem Icon="/Assets/github_icon.png" Header="Recent">
<NativeMenu/>
</NativeMenuItem>
<NativeMenuItemSeparator/>
<NativeMenuItem Header="{x:Static local:MainWindow.MenuQuitHeader}"
Gesture="{x:Static local:MainWindow.MenuQuitGesture}"
Clicked="OnCloseClicked" />
Click="OnCloseClicked" />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Edit">

8
samples/ControlCatalog/Models/Person.cs

@ -85,7 +85,7 @@ namespace ControlCatalog.Models
}
else
{
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList))
if (_errorLookup.TryGetValue(propertyName, out var errorList))
{
errorList.Clear();
errorList.Add(error!);
@ -114,12 +114,12 @@ namespace ControlCatalog.Models
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public IEnumerable? GetErrors(string propertyName)
public IEnumerable GetErrors(string? propertyName)
{
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList))
if (propertyName is { } && _errorLookup.TryGetValue(propertyName, out var errorList))
return errorList;
else
return null;
return Array.Empty<object>();
}
}
}

66
samples/ControlCatalog/Pages/AdornerLayerPage.xaml

@ -0,0 +1,66 @@
<UserControl x:Class="ControlCatalog.Pages.AdornerLayerPage"
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"
d:DesignHeight="800"
d:DesignWidth="400"
mc:Ignorable="d">
<DockPanel>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto" Margin="16" DockPanel.Dock="Top">
<TextBlock Grid.Column="0" Grid.Row="0">Rotation</TextBlock>
<Slider Name="rotation" Maximum="360" Grid.Column="1" Grid.Row="0"/>
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" DockPanel.Dock="Top">
<Button Name="AddAdorner"
Click="AddAdorner_OnClick"
Content="Add Adorner"
Margin="6" />
<Button Name="RemoveAdorner"
Click="RemoveAdorner_OnClick"
Content="Remove Adorner"
Margin="6" />
</StackPanel>
<Grid ColumnDefinitions="24,Auto,24"
RowDefinitions="24,Auto,24"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Border Background="{DynamicResource SystemAccentColor}" Grid.Column="1" Grid.Row="0"/>
<Border Background="{DynamicResource SystemAccentColor}" Grid.Column="0" Grid.Row="1"/>
<Border Background="{DynamicResource SystemAccentColor}" Grid.Column="2" Grid.Row="1"/>
<Border Background="{DynamicResource SystemAccentColor}" Grid.Column="1" Grid.Row="2"/>
<LayoutTransformControl Name="layoutTransform" Grid.Column="1" Grid.Row="1">
<LayoutTransformControl.LayoutTransform>
<RotateTransform Angle="{Binding #rotation.Value}"/>
</LayoutTransformControl.LayoutTransform>
<Button Name="AdornerButton"
Content="Adorned Button"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" VerticalAlignment="Stretch"
Width="200" Height="42">
<AdornerLayer.Adorner>
<Canvas x:Name="AdornerCanvas"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Cyan"
IsHitTestVisible="False"
Opacity="0.3"
IsVisible="True">
<Line StartPoint="-10000,0" EndPoint="10000,0" Stroke="Cyan" StrokeThickness="1" />
<Line StartPoint="-10000,42" EndPoint="10000,42" Stroke="Cyan" StrokeThickness="1" />
<Line StartPoint="0,-10000" EndPoint="0,10000" Stroke="Cyan" StrokeThickness="1" />
<Line StartPoint="200,-10000" EndPoint="200,10000" Stroke="Cyan" StrokeThickness="1" />
</Canvas>
</AdornerLayer.Adorner>
</Button>
</LayoutTransformControl>
</Grid>
</DockPanel>
</UserControl>

48
samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs

@ -0,0 +1,48 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class AdornerLayerPage : UserControl
{
private Control? _adorner;
public AdornerLayerPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void RemoveAdorner_OnClick(object? sender, RoutedEventArgs e)
{
var adornerButton = this.FindControl<Button>("AdornerButton");
if (adornerButton is { })
{
var adorner = AdornerLayer.GetAdorner(adornerButton);
if (adorner is { })
{
_adorner = adorner;
}
AdornerLayer.SetAdorner(adornerButton, null);
}
}
private void AddAdorner_OnClick(object? sender, RoutedEventArgs e)
{
var adornerButton = this.FindControl<Button>("AdornerButton");
if (adornerButton is { })
{
if (_adorner is { })
{
AdornerLayer.SetAdorner(adornerButton, _adorner);
}
}
}
}
}

2
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -28,7 +28,7 @@
</StackPanel>
<StackPanel>
<TextBlock Text="MinimumPopulateDelay: 1s" />
<AutoCompleteBox MinimumPopulateDelay="1" />
<AutoCompleteBox MinimumPopulateDelay="00:00:01" />
</StackPanel>
<StackPanel>
<TextBlock Text="MaxDropDownHeight: 60" />

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

@ -1,8 +1,6 @@
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Markup;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Data;
using System;
using System.Collections.Generic;
using System.Linq;
@ -161,23 +159,23 @@ namespace ControlCatalog.Pages
private bool LastWordContains(string? searchText, string? item)
{
var words = searchText?.Split(' ') ?? Array.Empty<string>();
var options = Sentences.Select(x => x.First).ToArray();
var options = Sentences.Select(x => x.First)
.ToArray<LinkedListNode<string>?>();
for (var i = 0; i < words.Length; ++i)
{
var word = words[i];
for (var j = 0; word is { } && j < options.Length; ++j)
{
var option = options[j];
if (option == null)
continue;
if (i == words.Length - 1)
{
options[j] = option.Value.ToLower().Contains(word.ToLower()) ? option : null;
}
else
if (options[i] is { } option)
{
options[j] = option.Value.Equals(word, StringComparison.InvariantCultureIgnoreCase) ? option.Next : null;
if (i == words.Length - 1)
{
options[j] = option.Value.ToLower().Contains(word.ToLower()) ? option : null;
}
else
{
options[j] = option.Value.Equals(word, StringComparison.InvariantCultureIgnoreCase) ? option.Next : null;
}
}
}
}

25
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs

@ -21,20 +21,23 @@ namespace ControlCatalog.Pages
public void OnSpin(object sender, SpinEventArgs e)
{
var spinner = (ButtonSpinner)sender;
var txtBox = (TextBlock)spinner.Content;
int value = Array.IndexOf(_mountains, txtBox?.Text);
if (e.Direction == SpinDirection.Increase)
value++;
else
value--;
if (spinner.Content is TextBlock txtBox)
{
int value = Array.IndexOf(_mountains, txtBox.Text);
if (e.Direction == SpinDirection.Increase)
value++;
else
value--;
if (value < 0)
value = _mountains.Length - 1;
else if (value >= _mountains.Length)
value = 0;
if (value < 0)
value = _mountains.Length - 1;
else if (value >= _mountains.Length)
value = 0;
txtBox.Text = _mountains[value];
}
txtBox.Text = _mountains[value];
}
private readonly string[] _mountains = new[]

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

@ -19,7 +19,7 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
public void OnRepeatButtonClick(object sender, object args)
public void OnRepeatButtonClick(object? sender, object args)
{
repeatButtonClickCount++;
var textBlock = this.Get<TextBlock>("RepeatButtonTextBlock");

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

@ -33,7 +33,7 @@ namespace ControlCatalog.Pages
}
private void TransitionChanged(object sender, SelectionChangedEventArgs e)
private void TransitionChanged(object? sender, SelectionChangedEventArgs e)
{
switch (_transition.SelectedIndex)
{

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

@ -23,55 +23,79 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
private async void CopyText(object sender, RoutedEventArgs args)
private async void CopyText(object? sender, RoutedEventArgs args)
{
await Application.Current.Clipboard.SetTextAsync(ClipboardContent.Text);
if (Application.Current!.Clipboard is { } clipboard && ClipboardContent is { } clipboardContent)
await clipboard.SetTextAsync(clipboardContent.Text ?? String.Empty);
}
private async void PasteText(object sender, RoutedEventArgs args)
private async void PasteText(object? sender, RoutedEventArgs args)
{
ClipboardContent.Text = await Application.Current.Clipboard.GetTextAsync();
if(Application.Current!.Clipboard is { } clipboard)
{
ClipboardContent.Text = await clipboard.GetTextAsync();
}
}
private async void CopyTextDataObject(object sender, RoutedEventArgs args)
private async void CopyTextDataObject(object? sender, RoutedEventArgs args)
{
var dataObject = new DataObject();
dataObject.Set(DataFormats.Text, ClipboardContent.Text ?? string.Empty);
await Application.Current.Clipboard.SetDataObjectAsync(dataObject);
if (Application.Current!.Clipboard is { } clipboard)
{
var dataObject = new DataObject();
dataObject.Set(DataFormats.Text, ClipboardContent.Text ?? string.Empty);
await clipboard.SetDataObjectAsync(dataObject);
}
}
private async void PasteTextDataObject(object sender, RoutedEventArgs args)
private async void PasteTextDataObject(object? sender, RoutedEventArgs args)
{
ClipboardContent.Text = await Application.Current.Clipboard.GetDataAsync(DataFormats.Text) as string ?? string.Empty;
if (Application.Current!.Clipboard is { } clipboard)
{
ClipboardContent.Text = await clipboard.GetDataAsync(DataFormats.Text) as string ?? string.Empty;
}
}
private async void CopyFilesDataObject(object sender, RoutedEventArgs args)
private async void CopyFilesDataObject(object? sender, RoutedEventArgs args)
{
var files = ClipboardContent.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
if (files.Length == 0)
if (Application.Current!.Clipboard is { } clipboard)
{
return;
var files = (ClipboardContent.Text ?? String.Empty)
.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
if (files.Length == 0)
{
return;
}
var dataObject = new DataObject();
dataObject.Set(DataFormats.FileNames, files);
await clipboard.SetDataObjectAsync(dataObject);
}
var dataObject = new DataObject();
dataObject.Set(DataFormats.FileNames, files);
await Application.Current.Clipboard.SetDataObjectAsync(dataObject);
}
private async void PasteFilesDataObject(object sender, RoutedEventArgs args)
private async void PasteFilesDataObject(object? sender, RoutedEventArgs args)
{
var fiels = await Application.Current.Clipboard.GetDataAsync(DataFormats.FileNames) as IEnumerable<string>;
ClipboardContent.Text = fiels != null ? string.Join(Environment.NewLine, fiels) : string.Empty;
if (Application.Current!.Clipboard is { } clipboard)
{
var fiels = await clipboard.GetDataAsync(DataFormats.FileNames) as IEnumerable<string>;
ClipboardContent.Text = fiels != null ? string.Join(Environment.NewLine, fiels) : string.Empty;
}
}
private async void GetFormats(object sender, RoutedEventArgs args)
{
var formats = await Application.Current.Clipboard.GetFormatsAsync();
ClipboardContent.Text = string.Join(Environment.NewLine, formats);
if (Application.Current!.Clipboard is { } clipboard)
{
var formats = await clipboard.GetFormatsAsync();
ClipboardContent.Text = string.Join(Environment.NewLine, formats);
}
}
private async void Clear(object sender, RoutedEventArgs args)
{
await Application.Current.Clipboard.ClearAsync();
if (Application.Current!.Clipboard is { } clipboard)
{
await clipboard.ClearAsync();
}
}
}
}

20
samples/ControlCatalog/Pages/ColorPickerPage.xaml

@ -2,6 +2,7 @@
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:controls="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls.ColorPicker"
xmlns:primitives="clr-namespace:Avalonia.Controls.Primitives;assembly=Avalonia.Controls"
xmlns:pc="clr-namespace:Avalonia.Controls.Primitives.Converters;assembly=Avalonia.Controls.ColorPicker"
mc:Ignorable="d"
@ -10,16 +11,22 @@
x:Class="ControlCatalog.Pages.ColorPickerPage">
<UserControl.Resources>
<pc:ThirdComponentConverter x:Key="ThirdComponent" />
</UserControl.Resources>
<Grid ColumnDefinitions="Auto,10,Auto,10,Auto"
<Grid x:Name="LayoutRoot"
ColumnDefinitions="Auto,10,Auto"
RowDefinitions="Auto,Auto">
<ColorPicker Grid.Column="0"
Grid.Row="1" />
<ColorView Grid.Column="0"
Grid.Row="0"
ColorSpectrumShape="Ring" />
<ColorPicker Grid.Column="0"
Grid.Row="1"
HsvColor="hsv(120, 1, 1)"
Margin="0,50,0,0">
<ColorPicker.Palette>
<controls:FlatColorPalette />
</ColorPicker.Palette>
</ColorPicker>
<Grid Grid.Column="2"
Grid.Row="0"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
@ -47,11 +54,8 @@
ColorModel="Hsva"
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />
<ColorPreviewer Grid.Row="5"
IsAccentColorsVisible="True"
IsAccentColorsVisible="False"
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />
</Grid>
<Grid Grid.Column="4"
Grid.Row="0">
</Grid>
</Grid>
</UserControl>

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

@ -1,6 +1,8 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace ControlCatalog.Pages
{
@ -9,6 +11,20 @@ namespace ControlCatalog.Pages
public ColorPickerPage()
{
InitializeComponent();
var layoutRoot = this.GetControl<Grid>("LayoutRoot");
// ColorPicker added from code-behind
var colorPicker = new ColorPicker()
{
Color = Colors.Blue,
Margin = new Thickness(0, 50, 0, 0),
HorizontalAlignment = HorizontalAlignment.Center,
};
Grid.SetColumn(colorPicker, 2);
Grid.SetRow(colorPicker, 1);
layoutRoot.Children.Add(colorPicker);
}
private void InitializeComponent()

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

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

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

@ -1,14 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.Rendering.Composition;
using Avalonia.Rendering.Composition.Animations;
@ -18,7 +12,7 @@ namespace ControlCatalog.Pages;
public partial class CompositionPage : UserControl
{
private ImplicitAnimationCollection _implicitAnimations;
private ImplicitAnimationCollection? _implicitAnimations;
public CompositionPage()
{
@ -28,7 +22,7 @@ public partial class CompositionPage : UserControl
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
this.FindControl<ItemsControl>("Items").Items = CreateColorItems();
this.Get<ItemsControl>("Items").Items = CreateColorItems();
}
private List<CompositionPageColorItem> CreateColorItems()
@ -115,7 +109,6 @@ public partial class CompositionPage : UserControl
public static void SetEnableAnimations(Border border, bool value)
{
var page = border.FindAncestorOfType<CompositionPage>();
if (page == null)
{
@ -127,8 +120,11 @@ public partial class CompositionPage : UserControl
return;
page.EnsureImplicitAnimations();
ElementComposition.GetElementVisual((Visual)border.GetVisualParent()).ImplicitAnimations =
page._implicitAnimations;
if (border.GetVisualParent() is Visual visualParent
&& ElementComposition.GetElementVisual(visualParent) is CompositionVisual compositionVisual)
{
compositionVisual.ImplicitAnimations = page._implicitAnimations;
}
}
}
@ -150,4 +146,4 @@ public class CompositionPageColorItem
{
Color = color;
}
}
}

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

@ -52,13 +52,13 @@ namespace ControlCatalog.Pages
base.OnDataContextChanged(e);
}
private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e)
private void ContextFlyoutPage_Closing(object? sender, CancelEventArgs e)
{
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox");
e.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
}
private void ContextFlyoutPage_Opening(object sender, EventArgs e)
private void ContextFlyoutPage_Opening(object? sender, EventArgs e)
{
if (e is CancelEventArgs cancelArgs)
{
@ -67,20 +67,20 @@ namespace ControlCatalog.Pages
}
}
private void CloseFlyout(object sender, RoutedEventArgs e)
private void CloseFlyout(object? sender, RoutedEventArgs e)
{
_textBox.ContextFlyout?.Hide();
}
public void CustomContextRequested(object sender, ContextRequestedEventArgs e)
public void CustomContextRequested(object? sender, ContextRequestedEventArgs e)
{
var border = (Border)sender;
var textBlock = (TextBlock)border.Child;
textBlock.Text = e.TryGetPosition(border, out var point)
? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}"
: "Context was requested without pointer";
e.Handled = true;
if (sender is Border border && border.Child is TextBlock textBlock)
{
textBlock.Text = e.TryGetPosition(border, out var point)
? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}"
: "Context was requested without pointer";
e.Handled = true;
}
}
private void InitializeComponent()

23
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@ -35,30 +35,31 @@ namespace ControlCatalog.Pages
base.OnDataContextChanged(e);
}
private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e)
private void ContextFlyoutPage_Closing(object? sender, CancelEventArgs e)
{
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox");
e.Cancel = cancelCloseCheckBox.IsChecked ?? false;
e.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
}
private void ContextFlyoutPage_Opening(object sender, EventArgs e)
private void ContextFlyoutPage_Opening(object? sender, EventArgs e)
{
if (e is CancelEventArgs cancelArgs)
{
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox");
cancelArgs.Cancel = cancelCloseCheckBox.IsChecked ?? false;
cancelArgs.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
}
}
public void CustomContextRequested(object sender, ContextRequestedEventArgs e)
public void CustomContextRequested(object? sender, ContextRequestedEventArgs e)
{
var border = (Border)sender;
var textBlock = (TextBlock)border.Child;
if (sender is Border border && border.Child is TextBlock textBlock)
{
textBlock.Text = e.TryGetPosition(border, out var point)
? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}"
: "Context was requested without pointer";
e.Handled = true;
}
textBlock.Text = e.TryGetPosition(border, out var point)
? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}"
: "Context was requested without pointer";
e.Handled = true;
}
private void InitializeComponent()

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

@ -62,7 +62,7 @@ namespace ControlCatalog.Pages
addButton.Click += (a, b) => collectionView3.AddNew();
}
private void Dg1_LoadingRow(object sender, DataGridRowEventArgs e)
private void Dg1_LoadingRow(object? sender, DataGridRowEventArgs e)
{
e.Row.Header = e.Row.GetIndex() + 1;
}
@ -74,7 +74,7 @@ namespace ControlCatalog.Pages
private class ReversedStringComparer : IComparer<object>, IComparer
{
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
if (x is string left && y is string right)
{

24
samples/ControlCatalog/Pages/DateTimePickerPage.xaml

@ -13,17 +13,17 @@
Margin="16"
HorizontalAlignment="Stretch"
Spacing="16">
<TextBlock FontSize="18">A simple DatePicker with a header</TextBlock>
<TextBlock FontSize="18">A simple DatePicker</TextBlock>
<StackPanel Orientation="Vertical">
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<DatePicker Header="Pick a date" />
<DatePicker />
</Border>
<Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
<TextBlock Padding="15">
<TextBlock.Text>
<x:String>
&lt;DatePicker Header="Pick a date" /&gt;
&lt;DatePicker/&gt;
</x:String>
</TextBlock.Text>
</TextBlock>
@ -33,7 +33,7 @@
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<DatePicker Header="Pick a date">
<DatePicker >
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
@ -79,24 +79,24 @@
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<TimePicker Header="Pick a time">
<TimePicker>
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</TimePicker>
</Border>
<TextBlock FontSize="18">A TimePicker with a header and minute increments specified.</TextBlock>
<TextBlock FontSize="18">A TimePicker with minute increments specified.</TextBlock>
<StackPanel Orientation="Vertical">
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<TimePicker Header="Arrival time" MinuteIncrement="15" />
<TimePicker MinuteIncrement="15" />
</Border>
<Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
<TextBlock Padding="15">
<TextBlock.Text>
<x:String>
&lt;TimePicker Header="Arrival time" MinuteIncrement="15" /&gt;
&lt;TimePicker MinuteIncrement="15" /&gt;
</x:String>
</TextBlock.Text>
</TextBlock>
@ -107,13 +107,13 @@
<StackPanel Orientation="Vertical">
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<TimePicker ClockIdentifier="12HourClock" Header="12 hour clock" />
<TimePicker ClockIdentifier="12HourClock"/>
</Border>
<Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
<TextBlock Padding="15">
<TextBlock.Text>
<x:String>
&lt;TimePicker ClockIdentifier="12HourClock" Header="12 hour clock" /&gt;
&lt;TimePicker ClockIdentifier="12HourClock" /&gt;
</x:String>
</TextBlock.Text>
</TextBlock>
@ -124,13 +124,13 @@
<StackPanel Orientation="Vertical">
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<TimePicker ClockIdentifier="24HourClock" Header="24 hour clock" />
<TimePicker ClockIdentifier="24HourClock" />
</Border>
<Panel Background="{DynamicResource SystemControlBackgroundBaseLowBrush}">
<TextBlock Padding="15">
<TextBlock.Text>
<x:String>
&lt;TimePicker ClockIdentifier="24HourClock" Header="24 hour clock" /&gt;
&lt;TimePicker ClockIdentifier="24HourClock" /&gt;
</x:String>
</TextBlock.Text>
</TextBlock>

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

@ -111,9 +111,16 @@ namespace ControlCatalog.Pages
Title = "Select folder",
Directory = lastSelectedDirectory?.TryGetUri(out var path) == true ? path.LocalPath : null
}.ShowAsync(GetWindow());
lastSelectedDirectory = new BclStorageFolder(new System.IO.DirectoryInfo(result));
results.Items = new [] { result };
resultsVisible.IsVisible = result != null;
if (string.IsNullOrEmpty(result))
{
resultsVisible.IsVisible = false;
}
else
{
lastSelectedDirectory = new BclStorageFolder(new System.IO.DirectoryInfo(result));
results.Items = new[] { result };
resultsVisible.IsVisible = true;
}
};
this.Get<Button>("OpenBoth").Click += async delegate
{

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

@ -1,9 +1,9 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using System;
using System;
using System.Linq;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages
{
@ -27,9 +27,9 @@ namespace ControlCatalog.Pages
void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
{
var dragMe = this.Get<Border>("DragMe" + suffix);
var dragState = this.Get<TextBlock>("DragState"+suffix);
var dragState = this.Get<TextBlock>("DragState" + suffix);
async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
async void DoDrag(object? sender, Avalonia.Input.PointerPressedEventArgs e)
{
var dragData = new DataObject();
factory(dragData);
@ -55,7 +55,7 @@ namespace ControlCatalog.Pages
}
}
void DragOver(object sender, DragEventArgs e)
void DragOver(object? sender, DragEventArgs e)
{
if (e.Source is Control c && c.Name == "MoveTarget")
{
@ -73,7 +73,7 @@ namespace ControlCatalog.Pages
e.DragEffects = DragDropEffects.None;
}
void Drop(object sender, DragEventArgs e)
void Drop(object? sender, DragEventArgs e)
{
if (e.Source is Control c && c.Name == "MoveTarget")
{
@ -83,11 +83,11 @@ namespace ControlCatalog.Pages
{
e.DragEffects = e.DragEffects & (DragDropEffects.Copy);
}
if (e.Data.Contains(DataFormats.Text))
_DropState.Text = e.Data.GetText();
else if (e.Data.Contains(DataFormats.FileNames))
_DropState.Text = string.Join(Environment.NewLine, e.Data.GetFileNames());
_DropState.Text = string.Join(Environment.NewLine, e.Data.GetFileNames() ?? Array.Empty<string>());
else if (e.Data.Contains(CustomFormat))
_DropState.Text = "Custom: " + e.Data.Get(CustomFormat);
}

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

@ -20,7 +20,7 @@ namespace ControlCatalog.Pages
SetXamlTexts();
}
private void Afp_DoubleTapped(object sender, RoutedEventArgs e)
private void Afp_DoubleTapped(object? sender, RoutedEventArgs e)
{
if (sender is Panel p)
{

10
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs

@ -123,7 +123,7 @@ namespace ControlCatalog.Pages
element.BringIntoView();
}
private void RepeaterClick(object sender, PointerPressedEventArgs e)
private void RepeaterClick(object? sender, PointerPressedEventArgs e)
{
if ((e.Source as TextBlock)?.DataContext is ItemsRepeaterPageViewModel.Item item)
{
@ -132,7 +132,7 @@ namespace ControlCatalog.Pages
}
}
private void RepeaterOnKeyDown(object sender, KeyEventArgs e)
private void RepeaterOnKeyDown(object? sender, KeyEventArgs e)
{
if (e.Key == Key.F5)
{
@ -140,17 +140,17 @@ namespace ControlCatalog.Pages
}
}
private void scrollToLast_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
private void scrollToLast_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
ScrollTo(_viewModel.Items.Count - 1);
}
private void scrollToRandom_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
private void scrollToRandom_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
ScrollTo(_random.Next(_viewModel.Items.Count - 1));
}
private void scrollToSelected_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
private void scrollToSelected_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
ScrollTo(_selectedIndex);
}

16
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
xmlns:converter="clr-namespace:ControlCatalog.Converter"
x:Class="ControlCatalog.Pages.NumericUpDownPage">
<StackPanel Orientation="Vertical" Spacing="4"
MaxWidth="800">
@ -54,11 +55,11 @@
<Grid Grid.Row="0" Grid.Column="2" Margin="8" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Minimum:</TextBlock>
<NumericUpDown Grid.Row="0" Grid.Column="1" Value="{Binding #upDown.Minimum}"
CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" HorizontalAlignment="Center"/>
NumberFormat="{Binding #upDown.NumberFormat}" VerticalAlignment="Center" Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Maximum:</TextBlock>
<NumericUpDown Grid.Row="1" Grid.Column="1" Value="{Binding #upDown.Maximum}"
CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" HorizontalAlignment="Center"/>
NumberFormat="{Binding #upDown.NumberFormat}" VerticalAlignment="Center" Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Increment:</TextBlock>
<NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding #upDown.Increment}" VerticalAlignment="Center"
@ -97,6 +98,17 @@
</DataValidationErrors.Error>
</NumericUpDown>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="10">
<Label Target="HexUpDown" FontSize="14" FontWeight="Bold" VerticalAlignment="Center">NumericUpDown in HEX mode:</Label>
<NumericUpDown x:Name="HexUpDown" Value="0"
VerticalAlignment="Center">
<NumericUpDown.TextConverter>
<converter:HexConverter></converter:HexConverter>
</NumericUpDown.TextConverter>
</NumericUpDown>
</StackPanel>
</WrapPanel>
</StackPanel>

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

@ -2,9 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using MiniMvvm;
@ -29,7 +27,7 @@ namespace ControlCatalog.Pages
public class NumbersPageViewModel : ViewModelBase
{
private IList<FormatObject>? _formats;
private FormatObject _selectedFormat;
private FormatObject? _selectedFormat;
private IList<Location>? _spinnerLocations;
private double _doubleValue;
@ -89,7 +87,7 @@ namespace ControlCatalog.Pages
.Where(c => new[] { "en-US", "en-GB", "fr-FR", "ar-DZ", "zh-CH", "cs-CZ" }.Contains(c.Name))
.ToArray();
public FormatObject SelectedFormat
public FormatObject? SelectedFormat
{
get { return _selectedFormat; }
set { this.RaiseAndSetIfChanged(ref _selectedFormat, value); }

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

@ -68,7 +68,7 @@ namespace ControlCatalog.Pages
set => SetAndRaise(DiscoProperty, ref _disco, value);
}
private string _info;
private string _info = string.Empty;
public static readonly DirectProperty<OpenGlPageControl, string> InfoProperty =
AvaloniaProperty.RegisterDirect<OpenGlPageControl, string>("Info", o => o.Info, (o, v) => o.Info = v);
@ -205,7 +205,7 @@ namespace ControlCatalog.Pages
public OpenGlPageControl()
{
var name = typeof(OpenGlPage).Assembly.GetManifestResourceNames().First(x => x.Contains("teapot.bin"));
using (var sr = new BinaryReader(typeof(OpenGlPage).Assembly.GetManifestResourceStream(name)))
using (var sr = new BinaryReader(typeof(OpenGlPage).Assembly.GetManifestResourceStream(name)!))
{
var buf = new byte[sr.ReadInt32()];
sr.Read(buf, 0, buf.Length);
@ -345,7 +345,7 @@ namespace ControlCatalog.Pages
0.01f, 1000);
var view = Matrix4x4.CreateLookAt(new Vector3(25, 25, 25), new Vector3(), new Vector3(0, -1, 0));
var view = Matrix4x4.CreateLookAt(new Vector3(25, 25, 25), new Vector3(), new Vector3(0, 1, 0));
var model = Matrix4x4.CreateFromYawPitchRoll(_yaw, _pitch, _roll);
var modelLoc = GL.GetUniformLocationString(_shaderProgram, "uModel");
var viewLoc = GL.GetUniformLocationString(_shaderProgram, "uView");

4
samples/ControlCatalog/Pages/PointerCanvas.cs

@ -174,9 +174,9 @@ Twist: {_lastProperties?.Twist}";
var lastPointer = e.GetCurrentPoint(this);
_lastProperties = lastPointer.Properties;
if (_lastProperties.PointerUpdateKind != PointerUpdateKind.Other)
if (_lastProperties?.PointerUpdateKind != PointerUpdateKind.Other)
{
_lastNonOtherUpdateKind = _lastProperties.PointerUpdateKind;
_lastNonOtherUpdateKind = _lastProperties?.PointerUpdateKind;
}
if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)

33
samples/ControlCatalog/Pages/PointersPage.xaml.cs

@ -1,8 +1,6 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages;
@ -31,43 +29,48 @@ public class PointersPage : UserControl
border2.PointerExited += Border_PointerUpdated;
}
private void Border_PointerUpdated(object sender, PointerEventArgs e)
private void Border_PointerUpdated(object? sender, PointerEventArgs e)
{
var textBlock = (TextBlock)((Border)sender).Child;
var position = e.GetPosition((Border)sender);
textBlock.Text = @$"Type: {e.Pointer.Type}
if (sender is Border border && border.Child is TextBlock textBlock)
{
var position = e.GetPosition(border);
textBlock.Text = @$"Type: {e.Pointer.Type}
Captured: {e.Pointer.Captured == sender}
PointerId: {e.Pointer.Id}
Position: {(int)position.X} {(int)position.Y}";
e.Handled = true;
e.Handled = true;
}
}
private void Border_PointerCaptureLost(object sender, PointerCaptureLostEventArgs e)
private void Border_PointerCaptureLost(object? sender, PointerCaptureLostEventArgs e)
{
var textBlock = (TextBlock)((Border)sender).Child;
textBlock.Text = @$"Type: {e.Pointer.Type}
if (sender is Border border && border.Child is TextBlock textBlock)
{
textBlock.Text = @$"Type: {e.Pointer.Type}
Captured: {e.Pointer.Captured == sender}
PointerId: {e.Pointer.Id}
Position: ??? ???";
e.Handled = true;
e.Handled = true;
}
}
private void Border_PointerReleased(object sender, PointerReleasedEventArgs e)
private void Border_PointerReleased(object? sender, PointerReleasedEventArgs e)
{
if (e.Pointer.Captured == sender)
{
e.Pointer.Capture(null);
e.Handled = true;
}
else
else if (e.Pointer.Captured is not null)
{
throw new InvalidOperationException("How?");
}
}
private void Border_PointerPressed(object sender, PointerPressedEventArgs e)
private void Border_PointerPressed(object? sender, PointerPressedEventArgs e)
{
e.Pointer.Capture((Border)sender);
e.Pointer.Capture(sender as Border);
e.Handled = true;
}

16
samples/ControlCatalog/Pages/ScreenPage.cs

@ -2,10 +2,10 @@ using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
namespace ControlCatalog.Pages
{
@ -18,8 +18,10 @@ namespace ControlCatalog.Pages
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
Window w = (Window)VisualRoot!;
w.PositionChanged += (sender, args) => InvalidateVisual();
if(VisualRoot is Window w)
{
w.PositionChanged += (_, _) => InvalidateVisual();
}
}
public override void Render(DrawingContext context)
@ -27,7 +29,7 @@ namespace ControlCatalog.Pages
base.Render(context);
if (!(VisualRoot is Window w))
{
return;
return;
}
var screens = w.Screens.All;
var scaling = ((IRenderRoot)w).RenderScaling;
@ -40,7 +42,7 @@ namespace ControlCatalog.Pages
if (screen.Bounds.X / 10f < _leftMost)
{
_leftMost = screen.Bounds.X / 10f;
InvalidateVisual();
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
return;
}
@ -60,10 +62,10 @@ namespace ControlCatalog.Pages
CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20));
formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%");
formattedText = CreateFormattedText($"Scaling: {screen.Scaling * 100}%");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"Primary: {screen.Primary}");
formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText =

8
samples/ControlCatalog/ViewModels/ContextPageViewModel.cs

@ -53,14 +53,14 @@ namespace ControlCatalog.ViewModels
var window = View?.GetVisualRoot() as Window;
if (window == null)
return;
var dialog = new OpenFileDialog();
var result = await dialog.ShowAsync(window);
var result = await window.StorageProvider.OpenFilePickerAsync(new Avalonia.Platform.Storage.FilePickerOpenOptions() { AllowMultiple = true });
if (result != null)
{
foreach (var path in result)
foreach (var file in result)
{
System.Diagnostics.Debug.WriteLine($"Opened: {path}");
System.Diagnostics.Debug.WriteLine($"Opened: {file.Name}");
}
}
}

7
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@ -74,14 +74,13 @@ namespace ControlCatalog.ViewModels
var window = View?.GetVisualRoot() as Window;
if (window == null)
return;
var dialog = new OpenFileDialog();
var result = await dialog.ShowAsync(window);
var result = await window.StorageProvider.OpenFilePickerAsync(new Avalonia.Platform.Storage.FilePickerOpenOptions() { AllowMultiple = true });
if (result != null)
{
foreach (var path in result)
foreach (var file in result)
{
System.Diagnostics.Debug.WriteLine($"Opened: {path}");
System.Diagnostics.Debug.WriteLine($"Opened: {file.Name}");
}
}
}

6
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@ -117,9 +117,9 @@ namespace ControlCatalog.ViewModels
PageTransitions[3].Transition = new PageSlide(TimeSpan.FromMilliseconds(Duration), PageSlide.SlideAxis.Vertical);
var compositeTransition = new CompositePageTransition();
compositeTransition.PageTransitions.Add(PageTransitions[1].Transition);
compositeTransition.PageTransitions.Add(PageTransitions[2].Transition);
compositeTransition.PageTransitions.Add(PageTransitions[3].Transition);
compositeTransition.PageTransitions.Add(PageTransitions[1].Transition!);
compositeTransition.PageTransitions.Add(PageTransitions[2].Transition!);
compositeTransition.PageTransitions.Add(PageTransitions[3].Transition!);
PageTransitions[4].Transition = compositeTransition;
PageTransitions[5].Transition = new CustomTransition(TimeSpan.FromMilliseconds(Duration));

27
samples/IntegrationTestApp/MacOSIntegration.cs

@ -0,0 +1,27 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Controls;
namespace IntegrationTestApp
{
public static class MacOSIntegration
{
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "sel_registerName")]
private static extern IntPtr GetHandle(string name);
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
private static extern long Int64_objc_msgSend(IntPtr receiver, IntPtr selector);
private static readonly IntPtr s_orderedIndexSelector;
static MacOSIntegration()
{
s_orderedIndexSelector = GetHandle("orderedIndex");;
}
public static long GetOrderedIndex(Window window)
{
return Int64_objc_msgSend(window.PlatformImpl!.Handle.Handle, s_orderedIndexSelector);
}
}
}

50
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Automation;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
using Microsoft.CodeAnalysis;
namespace IntegrationTestApp
{
@ -31,20 +32,23 @@ namespace IntegrationTestApp
private void InitializeViewMenu()
{
var mainTabs = this.FindControl<TabControl>("MainTabs");
var mainTabs = this.Get<TabControl>("MainTabs");
var viewMenu = (NativeMenuItem)NativeMenu.GetMenu(this).Items[1];
foreach (TabItem tabItem in mainTabs.Items)
if (mainTabs.Items is not null)
{
var menuItem = new NativeMenuItem
foreach (TabItem tabItem in mainTabs.Items)
{
Header = (string)tabItem.Header!,
IsChecked = tabItem.IsSelected,
ToggleType = NativeMenuItemToggleType.Radio,
};
menuItem.Click += (s, e) => tabItem.IsSelected = true;
viewMenu.Menu.Items.Add(menuItem);
var menuItem = new NativeMenuItem
{
Header = (string)tabItem.Header!,
IsChecked = tabItem.IsSelected,
ToggleType = NativeMenuItemToggleType.Radio,
};
menuItem.Click += (s, e) => tabItem.IsSelected = true;
viewMenu?.Menu?.Items.Add(menuItem);
}
}
}
@ -61,6 +65,17 @@ namespace IntegrationTestApp
WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex,
};
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
{
// Make sure the windows have unique names and AutomationIds.
var existing = lifetime.Windows.OfType<ShowWindowTest>().Count();
if (existing > 0)
{
AutomationProperties.SetAutomationId(window, window.Name + (existing + 1));
window.Title += $" {existing + 1}";
}
}
if (size.HasValue)
{
window.Width = size.Value.Width;
@ -99,6 +114,7 @@ namespace IntegrationTestApp
foreach (var window in lifetime.Windows)
{
window.Show();
if (window.WindowState == WindowState.Minimized)
window.WindowState = WindowState.Normal;
}
@ -106,8 +122,8 @@ namespace IntegrationTestApp
private void MenuClicked(object? sender, RoutedEventArgs e)
{
var clickedMenuItemTextBlock = this.FindControl<TextBlock>("ClickedMenuItem");
clickedMenuItemTextBlock.Text = ((MenuItem)sender!).Header.ToString();
var clickedMenuItemTextBlock = this.Get<TextBlock>("ClickedMenuItem");
clickedMenuItemTextBlock.Text = (sender as MenuItem)?.Header?.ToString();
}
private void OnButtonClick(object? sender, RoutedEventArgs e)
@ -115,13 +131,13 @@ namespace IntegrationTestApp
var source = e.Source as Button;
if (source?.Name == "ComboBoxSelectionClear")
this.FindControl<ComboBox>("BasicComboBox").SelectedIndex = -1;
this.Get<ComboBox>("BasicComboBox").SelectedIndex = -1;
if (source?.Name == "ComboBoxSelectFirst")
this.FindControl<ComboBox>("BasicComboBox").SelectedIndex = 0;
this.Get<ComboBox>("BasicComboBox").SelectedIndex = 0;
if (source?.Name == "ListBoxSelectionClear")
this.FindControl<ListBox>("BasicListBox").SelectedIndex = -1;
this.Get<ListBox>("BasicListBox").SelectedIndex = -1;
if (source?.Name == "MenuClickedMenuItemReset")
this.FindControl<TextBlock>("ClickedMenuItem").Text = "None";
this.Get<TextBlock>("ClickedMenuItem").Text = "None";
if (source?.Name == "ShowWindow")
ShowWindow();
if (source?.Name == "SendToBack")

7
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -3,7 +3,7 @@
x:Class="IntegrationTestApp.ShowWindowTest"
Name="SecondaryWindow"
Title="Show Window Test">
<Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Label Grid.Column="0" Grid.Row="1">Client Size</Label>
<TextBox Name="ClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True"
Text="{Binding ClientSize, Mode=OneWay}"/>
@ -31,5 +31,10 @@
<ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>Fullscreen</ComboBoxItem>
</ComboBox>
<Label Grid.Column="0" Grid.Row="8">Order (mac)</Label>
<TextBox Name="Order" Grid.Column="1" Grid.Row="8" IsReadOnly="True"/>
<Button Name="HideButton" Grid.Row="9" Command="{Binding $parent[Window].Hide}">Hide</Button>
</Grid>
</Window>

28
samples/IntegrationTestApp/ShowWindowTest.axaml.cs

@ -1,21 +1,32 @@
using System;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Rendering;
using Avalonia.Threading;
namespace IntegrationTestApp
{
public class ShowWindowTest : Window
{
private readonly DispatcherTimer? _timer;
private readonly TextBox? _orderTextBox;
public ShowWindowTest()
{
InitializeComponent();
DataContext = this;
PositionChanged += (s, e) => this.GetControl<TextBox>("Position").Text = $"{Position}";
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
_orderTextBox = this.GetControl<TextBox>("Order");
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
_timer.Tick += TimerOnTick;
_timer.Start();
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
@ -36,5 +47,16 @@ namespace IntegrationTestApp
ownerRect.Text = $"{owner.Position}, {PixelSize.FromSize(owner.FrameSize!.Value, scaling)}";
}
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_timer?.Stop();
}
private void TimerOnTick(object? sender, EventArgs e)
{
_orderTextBox!.Text = MacOSIntegration.GetOrderedIndex(this).ToString();
}
}
}

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

Loading…
Cancel
Save