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 csharp_space_between_square_brackets = false
space_within_single_line_array_initializer_braces = true 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 # Wrapping preferences
csharp_wrap_before_ternary_opsigns = false csharp_wrap_before_ternary_opsigns = false
# Avalonia DevAnalyzer preferences
dotnet_diagnostic.AVADEV2001.severity = error
# Xaml files # Xaml files
[*.{xaml,axaml}] [*.{xaml,axaml}]
indent_size = 2 indent_size = 2

1
.github/FUNDING.yml

@ -1 +1,2 @@
github: avaloniaui
open_collective: avalonia 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 - [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Documentation with user documentation
## Breaking changes ## 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 ## Obsoletions / Deprecations
<!--- Obsolete and Deprecated attributes on APIs MUST only be included when discussed with Core team. @grokys, @kekekeks & @danwalmsley --> <!--- 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 *.map
src/Web/Avalonia.Web.Blazor/wwwroot/*.js src/Web/Avalonia.Web.Blazor/wwwroot/*.js
src/Web/Avalonia.Web.Blazor/Interop/Typescript/*.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"] [submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"]
path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
url = https://github.com/kekekeks/XamlX.git 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}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
build\ApiDiff.props = build\ApiDiff.props build\ApiDiff.props = build\ApiDiff.props
build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props
build\Base.props = build\Base.props build\Base.props = build\Base.props
build\Binding.props = build\Binding.props build\Binding.props = build\Binding.props
build\CoreLibraries.props = build\CoreLibraries.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.CSharp.props = build\Microsoft.CSharp.props
build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
build\Moq.props = build\Moq.props build\Moq.props = build\Moq.props
build\NetAnalyzers.props = build\NetAnalyzers.props
build\NetCore.props = build\NetCore.props build\NetCore.props = build\NetCore.props
build\NetFX.props = build\NetFX.props build\NetFX.props = build\NetFX.props
build\NullableEnable.props = build\NullableEnable.props
build\ReactiveUI.props = build\ReactiveUI.props build\ReactiveUI.props = build\ReactiveUI.props
build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
build\Rx.props = build\Rx.props build\Rx.props = build\Rx.props
@ -198,8 +201,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{86A3F706-DC3
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web.Blazor", "src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj", "{25831348-EB2A-483E-9576-E8F6528674A5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web.Blazor", "src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj", "{25831348-EB2A-483E-9576-E8F6528674A5}"
EndProject 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}" 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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{EABE2161-989B-42BF-BD8D-1E34B20C21F1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{EABE2161-989B-42BF-BD8D-1E34B20C21F1}"
EndProject 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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution 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.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.Build.0 = 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.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.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.ActiveCfg = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = 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 {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}.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.ActiveCfg = Release|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.Build.0 = 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 {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}.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.ActiveCfg = Release|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -545,6 +582,7 @@ Global
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} {41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {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} {351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C} {909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098} {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} {676D6BFD-029D-4E43-BFC7-3892265CE251} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{25831348-EB2A-483E-9576-E8F6528674A5} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268} {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} {26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098} {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {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} {2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{EABE2161-989B-42BF-BD8D-1E34B20C21F1} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {EABE2161-989B-42BF-BD8D-1E34B20C21F1} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

4
NOTICE.md

@ -111,7 +111,7 @@ DEALINGS IN THE SOFTWARE.
# Metsys.Bson # Metsys.Bson
Copyright (c) 2010, Karl Seguin - http://www.openmymind.net/ Copyright (c) 2010, Karl Seguin - https://www.openmymind.net/
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without 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 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (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' name: 'AvaloniaMacPool'
steps: 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: system_profiler SPDisplaysDataType |grep Resolution
- script: | - script: |
@ -41,9 +51,14 @@ jobs:
steps: steps:
- task: UseDotNet@2 - 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: inputs:
version: 6.0.202 version: 7.0.100-rc.2.22477.23
- task: Windows Application Driver@0 - task: Windows Application Driver@0
inputs: inputs:
@ -57,6 +72,7 @@ jobs:
projects: 'samples/IntegrationTestApp/IntegrationTestApp.csproj' projects: 'samples/IntegrationTestApp/IntegrationTestApp.csproj'
- task: DotNetCoreCLI@2 - task: DotNetCoreCLI@2
retryCountOnTaskFailure: 3
inputs: inputs:
command: 'test' command: 'test'
projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj' projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj'

44
azure-pipelines.yml

@ -6,7 +6,6 @@ jobs:
variables: variables:
SolutionDir: '$(Build.SourcesDirectory)' SolutionDir: '$(Build.SourcesDirectory)'
steps: steps:
- task: PowerShell@2 - task: PowerShell@2
displayName: Get PR Number displayName: Get PR Number
inputs: inputs:
@ -31,14 +30,20 @@ jobs:
vmImage: 'ubuntu-20.04' vmImage: 'ubuntu-20.04'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418' displayName: 'Use .NET Core SDK 6.0.401'
inputs: inputs:
version: 3.1.418 version: 6.0.401
- task: UseDotNet@2 - 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: inputs:
version: 6.0.202 script: |
dotnet workload install wasm-tools wasm-experimental
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Run Build' displayName: 'Run Build'
@ -62,22 +67,21 @@ jobs:
vmImage: 'macos-12' vmImage: 'macos-12'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418' displayName: 'Use .NET Core SDK 6.0.401'
inputs: inputs:
version: 3.1.418 version: 6.0.401
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.202' displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs: inputs:
version: 6.0.202 version: 7.0.100-rc.2.22477.23
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Mono 5.18' displayName: 'Install Workloads'
inputs: inputs:
script: | 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 dotnet workload install wasm-tools wasm-experimental
sudo installer -verbose -pkg ./mono.pkg -target /
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Generate avalonia-native' displayName: 'Generate avalonia-native'
inputs: inputs:
@ -134,26 +138,26 @@ jobs:
SolutionDir: '$(Build.SourcesDirectory)' SolutionDir: '$(Build.SourcesDirectory)'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418' displayName: 'Use .NET Core SDK 6.0.401'
inputs: inputs:
version: 3.1.418 version: 6.0.401
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.202' displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23'
inputs: inputs:
version: 6.0.202 version: 7.0.100-rc.2.22477.23
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'
inputs: inputs:
script: | script: |
dotnet workload install android ios dotnet workload install android ios wasm-tools wasm-experimental
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Nuke' displayName: 'Install Nuke'
inputs: inputs:
script: | script: |
dotnet tool install --global Nuke.GlobalTool --version 0.24.0 dotnet tool install --global Nuke.GlobalTool --version 6.2.1
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Run Nuke' 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()] [CmdletBinding()]
Param( Param(
#[switch]$CustomParam,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$BuildArguments [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 $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
########################################################################### ###########################################################################
@ -15,15 +14,15 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
########################################################################### ###########################################################################
$BuildProjectFile = "$PSScriptRoot\nukebuild\_build.csproj" $BuildProjectFile = "$PSScriptRoot\nukebuild\_build.csproj"
$TempDirectory = "$PSScriptRoot\\.tmp" $TempDirectory = "$PSScriptRoot\\.nuke\temp"
$DotNetGlobalFile = "$PSScriptRoot\\global.json" $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" $DotNetChannel = "Current"
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
$env:NUGET_XMLDOC_MODE = "skip" $env:DOTNET_MULTILEVEL_LOOKUP = 0
########################################################################### ###########################################################################
# EXECUTION # EXECUTION
@ -34,38 +33,37 @@ function ExecSafe([scriptblock] $cmd) {
if ($LASTEXITCODE) { exit $LASTEXITCODE } if ($LASTEXITCODE) { exit $LASTEXITCODE }
} }
# If global.json exists, load expected version # If dotnet CLI is installed globally and it matches requested version, use for execution
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 ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` 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 $env:DOTNET_EXE = (Get-Command "dotnet").Path
} }
else { else {
$DotNetDirectory = "$TempDirectory\dotnet-win"
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
# Download install script # Download install script
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" $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) (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 # Install by channel or version
$DotNetDirectory = "$TempDirectory\dotnet-win"
if (!(Test-Path variable:DotNetVersion)) { if (!(Test-Path variable:DotNetVersion)) {
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
} else { } else {
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
} }
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
$env:PATH="$DotNetDirectory;$env:PATH"
} }
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 #!/usr/bin/env bash
echo $(bash --version 2>&1 | head -n 1) 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
set -eo pipefail set -eo pipefail
SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) 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" 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_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=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"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<PackageReference Include="HarfBuzzSharp" 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" /> <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" /> <PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2.1-preview.108" />
</ItemGroup> </ItemGroup>
</Project> </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"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<PackageReference Include="ReactiveUI" Version="13.2.10" /> <PackageReference Include="ReactiveUI" Version="18.3.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

2
build/SharedVersion.props

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Product>Avalonia</Product> <Product>Avalonia</Product>
<Version>0.10.999</Version> <Version>11.0.999</Version>
<Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright> <Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl> <PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl> <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"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<PackageReference Include="SkiaSharp" 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-preview.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-preview.1" /> <PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

12
dirs.proj

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

2
global.json

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

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

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

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

@ -91,8 +91,6 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
if(_parent != nullptr) if(_parent != nullptr)
{ {
_parent->_children.remove(this); _parent->_children.remove(this);
_parent->BringToFront();
} }
auto cparent = dynamic_cast<WindowImpl *>(parent); auto cparent = dynamic_cast<WindowImpl *>(parent);
@ -121,7 +119,7 @@ void WindowImpl::BringToFront()
{ {
if(Window != nullptr) if(Window != nullptr)
{ {
if (![Window isMiniaturized]) if ([Window isVisible] && ![Window isMiniaturized])
{ {
if(IsDialog()) 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.DotNet.DotNetTasks;
using static Nuke.Common.Tools.Xunit.XunitTasks; using static Nuke.Common.Tools.Xunit.XunitTasks;
using static Nuke.Common.Tools.VSWhere.VSWhereTasks; using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
using MicroCom.CodeGenerator;
/* /*
Before editing this file, install support plugin for your IDE, Before editing this file, install support plugin for your IDE,
@ -36,25 +37,6 @@ partial class Build : NukeBuild
{ {
[Solution("Avalonia.sln")] readonly Solution Solution; [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; } BuildParameters Parameters { get; set; }
protected override void OnBuildInitialized() protected override void OnBuildInitialized()
{ {
@ -89,25 +71,28 @@ partial class Build : NukeBuild
} }
ExecWait("dotnet version:", "dotnet", "--info"); ExecWait("dotnet version:", "dotnet", "--info");
ExecWait("dotnet workloads:", "dotnet", "workload list"); ExecWait("dotnet workloads:", "dotnet", "workload list");
Information("Processor count: " + Environment.ProcessorCount);
Information("Available RAM: " + GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 0x100000 + "MB");
} }
IReadOnlyCollection<Output> MsBuildCommon( DotNetConfigHelper ApplySettingCore(DotNetConfigHelper c)
string projectFile,
Configure<MSBuildSettings> configurator = null)
{ {
return MSBuild(c => c if (Parameters.IsRunningOnAzure)
.SetProjectFile(projectFile) c.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64"));
// This is required for VS2019 image on Azure Pipelines c.AddProperty("PackageVersion", Parameters.Version)
.When(Parameters.IsRunningOnWindows &&
Parameters.IsRunningOnAzure, _ => _
.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64")))
.AddProperty("PackageVersion", Parameters.Version)
.AddProperty("iOSRoslynPathHackRequired", true) .AddProperty("iOSRoslynPathHackRequired", true)
.SetProcessToolPath(MsBuildExe.Value)
.SetConfiguration(Parameters.Configuration) .SetConfiguration(Parameters.Configuration)
.SetVerbosity(MSBuildVerbosity.Minimal) .SetVerbosity(DotNetVerbosity.Minimal);
.Apply(configurator)); 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(() => Target Clean => _ => _.Executes(() =>
{ {
@ -149,20 +134,11 @@ partial class Build : NukeBuild
Target Compile => _ => _ Target Compile => _ => _
.DependsOn(Clean, CompileNative) .DependsOn(Clean, CompileNative)
.DependsOn(CompileHtmlPreviewer) .DependsOn(CompileHtmlPreviewer)
.Executes(async () => .Executes(() =>
{ {
if (Parameters.IsRunningOnWindows) DotNetBuild(c => ApplySetting(c)
MsBuildCommon(Parameters.MSBuildSolution, c => c .SetProjectFile(Parameters.MSBuildSolution)
.SetProcessArgumentConfigurator(a => a.Add("/r")) );
.AddTargets("Build")
);
else
DotNetBuild(c => c
.SetProjectFile(Parameters.MSBuildSolution)
.AddProperty("PackageVersion", Parameters.Version)
.SetConfiguration(Parameters.Configuration)
);
}); });
void RunCoreTest(string projectName) void RunCoreTest(string projectName)
@ -182,14 +158,13 @@ partial class Build : NukeBuild
Information($"Running for {projectName} ({fw}) ..."); Information($"Running for {projectName} ({fw}) ...");
DotNetTest(c => c DotNetTest(c => ApplySetting(c)
.SetProjectFile(project) .SetProjectFile(project)
.SetConfiguration(Parameters.Configuration)
.SetFramework(fw) .SetFramework(fw)
.EnableNoBuild() .EnableNoBuild()
.EnableNoRestore() .EnableNoRestore()
.When(Parameters.PublishTestResults, _ => _ .When(Parameters.PublishTestResults, _ => _
.SetLogger("trx") .SetLoggers("trx")
.SetResultsDirectory(Parameters.TestResultsRoot))); .SetResultsDirectory(Parameters.TestResultsRoot)));
} }
} }
@ -241,8 +216,6 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.DesignerSupport.Tests"); RunCoreTest("Avalonia.DesignerSupport.Tests");
}); });
[PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
Target RunLeakTests => _ => _ Target RunLeakTests => _ => _
.OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile) .DependsOn(Compile)
@ -250,12 +223,9 @@ partial class Build : NukeBuild
{ {
void DoMemoryTest() void DoMemoryTest()
{ {
var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"; RunCoreTest("Avalonia.LeakTests");
DotMemoryUnit(
$"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}",
timeout: 120_000);
} }
ControlFlow.ExecuteWithRetry(DoMemoryTest, waitInSeconds: 3); ControlFlow.ExecuteWithRetry(DoMemoryTest, delay: TimeSpan.FromMilliseconds(3));
}); });
Target ZipFiles => _ => _ Target ZipFiles => _ => _
@ -263,19 +233,7 @@ partial class Build : NukeBuild
.Executes(() => .Executes(() =>
{ {
var data = Parameters; 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.ZipNuGetArtifacts, data.NugetRoot);
Zip(data.ZipTargetControlCatalogNetCoreDir, pathToPublish);
}); });
Target CreateIntermediateNugetPackages => _ => _ Target CreateIntermediateNugetPackages => _ => _
@ -283,15 +241,7 @@ partial class Build : NukeBuild
.After(RunTests) .After(RunTests)
.Executes(() => .Executes(() =>
{ {
if (Parameters.IsRunningOnWindows) DotNetPack(c => ApplySetting(c).SetProject(Parameters.MSBuildSolution));
MsBuildCommon(Parameters.MSBuildSolution, c => c
.AddTargets("Pack"));
else
DotNetPack(c => c
.SetProject(Parameters.MSBuildSolution)
.SetConfiguration(Parameters.Configuration)
.AddProperty("PackageVersion", Parameters.Version));
}); });
Target CreateNugetPackages => _ => _ Target CreateNugetPackages => _ => _
@ -329,6 +279,14 @@ partial class Build : NukeBuild
.DependsOn(Package) .DependsOn(Package)
.DependsOn(ZipFiles); .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() => public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) RuntimeInformation.IsOSPlatform(OSPlatform.Windows)

8
nukebuild/BuildParameters.cs

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

12
nukebuild/BuildTasksPatcher.cs

@ -17,8 +17,12 @@ public class BuildTasksPatcher
{ {
if (entry.Name == "Avalonia.Build.Tasks.dll") 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"; 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(); var patched = new MemoryStream();
try try
{ {
@ -57,10 +61,8 @@ public class BuildTasksPatcher
{ {
try try
{ {
if (File.Exists(temp)) if(Directory.Exists(tempDir))
File.Delete(temp); Directory.Delete(tempDir, true);
if (File.Exists(output))
File.Delete(output);
} }
catch 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 (fsEntry is FileInfo)
{ {
#if NET6
var relPath = Path.GetRelativePath(rootPath, fsEntry.FullName); var relPath = Path.GetRelativePath(rootPath, fsEntry.FullName);
#else
var relPath = GetRelativePath(rootPath, fsEntry.FullName);
#endif
AddFile(fsEntry.FullName, relPath); 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 class NumergeNukeLogger : INumergeLogger
{ {
public void Log(NumergeLogLevel level, string message) public void Log(NumergeLogLevel level, string message)

41
nukebuild/_build.csproj

@ -1,41 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace></RootNamespace> <RootNamespace></RootNamespace>
<IsPackable>False</IsPackable> <IsPackable>False</IsPackable>
<NoWarn>CS0649;CS0169</NoWarn> <NoWarn>CS0649;CS0169;SYSLIB0011</NoWarn>
<NukeTelemetryVersion>1</NukeTelemetryVersion>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<Import Project="..\build\JetBrains.dotMemoryUnit.props" /> <Import Project="..\build\JetBrains.dotMemoryUnit.props" />
<ItemGroup> <ItemGroup>
<PackageReference Include="Nuke.Common" Version="5.0.0" /> <PackageReference Include="Nuke.Common" Version="6.2.1" />
<PackageReference Include="xunit.runner.console" Version="2.3.1" />
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " /> <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" /> <PackageReference Include="MicroCom.CodeGenerator" Version="0.10.4" />
<!-- Keep in sync with Avalonia.Build.Tasks --> <!-- 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>
<ItemGroup> <ItemGroup>
<NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" /> <NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" />
<NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" /> <NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
<None Remove="*.csproj.DotSettings;*.ref.*.txt" />
<!-- Common build related files --> <!-- 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 Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" /> <Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup> </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> </Project>

1
nukebuild/il-repack

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

3
packages/Avalonia/AvaloniaBuildTasks.targets

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

12
samples/ControlCatalog.Android/MainActivity.cs

@ -5,16 +5,8 @@ using Avalonia.Android;
namespace ControlCatalog.Android namespace ControlCatalog.Android
{ {
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
public class MainActivity : AvaloniaActivity<App> 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.App;
using Android.Content; using Android.Content;
using Android.Content.PM;
using Android.OS; using Android.OS;
using Avalonia.Android;
namespace ControlCatalog.Android namespace ControlCatalog.Android
{ {
[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)] [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) protected override void OnCreate(Bundle? savedInstanceState)
{ {
base.OnCreate(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.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http @using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using ControlCatalog.Web @using ControlCatalog.Blazor.Web.Shared
@using ControlCatalog.Web.Shared
@using SkiaSharp @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 href="" class="reload">Reload</a>
<a class="dismiss">🗙</a> <a class="dismiss">🗙</a>
</div> </div>
<script src="js/app.js"></script>
<script src="_framework/blazor.webassembly.js"></script> <script src="_framework/blazor.webassembly.js"></script>
</body> </body>
</html> </html>

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

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

4
samples/ControlCatalog.NetCore/Program.cs

@ -115,10 +115,6 @@ namespace ControlCatalog.NetCore
UseDBusMenu = true, UseDBusMenu = true,
EnableIme = true EnableIme = true
}) })
.With(new Win32PlatformOptions
{
EnableMultitouch = true
})
.UseSkia() .UseSkia()
.AfterSetup(builder => .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> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<!--Temporal hack that fixes compilation in VS--> <WasmMainJSPath>main.js</WasmMainJSPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <OutputType>Exe</OutputType>
<EmccTotalMemory>16777216</EmccTotalMemory> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport> <MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData> <WasmBuildNative>true</WasmBuildNative>
<EmccFlags>-sVERBOSE -sERROR_ON_UNDEFINED_SYMBOLS=0</EmccFlags>
</PropertyGroup> </PropertyGroup>
<!-- In debug, make builds faster by reducing optimizations --> <PropertyGroup Condition="'$(Configuration)'=='Release'">
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> <RunAOTCompilation>true</RunAOTCompilation>
<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>
<PublishTrimmed>true</PublishTrimmed> <PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode> <TrimMode>full</TrimMode>
<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols> <WasmBuildNative>true</WasmBuildNative>
<InvariantGlobalization>true</InvariantGlobalization>
<EmccCompileOptimizationFlag>-O2</EmccCompileOptimizationFlag>
<EmccLinkOptimizationFlag>-O2</EmccLinkOptimizationFlag>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.0" /> <TrimmerRootDescriptor Include="Roots.xml" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.0" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" /> <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" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\ReferenceCoreLibraries.props" /> <ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" /> <WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraFilesToDeploy Include="main.js" />
<Import Project="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.targets" /> <WasmExtraFilesToDeploy Include="embed.js" />
<Import Project="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.CompilationTuning.props" /> <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> </Project>

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

@ -1,34 +1,42 @@
using System; using System;
using System.Runtime.InteropServices.JavaScript;
using Avalonia;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Web.Blazor; using Avalonia.Web;
using ControlCatalog.Pages; using ControlCatalog.Pages;
using Microsoft.JSInterop;
namespace ControlCatalog.Web; namespace ControlCatalog.Web;
public class EmbedSampleWeb : INativeDemoControl public class EmbedSampleWeb : INativeDemoControl
{ {
public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault) public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault)
{ {
var runtime = AvaloniaLocator.Current.GetRequiredService<IJSInProcessRuntime>();
if (isSecond) if (isSecond)
{ {
var iframe = runtime.Invoke<IJSInProcessObjectReference>("document.createElement", "iframe"); var iframe = EmbedInterop.CreateElement("iframe");
iframe.InvokeVoid("setAttribute", "src", "https://www.youtube.com/embed/kZCIporjJ70"); iframe.SetProperty("src", "https://www.youtube.com/embed/kZCIporjJ70");
return new JSObjectControlHandle(iframe); return new JSObjectControlHandle(iframe);
} }
else else
{ {
// window.createAppButton source is defined in "app.js" file. var defaultHandle = (JSObjectControlHandle)createDefault();
var button = runtime.Invoke<IJSInProcessObjectReference>("window.createAppButton");
_ = 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.Runtime.Versioning;
using System.Net.Http; using Avalonia;
using System.Threading.Tasks; using Avalonia.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using ControlCatalog;
using Microsoft.Extensions.DependencyInjection;
using ControlCatalog.Web; 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) public static AppBuilder BuildAvaloniaApp()
{ => AppBuilder.Configure<App>();
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
return builder;
}
} }

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 () { export function addAppButton(parent) {
var button = document.createElement('button'); var button = globalThis.document.createElement('button');
button.innerText = 'Hello world'; button.innerText = 'Hello world';
var clickCount = 0; var clickCount = 0;
button.onclick = () => { button.onclick = () => {
clickCount++; clickCount++;
button.innerText = 'Click count ' + clickCount; button.innerText = 'Click count ' + clickCount;
}; };
parent.appendChild(button);
return 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>iossimulator-x64</RuntimeIdentifier>
<!-- <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>--> <!-- <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>-->
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodesignKey>iPhone Developer</CodesignKey>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" /> <ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />

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" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.DecoratedWindow" x:Class="ControlCatalog.DecoratedWindow"
Title="Avalonia Control Gallery" 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.Menu>
<NativeMenu> <NativeMenu>
<NativeMenuItem Header="Decorated"> <NativeMenuItem Header="Decorated">

3
samples/ControlCatalog/MainView.xaml

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

11
samples/ControlCatalog/MainView.xaml.cs

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

6
samples/ControlCatalog/MainWindow.xaml

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

8
samples/ControlCatalog/Models/Person.cs

@ -85,7 +85,7 @@ namespace ControlCatalog.Models
} }
else else
{ {
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList)) if (_errorLookup.TryGetValue(propertyName, out var errorList))
{ {
errorList.Clear(); errorList.Clear();
errorList.Add(error!); errorList.Add(error!);
@ -114,12 +114,12 @@ namespace ControlCatalog.Models
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 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; return errorList;
else 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>
<StackPanel> <StackPanel>
<TextBlock Text="MinimumPopulateDelay: 1s" /> <TextBlock Text="MinimumPopulateDelay: 1s" />
<AutoCompleteBox MinimumPopulateDelay="1" /> <AutoCompleteBox MinimumPopulateDelay="00:00:01" />
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="MaxDropDownHeight: 60" /> <TextBlock Text="MaxDropDownHeight: 60" />

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

@ -1,8 +1,6 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Markup;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Data;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -161,23 +159,23 @@ namespace ControlCatalog.Pages
private bool LastWordContains(string? searchText, string? item) private bool LastWordContains(string? searchText, string? item)
{ {
var words = searchText?.Split(' ') ?? Array.Empty<string>(); 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) for (var i = 0; i < words.Length; ++i)
{ {
var word = words[i]; var word = words[i];
for (var j = 0; word is { } && j < options.Length; ++j) for (var j = 0; word is { } && j < options.Length; ++j)
{ {
var option = options[j]; if (options[i] is { } option)
if (option == null)
continue;
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; 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) public void OnSpin(object sender, SpinEventArgs e)
{ {
var spinner = (ButtonSpinner)sender; var spinner = (ButtonSpinner)sender;
var txtBox = (TextBlock)spinner.Content;
int value = Array.IndexOf(_mountains, txtBox?.Text); if (spinner.Content is TextBlock txtBox)
if (e.Direction == SpinDirection.Increase) {
value++; int value = Array.IndexOf(_mountains, txtBox.Text);
else if (e.Direction == SpinDirection.Increase)
value--; value++;
else
value--;
if (value < 0) if (value < 0)
value = _mountains.Length - 1; value = _mountains.Length - 1;
else if (value >= _mountains.Length) else if (value >= _mountains.Length)
value = 0; value = 0;
txtBox.Text = _mountains[value];
}
txtBox.Text = _mountains[value];
} }
private readonly string[] _mountains = new[] private readonly string[] _mountains = new[]

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

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

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

@ -23,55 +23,79 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this); 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(); if (Application.Current!.Clipboard is { } clipboard)
dataObject.Set(DataFormats.Text, ClipboardContent.Text ?? string.Empty); {
await Application.Current.Clipboard.SetDataObjectAsync(dataObject); 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 (Application.Current!.Clipboard is { } clipboard)
if (files.Length == 0)
{ {
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>; if (Application.Current!.Clipboard is { } clipboard)
ClipboardContent.Text = fiels != null ? string.Join(Environment.NewLine, fiels) : string.Empty; {
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) private async void GetFormats(object sender, RoutedEventArgs args)
{ {
var formats = await Application.Current.Clipboard.GetFormatsAsync(); if (Application.Current!.Clipboard is { } clipboard)
ClipboardContent.Text = string.Join(Environment.NewLine, formats); {
var formats = await clipboard.GetFormatsAsync();
ClipboardContent.Text = string.Join(Environment.NewLine, formats);
}
} }
private async void Clear(object sender, RoutedEventArgs args) 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:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 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:primitives="clr-namespace:Avalonia.Controls.Primitives;assembly=Avalonia.Controls"
xmlns:pc="clr-namespace:Avalonia.Controls.Primitives.Converters;assembly=Avalonia.Controls.ColorPicker" xmlns:pc="clr-namespace:Avalonia.Controls.Primitives.Converters;assembly=Avalonia.Controls.ColorPicker"
mc:Ignorable="d" mc:Ignorable="d"
@ -10,16 +11,22 @@
x:Class="ControlCatalog.Pages.ColorPickerPage"> x:Class="ControlCatalog.Pages.ColorPickerPage">
<UserControl.Resources> <UserControl.Resources>
<pc:ThirdComponentConverter x:Key="ThirdComponent" />
</UserControl.Resources> </UserControl.Resources>
<Grid ColumnDefinitions="Auto,10,Auto,10,Auto" <Grid x:Name="LayoutRoot"
ColumnDefinitions="Auto,10,Auto"
RowDefinitions="Auto,Auto"> RowDefinitions="Auto,Auto">
<ColorPicker Grid.Column="0"
Grid.Row="1" />
<ColorView Grid.Column="0" <ColorView Grid.Column="0"
Grid.Row="0" Grid.Row="0"
ColorSpectrumShape="Ring" /> 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 Grid.Column="2"
Grid.Row="0" Grid.Row="0"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
@ -47,11 +54,8 @@
ColorModel="Hsva" ColorModel="Hsva"
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />
<ColorPreviewer Grid.Row="5" <ColorPreviewer Grid.Row="5"
IsAccentColorsVisible="True" IsAccentColorsVisible="False"
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" />
</Grid> </Grid>
<Grid Grid.Column="4"
Grid.Row="0">
</Grid>
</Grid> </Grid>
</UserControl> </UserControl>

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

@ -1,6 +1,8 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
@ -9,6 +11,20 @@ namespace ControlCatalog.Pages
public ColorPickerPage() public ColorPickerPage()
{ {
InitializeComponent(); 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() private void InitializeComponent()

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

@ -17,7 +17,7 @@ namespace ControlCatalog.Pages
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); 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.Items = FontManager.Current.GetInstalledFontFamilyNames().Select(x => new FontFamily(x));
fontComboBox.SelectedIndex = 0; fontComboBox.SelectedIndex = 0;
} }

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

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

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

@ -52,13 +52,13 @@ namespace ControlCatalog.Pages
base.OnDataContextChanged(e); 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"); 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) 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(); _textBox.ContextFlyout?.Hide();
} }
public void CustomContextRequested(object sender, ContextRequestedEventArgs e) public void CustomContextRequested(object? sender, ContextRequestedEventArgs e)
{ {
var border = (Border)sender; if (sender is Border border && border.Child is TextBlock textBlock)
var textBlock = (TextBlock)border.Child; {
textBlock.Text = e.TryGetPosition(border, out var point)
textBlock.Text = e.TryGetPosition(border, out var point) ? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}"
? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}" : "Context was requested without pointer";
: "Context was requested without pointer"; e.Handled = true;
e.Handled = true; }
} }
private void InitializeComponent() private void InitializeComponent()

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

@ -35,30 +35,31 @@ namespace ControlCatalog.Pages
base.OnDataContextChanged(e); 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"); 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) if (e is CancelEventArgs cancelArgs)
{ {
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox"); 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; if (sender is Border border && border.Child is TextBlock textBlock)
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;
}
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() private void InitializeComponent()

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

@ -62,7 +62,7 @@ namespace ControlCatalog.Pages
addButton.Click += (a, b) => collectionView3.AddNew(); 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; e.Row.Header = e.Row.GetIndex() + 1;
} }
@ -74,7 +74,7 @@ namespace ControlCatalog.Pages
private class ReversedStringComparer : IComparer<object>, IComparer 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) if (x is string left && y is string right)
{ {

24
samples/ControlCatalog/Pages/DateTimePickerPage.xaml

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

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

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

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

@ -1,9 +1,9 @@
using Avalonia.Controls; using System;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
@ -27,9 +27,9 @@ namespace ControlCatalog.Pages
void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects) void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
{ {
var dragMe = this.Get<Border>("DragMe" + suffix); 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(); var dragData = new DataObject();
factory(dragData); 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") if (e.Source is Control c && c.Name == "MoveTarget")
{ {
@ -73,7 +73,7 @@ namespace ControlCatalog.Pages
e.DragEffects = DragDropEffects.None; 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") if (e.Source is Control c && c.Name == "MoveTarget")
{ {
@ -83,11 +83,11 @@ namespace ControlCatalog.Pages
{ {
e.DragEffects = e.DragEffects & (DragDropEffects.Copy); e.DragEffects = e.DragEffects & (DragDropEffects.Copy);
} }
if (e.Data.Contains(DataFormats.Text)) if (e.Data.Contains(DataFormats.Text))
_DropState.Text = e.Data.GetText(); _DropState.Text = e.Data.GetText();
else if (e.Data.Contains(DataFormats.FileNames)) 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)) else if (e.Data.Contains(CustomFormat))
_DropState.Text = "Custom: " + e.Data.Get(CustomFormat); _DropState.Text = "Custom: " + e.Data.Get(CustomFormat);
} }

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

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

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

@ -123,7 +123,7 @@ namespace ControlCatalog.Pages
element.BringIntoView(); 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) 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) 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); 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)); 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); ScrollTo(_selectedIndex);
} }

16
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:sys="clr-namespace:System;assembly=netstandard"
xmlns:converter="clr-namespace:ControlCatalog.Converter"
x:Class="ControlCatalog.Pages.NumericUpDownPage"> x:Class="ControlCatalog.Pages.NumericUpDownPage">
<StackPanel Orientation="Vertical" Spacing="4" <StackPanel Orientation="Vertical" Spacing="4"
MaxWidth="800"> MaxWidth="800">
@ -54,11 +55,11 @@
<Grid Grid.Row="0" Grid.Column="2" Margin="8" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, Auto"> <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> <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}" <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> <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}" <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> <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" <NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding #upDown.Increment}" VerticalAlignment="Center"
@ -97,6 +98,17 @@
</DataValidationErrors.Error> </DataValidationErrors.Error>
</NumericUpDown> </NumericUpDown>
</StackPanel> </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> </WrapPanel>
</StackPanel> </StackPanel>

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

@ -2,9 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using MiniMvvm; using MiniMvvm;
@ -29,7 +27,7 @@ namespace ControlCatalog.Pages
public class NumbersPageViewModel : ViewModelBase public class NumbersPageViewModel : ViewModelBase
{ {
private IList<FormatObject>? _formats; private IList<FormatObject>? _formats;
private FormatObject _selectedFormat; private FormatObject? _selectedFormat;
private IList<Location>? _spinnerLocations; private IList<Location>? _spinnerLocations;
private double _doubleValue; 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)) .Where(c => new[] { "en-US", "en-GB", "fr-FR", "ar-DZ", "zh-CH", "cs-CZ" }.Contains(c.Name))
.ToArray(); .ToArray();
public FormatObject SelectedFormat public FormatObject? SelectedFormat
{ {
get { return _selectedFormat; } get { return _selectedFormat; }
set { this.RaiseAndSetIfChanged(ref _selectedFormat, value); } 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); set => SetAndRaise(DiscoProperty, ref _disco, value);
} }
private string _info; private string _info = string.Empty;
public static readonly DirectProperty<OpenGlPageControl, string> InfoProperty = public static readonly DirectProperty<OpenGlPageControl, string> InfoProperty =
AvaloniaProperty.RegisterDirect<OpenGlPageControl, string>("Info", o => o.Info, (o, v) => o.Info = v); AvaloniaProperty.RegisterDirect<OpenGlPageControl, string>("Info", o => o.Info, (o, v) => o.Info = v);
@ -205,7 +205,7 @@ namespace ControlCatalog.Pages
public OpenGlPageControl() public OpenGlPageControl()
{ {
var name = typeof(OpenGlPage).Assembly.GetManifestResourceNames().First(x => x.Contains("teapot.bin")); 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()]; var buf = new byte[sr.ReadInt32()];
sr.Read(buf, 0, buf.Length); sr.Read(buf, 0, buf.Length);
@ -345,7 +345,7 @@ namespace ControlCatalog.Pages
0.01f, 1000); 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 model = Matrix4x4.CreateFromYawPitchRoll(_yaw, _pitch, _roll);
var modelLoc = GL.GetUniformLocationString(_shaderProgram, "uModel"); var modelLoc = GL.GetUniformLocationString(_shaderProgram, "uModel");
var viewLoc = GL.GetUniformLocationString(_shaderProgram, "uView"); var viewLoc = GL.GetUniformLocationString(_shaderProgram, "uView");

4
samples/ControlCatalog/Pages/PointerCanvas.cs

@ -174,9 +174,9 @@ Twist: {_lastProperties?.Twist}";
var lastPointer = e.GetCurrentPoint(this); var lastPointer = e.GetCurrentPoint(this);
_lastProperties = lastPointer.Properties; _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) if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)

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

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

16
samples/ControlCatalog/Pages/ScreenPage.cs

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

8
samples/ControlCatalog/ViewModels/ContextPageViewModel.cs

@ -53,14 +53,14 @@ namespace ControlCatalog.ViewModels
var window = View?.GetVisualRoot() as Window; var window = View?.GetVisualRoot() as Window;
if (window == null) if (window == null)
return; 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) 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; var window = View?.GetVisualRoot() as Window;
if (window == null) if (window == null)
return; return;
var dialog = new OpenFileDialog(); var result = await window.StorageProvider.OpenFilePickerAsync(new Avalonia.Platform.Storage.FilePickerOpenOptions() { AllowMultiple = true });
var result = await dialog.ShowAsync(window);
if (result != null) 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); PageTransitions[3].Transition = new PageSlide(TimeSpan.FromMilliseconds(Duration), PageSlide.SlideAxis.Vertical);
var compositeTransition = new CompositePageTransition(); var compositeTransition = new CompositePageTransition();
compositeTransition.PageTransitions.Add(PageTransitions[1].Transition); compositeTransition.PageTransitions.Add(PageTransitions[1].Transition!);
compositeTransition.PageTransitions.Add(PageTransitions[2].Transition); compositeTransition.PageTransitions.Add(PageTransitions[2].Transition!);
compositeTransition.PageTransitions.Add(PageTransitions[3].Transition); compositeTransition.PageTransitions.Add(PageTransitions[3].Transition!);
PageTransitions[4].Transition = compositeTransition; PageTransitions[4].Transition = compositeTransition;
PageTransitions[5].Transition = new CustomTransition(TimeSpan.FromMilliseconds(Duration)); 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.Collections.Generic;
using System.Linq; using System.Linq;
using Avalonia; using Avalonia;
using Avalonia.Automation;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Microsoft.CodeAnalysis;
namespace IntegrationTestApp namespace IntegrationTestApp
{ {
@ -31,20 +32,23 @@ namespace IntegrationTestApp
private void InitializeViewMenu() private void InitializeViewMenu()
{ {
var mainTabs = this.FindControl<TabControl>("MainTabs"); var mainTabs = this.Get<TabControl>("MainTabs");
var viewMenu = (NativeMenuItem)NativeMenu.GetMenu(this).Items[1]; 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!, var menuItem = new NativeMenuItem
IsChecked = tabItem.IsSelected, {
ToggleType = NativeMenuItemToggleType.Radio, Header = (string)tabItem.Header!,
}; IsChecked = tabItem.IsSelected,
ToggleType = NativeMenuItemToggleType.Radio,
menuItem.Click += (s, e) => tabItem.IsSelected = true; };
viewMenu.Menu.Items.Add(menuItem);
menuItem.Click += (s, e) => tabItem.IsSelected = true;
viewMenu?.Menu?.Items.Add(menuItem);
}
} }
} }
@ -61,6 +65,17 @@ namespace IntegrationTestApp
WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex, 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) if (size.HasValue)
{ {
window.Width = size.Value.Width; window.Width = size.Value.Width;
@ -99,6 +114,7 @@ namespace IntegrationTestApp
foreach (var window in lifetime.Windows) foreach (var window in lifetime.Windows)
{ {
window.Show();
if (window.WindowState == WindowState.Minimized) if (window.WindowState == WindowState.Minimized)
window.WindowState = WindowState.Normal; window.WindowState = WindowState.Normal;
} }
@ -106,8 +122,8 @@ namespace IntegrationTestApp
private void MenuClicked(object? sender, RoutedEventArgs e) private void MenuClicked(object? sender, RoutedEventArgs e)
{ {
var clickedMenuItemTextBlock = this.FindControl<TextBlock>("ClickedMenuItem"); var clickedMenuItemTextBlock = this.Get<TextBlock>("ClickedMenuItem");
clickedMenuItemTextBlock.Text = ((MenuItem)sender!).Header.ToString(); clickedMenuItemTextBlock.Text = (sender as MenuItem)?.Header?.ToString();
} }
private void OnButtonClick(object? sender, RoutedEventArgs e) private void OnButtonClick(object? sender, RoutedEventArgs e)
@ -115,13 +131,13 @@ namespace IntegrationTestApp
var source = e.Source as Button; var source = e.Source as Button;
if (source?.Name == "ComboBoxSelectionClear") if (source?.Name == "ComboBoxSelectionClear")
this.FindControl<ComboBox>("BasicComboBox").SelectedIndex = -1; this.Get<ComboBox>("BasicComboBox").SelectedIndex = -1;
if (source?.Name == "ComboBoxSelectFirst") if (source?.Name == "ComboBoxSelectFirst")
this.FindControl<ComboBox>("BasicComboBox").SelectedIndex = 0; this.Get<ComboBox>("BasicComboBox").SelectedIndex = 0;
if (source?.Name == "ListBoxSelectionClear") if (source?.Name == "ListBoxSelectionClear")
this.FindControl<ListBox>("BasicListBox").SelectedIndex = -1; this.Get<ListBox>("BasicListBox").SelectedIndex = -1;
if (source?.Name == "MenuClickedMenuItemReset") if (source?.Name == "MenuClickedMenuItemReset")
this.FindControl<TextBlock>("ClickedMenuItem").Text = "None"; this.Get<TextBlock>("ClickedMenuItem").Text = "None";
if (source?.Name == "ShowWindow") if (source?.Name == "ShowWindow")
ShowWindow(); ShowWindow();
if (source?.Name == "SendToBack") if (source?.Name == "SendToBack")

7
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -3,7 +3,7 @@
x:Class="IntegrationTestApp.ShowWindowTest" x:Class="IntegrationTestApp.ShowWindowTest"
Name="SecondaryWindow" Name="SecondaryWindow"
Title="Show Window Test"> 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> <Label Grid.Column="0" Grid.Row="1">Client Size</Label>
<TextBox Name="ClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True" <TextBox Name="ClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True"
Text="{Binding ClientSize, Mode=OneWay}"/> Text="{Binding ClientSize, Mode=OneWay}"/>
@ -31,5 +31,10 @@
<ComboBoxItem>Maximized</ComboBoxItem> <ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>Fullscreen</ComboBoxItem> <ComboBoxItem>Fullscreen</ComboBoxItem>
</ComboBox> </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> </Grid>
</Window> </Window>

28
samples/IntegrationTestApp/ShowWindowTest.axaml.cs

@ -1,21 +1,32 @@
using System; using System;
using System.Runtime.InteropServices;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Rendering; using Avalonia.Threading;
namespace IntegrationTestApp namespace IntegrationTestApp
{ {
public class ShowWindowTest : Window public class ShowWindowTest : Window
{ {
private readonly DispatcherTimer? _timer;
private readonly TextBox? _orderTextBox;
public ShowWindowTest() public ShowWindowTest()
{ {
InitializeComponent(); InitializeComponent();
DataContext = this; DataContext = this;
PositionChanged += (s, e) => this.GetControl<TextBox>("Position").Text = $"{Position}"; 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() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
@ -36,5 +47,16 @@ namespace IntegrationTestApp
ownerRect.Text = $"{owner.Position}, {PixelSize.FromSize(owner.FrameSize!.Value, scaling)}"; 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