diff --git a/.editorconfig b/.editorconfig
index 128b6f1712..179491eece 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -134,6 +134,9 @@ csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
space_within_single_line_array_initializer_braces = true
+#Net Analyzer
+dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed.
+
# Wrapping preferences
csharp_wrap_before_ternary_opsigns = false
diff --git a/.gitignore b/.gitignore
index 84faae1806..61a3b53de1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -215,3 +215,4 @@ 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
diff --git a/.gitmodules b/.gitmodules
index 2d11fdfa9e..032bc879cc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"]
path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
url = https://github.com/kekekeks/XamlX.git
+[submodule "nukebuild/il-repack"]
+ path = nukebuild/il-repack
+ url = https://github.com/Gillibald/il-repack
diff --git a/.nuke b/.nuke
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
new file mode 100644
index 0000000000..5bbc3d6915
--- /dev/null
+++ b/.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"
+ ]
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/.nuke/parameters.json b/.nuke/parameters.json
new file mode 100644
index 0000000000..42521bb7dd
--- /dev/null
+++ b/.nuke/parameters.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "./build.schema.json",
+ "Solution": ""
+}
\ No newline at end of file
diff --git a/Avalonia.sln b/Avalonia.sln
index 68335c672c..c000f56d09 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -90,6 +90,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject
build\ApiDiff.props = build\ApiDiff.props
+ build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props
build\Base.props = build\Base.props
build\Binding.props = build\Binding.props
build\CoreLibraries.props = build\CoreLibraries.props
@@ -102,8 +103,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\Microsoft.CSharp.props = build\Microsoft.CSharp.props
build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
build\Moq.props = build\Moq.props
+ build\NetAnalyzers.props = build\NetAnalyzers.props
build\NetCore.props = build\NetCore.props
build\NetFX.props = build\NetFX.props
+ build\NullableEnable.props = build\NullableEnable.props
build\ReactiveUI.props = build\ReactiveUI.props
build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
build\Rx.props = build\Rx.props
@@ -198,8 +201,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{86A3F706-DC3
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web.Blazor", "src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj", "{25831348-EB2A-483E-9576-E8F6528674A5}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{C08E9894-AA92-426E-BF56-033E262CAD3E}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}"
@@ -212,15 +213,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ColorPick
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{EABE2161-989B-42BF-BD8D-1E34B20C21F1}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevGenerators", "src\tools\DevGenerators\DevGenerators.csproj", "{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevGenerators", "src\tools\DevGenerators\DevGenerators.csproj", "{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web", "src\Web\Avalonia.Web\Avalonia.Web.csproj", "{76D39FF6-6B4F-46C4-93CD-E6FC4665739E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox", "samples\MobileSandbox\MobileSandbox.csproj", "{3B8519C1-2F51-4F12-A348-120AB91D4532}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileSandbox", "samples\MobileSandbox\MobileSandbox.csproj", "{3B8519C1-2F51-4F12-A348-120AB91D4532}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Android", "samples\MobileSandbox.Android\MobileSandbox.Android.csproj", "{C90FE60B-B01E-4F35-91D6-379D6966030F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileSandbox.Android", "samples\MobileSandbox.Android\MobileSandbox.Android.csproj", "{C90FE60B-B01E-4F35-91D6-379D6966030F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.iOS", "samples\MobileSandbox.iOS\MobileSandbox.iOS.csproj", "{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileSandbox.iOS", "samples\MobileSandbox.iOS\MobileSandbox.iOS.csproj", "{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Blazor.Web", "samples\ControlCatalog.Blazor.Web\ControlCatalog.Blazor.Web.csproj", "{6A710364-AE6D-40BD-968B-024311527AC2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{8B3E8405-DE18-4048-A459-9CA4AC3319A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -407,9 +414,7 @@ Global
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.Build.0 = Release|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -478,10 +483,6 @@ Global
{25831348-EB2A-483E-9576-E8F6528674A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.Build.0 = Release|Any CPU
- {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|Any CPU.Build.0 = Release|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -510,6 +511,10 @@ Global
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {76D39FF6-6B4F-46C4-93CD-E6FC4665739E}.Release|Any CPU.Build.0 = Release|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B8519C1-2F51-4F12-A348-120AB91D4532}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -526,6 +531,14 @@ Global
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62D392C9-81CF-487F-92E8-598B2AF3FDCE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6A710364-AE6D-40BD-968B-024311527AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6A710364-AE6D-40BD-968B-024311527AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6A710364-AE6D-40BD-968B-024311527AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6A710364-AE6D-40BD-968B-024311527AC2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -569,6 +582,7 @@ Global
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+ {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
@@ -576,18 +590,19 @@ Global
{676D6BFD-029D-4E43-BFC7-3892265CE251} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{25831348-EB2A-483E-9576-E8F6528674A5} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
- {C08E9894-AA92-426E-BF56-033E262CAD3E} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{EABE2161-989B-42BF-BD8D-1E34B20C21F1} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
- {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
+ {76D39FF6-6B4F-46C4-93CD-E6FC4665739E} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{3B8519C1-2F51-4F12-A348-120AB91D4532} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C90FE60B-B01E-4F35-91D6-379D6966030F} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{FED9A71D-00D7-4F40-A9E4-1229EEA28EEB} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{62D392C9-81CF-487F-92E8-598B2AF3FDCE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {6A710364-AE6D-40BD-968B-024311527AC2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {8B3E8405-DE18-4048-A459-9CA4AC3319A2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
diff --git a/azure-pipelines-integrationtests.yml b/azure-pipelines-integrationtests.yml
index 0b79758c76..ee8abb75c1 100644
--- a/azure-pipelines-integrationtests.yml
+++ b/azure-pipelines-integrationtests.yml
@@ -41,9 +41,9 @@ jobs:
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 6.0.202'
+ displayName: 'Use .NET Core SDK 6.0.401'
inputs:
- version: 6.0.202
+ version: 6.0.401
- task: Windows Application Driver@0
inputs:
@@ -57,6 +57,7 @@ jobs:
projects: 'samples/IntegrationTestApp/IntegrationTestApp.csproj'
- task: DotNetCoreCLI@2
+ retryCountOnTaskFailure: 3
inputs:
command: 'test'
projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj'
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 52fc8db53c..33b2dc670a 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -6,7 +6,6 @@ jobs:
variables:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
-
- task: PowerShell@2
displayName: Get PR Number
inputs:
@@ -31,14 +30,20 @@ jobs:
vmImage: 'ubuntu-20.04'
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 3.1.418'
+ displayName: 'Use .NET Core SDK 6.0.401'
inputs:
- version: 3.1.418
+ version: 6.0.401
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 6.0.202'
+ displayName: 'Use .NET Core SDK 7.0.100-rc.1.22431.12'
+ inputs:
+ version: 7.0.100-rc.1.22431.12
+
+ - task: CmdLine@2
+ displayName: 'Install Workloads'
inputs:
- version: 6.0.202
+ script: |
+ dotnet workload install wasm-tools wasm-experimental
- task: CmdLine@2
displayName: 'Run Build'
@@ -62,22 +67,21 @@ jobs:
vmImage: 'macos-12'
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 3.1.418'
+ displayName: 'Use .NET Core SDK 6.0.401'
inputs:
- version: 3.1.418
+ version: 6.0.401
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 6.0.202'
+ displayName: 'Use .NET Core SDK 7.0.100-rc.1.22431.12'
inputs:
- version: 6.0.202
-
+ version: 7.0.100-rc.1.22431.12
+
- task: CmdLine@2
- displayName: 'Install Mono 5.18'
+ displayName: 'Install Workloads'
inputs:
script: |
- curl -o ./mono.pkg https://download.mono-project.com/archive/5.18.0/macos-10-universal/MonoFramework-MDK-5.18.0.225.macos10.xamarin.universal.pkg
- sudo installer -verbose -pkg ./mono.pkg -target /
-
+ dotnet workload install wasm-tools wasm-experimental
+
- task: CmdLine@2
displayName: 'Generate avalonia-native'
inputs:
@@ -134,26 +138,26 @@ jobs:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 3.1.418'
+ displayName: 'Use .NET Core SDK 6.0.401'
inputs:
- version: 3.1.418
+ version: 6.0.401
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 6.0.202'
+ displayName: 'Use .NET Core SDK 7.0.100-rc.1.22431.12'
inputs:
- version: 6.0.202
+ version: 7.0.100-rc.1.22431.12
- task: CmdLine@2
displayName: 'Install Workloads'
inputs:
script: |
- dotnet workload install android ios
+ dotnet workload install android ios wasm-tools wasm-experimental
- task: CmdLine@2
displayName: 'Install Nuke'
inputs:
script: |
- dotnet tool install --global Nuke.GlobalTool --version 0.24.0
+ dotnet tool install --global Nuke.GlobalTool --version 6.2.1
- task: CmdLine@2
displayName: 'Run Nuke'
diff --git a/build.cmd b/build.cmd
new file mode 100644
index 0000000000..b08cc590f4
--- /dev/null
+++ b/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" %*
diff --git a/build.ps1 b/build.ps1
index 985e8abcee..997e5b423f 100644
--- a/build.ps1
+++ b/build.ps1
@@ -1,13 +1,12 @@
[CmdletBinding()]
Param(
- #[switch]$CustomParam,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$BuildArguments
)
-Write-Output "Windows PowerShell $($Host.Version)"
+Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
-Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 }
+Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################
@@ -15,15 +14,15 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################
$BuildProjectFile = "$PSScriptRoot\nukebuild\_build.csproj"
-$TempDirectory = "$PSScriptRoot\\.tmp"
+$TempDirectory = "$PSScriptRoot\\.nuke\temp"
$DotNetGlobalFile = "$PSScriptRoot\\global.json"
-$DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1"
+$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "Current"
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
-$env:NUGET_XMLDOC_MODE = "skip"
+$env:DOTNET_MULTILEVEL_LOOKUP = 0
###########################################################################
# EXECUTION
@@ -34,38 +33,37 @@ function ExecSafe([scriptblock] $cmd) {
if ($LASTEXITCODE) { exit $LASTEXITCODE }
}
-# If global.json exists, load expected version
-if (Test-Path $DotNetGlobalFile) {
- $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
- if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
- $DotNetVersion = $DotNetGlobal.sdk.version
- }
-}
-
-# If dotnet is installed locally, and expected version is not set or installation matches the expected version
+# If dotnet CLI is installed globally and it matches requested version, use for execution
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
- (!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) {
+ $(dotnet --version) -and $LASTEXITCODE -eq 0) {
$env:DOTNET_EXE = (Get-Command "dotnet").Path
}
else {
- $DotNetDirectory = "$TempDirectory\dotnet-win"
- $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
-
# Download install script
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
- mkdir -force $TempDirectory > $null
+ New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
+ # If global.json exists, load expected version
+ if (Test-Path $DotNetGlobalFile) {
+ $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
+ if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
+ $DotNetVersion = $DotNetGlobal.sdk.version
+ }
+ }
+
# Install by channel or version
+ $DotNetDirectory = "$TempDirectory\dotnet-win"
if (!(Test-Path variable:DotNetVersion)) {
- ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
+ ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
} else {
- ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
+ ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
}
-
- $env:PATH="$DotNetDirectory;$env:PATH"
+ $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
}
-Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
+Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
-ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile -- $BuildArguments }
+ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
+ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
diff --git a/build.sh b/build.sh
index 9532b4fbe0..76919a5351 100755
--- a/build.sh
+++ b/build.sh
@@ -1,16 +1,6 @@
#!/usr/bin/env bash
-echo $(bash --version 2>&1 | head -n 1)
-
-#CUSTOMPARAM=0
-BUILD_ARGUMENTS=()
-for i in "$@"; do
- case $(echo $1 | awk '{print tolower($0)}') in
- # -custom-param) CUSTOMPARAM=1;;
- *) BUILD_ARGUMENTS+=("$1") ;;
- esac
- shift
-done
+bash --version 2>&1 | head -n 1
set -eo pipefail
SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
@@ -20,11 +10,53 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
###########################################################################
BUILD_PROJECT_FILE="$SCRIPT_DIR/nukebuild/_build.csproj"
+TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
+
+DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
+DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
+DOTNET_CHANNEL="Current"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
-export NUGET_XMLDOC_MODE="skip"
+export DOTNET_MULTILEVEL_LOOKUP=0
-dotnet --info
+###########################################################################
+# EXECUTION
+###########################################################################
-dotnet run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]}
+function FirstJsonValue {
+ perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
+}
+
+# If dotnet CLI is installed globally and it matches requested version, use for execution
+if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
+ export DOTNET_EXE="$(command -v dotnet)"
+else
+ # Download install script
+ DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
+ mkdir -p "$TEMP_DIRECTORY"
+ curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
+ chmod +x "$DOTNET_INSTALL_FILE"
+
+ # If global.json exists, load expected version
+ if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
+ DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
+ if [[ "$DOTNET_VERSION" == "" ]]; then
+ unset DOTNET_VERSION
+ fi
+ fi
+
+ # Install by channel or version
+ DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
+ if [[ -z ${DOTNET_VERSION+x} ]]; then
+ "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
+ else
+ "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
+ fi
+ export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
+fi
+
+echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
+
+"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
+"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
diff --git a/build/NetAnalyzers.props b/build/NetAnalyzers.props
new file mode 100644
index 0000000000..dfca9ecf9e
--- /dev/null
+++ b/build/NetAnalyzers.props
@@ -0,0 +1,5 @@
+
+
+ true
+
+
diff --git a/dirs.proj b/dirs.proj
index 47ad0dfd55..a2544ef951 100644
--- a/dirs.proj
+++ b/dirs.proj
@@ -23,12 +23,13 @@
+
-
+
diff --git a/global.json b/global.json
index a6792b05c7..44d4e10dbf 100644
--- a/global.json
+++ b/global.json
@@ -1,8 +1,4 @@
{
- "sdk": {
- "version": "6.0.202",
- "rollForward": "latestFeature"
- },
"msbuild-sdks": {
"Microsoft.Build.Traversal": "1.0.43",
"MSBuild.Sdk.Extras": "3.0.22",
diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index 4bbb667154..7425c344c3 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -23,6 +23,7 @@ using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
using static Nuke.Common.Tools.Xunit.XunitTasks;
using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
+using MicroCom.CodeGenerator;
/*
Before editing this file, install support plugin for your IDE,
@@ -163,7 +164,7 @@ partial class Build : NukeBuild
.EnableNoBuild()
.EnableNoRestore()
.When(Parameters.PublishTestResults, _ => _
- .SetLogger("trx")
+ .SetLoggers("trx")
.SetResultsDirectory(Parameters.TestResultsRoot)));
}
}
@@ -215,8 +216,6 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.DesignerSupport.Tests");
});
- [PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
-
Target RunLeakTests => _ => _
.OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile)
@@ -224,12 +223,9 @@ partial class Build : NukeBuild
{
void DoMemoryTest()
{
- var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll";
- DotMemoryUnit(
- $"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}",
- timeout: 120_000);
+ RunCoreTest("Avalonia.LeakTests");
}
- ControlFlow.ExecuteWithRetry(DoMemoryTest, waitInSeconds: 3);
+ ControlFlow.ExecuteWithRetry(DoMemoryTest, delay: TimeSpan.FromMilliseconds(3));
});
Target ZipFiles => _ => _
@@ -283,6 +279,14 @@ partial class Build : NukeBuild
.DependsOn(Package)
.DependsOn(ZipFiles);
+ Target GenerateCppHeaders => _ => _.Executes(() =>
+ {
+ var file = MicroComCodeGenerator.Parse(
+ File.ReadAllText(RootDirectory / "src" / "Avalonia.Native" / "avn.idl"));
+ File.WriteAllText(RootDirectory / "native" / "Avalonia.Native" / "inc" / "avalonia-native.h",
+ file.GenerateCppHeader());
+ });
+
public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs
index 1826623674..dfa914d1db 100644
--- a/nukebuild/BuildParameters.cs
+++ b/nukebuild/BuildParameters.cs
@@ -74,11 +74,11 @@ public partial class Build
MSBuildSolution = RootDirectory / "dirs.proj";
// PARAMETERS
- IsLocalBuild = Host == HostType.Console;
+ IsLocalBuild = NukeBuild.IsLocalBuild;
IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix ||
Environment.OSVersion.Platform == PlatformID.MacOSX;
IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
- IsRunningOnAzure = Host == HostType.AzurePipelines ||
+ IsRunningOnAzure = Host is AzurePipelines ||
Environment.GetEnvironmentVariable("LOGNAME") == "vsts";
if (IsRunningOnAzure)
diff --git a/nukebuild/BuildTasksPatcher.cs b/nukebuild/BuildTasksPatcher.cs
index e3766ae23f..5fd331035a 100644
--- a/nukebuild/BuildTasksPatcher.cs
+++ b/nukebuild/BuildTasksPatcher.cs
@@ -17,8 +17,12 @@ public class BuildTasksPatcher
{
if (entry.Name == "Avalonia.Build.Tasks.dll")
{
- var temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".dll");
+ var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
+ Directory.CreateDirectory(tempDir);
+ var temp = Path.Combine(tempDir, Guid.NewGuid() + ".dll");
var output = temp + ".output";
+ File.Copy(typeof(Microsoft.Build.Framework.ITask).Assembly.GetModules()[0].FullyQualifiedName,
+ Path.Combine(tempDir, "Microsoft.Build.Framework.dll"));
var patched = new MemoryStream();
try
{
@@ -57,10 +61,8 @@ public class BuildTasksPatcher
{
try
{
- if (File.Exists(temp))
- File.Delete(temp);
- if (File.Exists(output))
- File.Delete(output);
+ if(Directory.Exists(tempDir))
+ Directory.Delete(tempDir, true);
}
catch
{
diff --git a/nukebuild/DotNetConfigHelper.cs b/nukebuild/DotNetConfigHelper.cs
index 932525288c..eca1e2684d 100644
--- a/nukebuild/DotNetConfigHelper.cs
+++ b/nukebuild/DotNetConfigHelper.cs
@@ -46,7 +46,7 @@ public class DotNetConfigHelper
public DotNetConfigHelper SetVerbosity(DotNetVerbosity verbosity)
{
Build = Build?.SetVerbosity(verbosity);
- Pack = Pack?.SetVerbostiy(verbosity);
+ Pack = Pack?.SetVerbosity(verbosity);
Test = Test?.SetVerbosity(verbosity);
return this;
}
@@ -54,4 +54,4 @@ public class DotNetConfigHelper
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);
-}
\ No newline at end of file
+}
diff --git a/nukebuild/MicroComGen.cs b/nukebuild/MicroComGen.cs
deleted file mode 100644
index b1e546cb97..0000000000
--- a/nukebuild/MicroComGen.cs
+++ /dev/null
@@ -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());
- });
-}
\ No newline at end of file
diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs
index 1ac14bf622..6f79972ad6 100644
--- a/nukebuild/Shims.cs
+++ b/nukebuild/Shims.cs
@@ -49,7 +49,11 @@ public partial class Build
{
if (fsEntry is FileInfo)
{
+#if NET6
var relPath = Path.GetRelativePath(rootPath, fsEntry.FullName);
+#else
+ var relPath = GetRelativePath(rootPath, fsEntry.FullName);
+#endif
AddFile(fsEntry.FullName, relPath);
}
}
@@ -78,6 +82,17 @@ public partial class Build
}
}
+ private static string GetRelativePath(string relativeTo, string path)
+ {
+ var uri = new Uri(relativeTo);
+ var rel = Uri.UnescapeDataString(uri.MakeRelativeUri(new Uri(path)).ToString()).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
+ if (rel.Contains(Path.DirectorySeparatorChar.ToString()) == false)
+ {
+ rel = $".{Path.DirectorySeparatorChar}{rel}";
+ }
+ return rel;
+ }
+
class NumergeNukeLogger : INumergeLogger
{
public void Log(NumergeLogLevel level, string message)
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index b2c58e2292..8c0d824298 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -1,41 +1,48 @@
-
Exe
- netcoreapp3.1
false
False
- CS0649;CS0169
+ CS0649;CS0169;SYSLIB0011
+ 1
+ net7.0
+
-
-
+
-
-
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nukebuild/il-repack b/nukebuild/il-repack
new file mode 160000
index 0000000000..892f079ea8
--- /dev/null
+++ b/nukebuild/il-repack
@@ -0,0 +1 @@
+Subproject commit 892f079ea8cb0c178f0a68f53a7a7eac13acdda9
diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs
index 33ca511340..62c582610c 100644
--- a/samples/ControlCatalog.Android/MainActivity.cs
+++ b/samples/ControlCatalog.Android/MainActivity.cs
@@ -5,16 +5,8 @@ using Avalonia.Android;
namespace ControlCatalog.Android
{
- [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
- public class MainActivity : AvaloniaActivity
+ [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AvaloniaMainActivity
{
- protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
- {
- return base.CustomizeAppBuilder(builder)
- .AfterSetup(_ =>
- {
- Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
- });
- }
}
}
diff --git a/samples/ControlCatalog.Android/SplashActivity.cs b/samples/ControlCatalog.Android/SplashActivity.cs
index dc292fd37b..908b5f082a 100644
--- a/samples/ControlCatalog.Android/SplashActivity.cs
+++ b/samples/ControlCatalog.Android/SplashActivity.cs
@@ -1,12 +1,23 @@
using Android.App;
using Android.Content;
+using Android.Content.PM;
using Android.OS;
+using Avalonia.Android;
namespace ControlCatalog.Android
{
[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : Activity
+ public class SplashActivity : AvaloniaSplashActivity
{
+ protected override Avalonia.AppBuilder CustomizeAppBuilder(Avalonia.AppBuilder builder)
+ {
+ return base.CustomizeAppBuilder(builder)
+ .AfterSetup(_ =>
+ {
+ Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
+ });
+ }
+
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
diff --git a/samples/ControlCatalog.Web/App.razor b/samples/ControlCatalog.Blazor.Web/App.razor
similarity index 100%
rename from samples/ControlCatalog.Web/App.razor
rename to samples/ControlCatalog.Blazor.Web/App.razor
diff --git a/samples/ControlCatalog.Blazor.Web/App.razor.cs b/samples/ControlCatalog.Blazor.Web/App.razor.cs
new file mode 100644
index 0000000000..8cc0095f20
--- /dev/null
+++ b/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()
+ .UseBlazor()
+ // .With(new SkiaOptions { CustomGpuFactory = null }) // uncomment to disable GPU/GL rendering
+ .SetupWithSingleViewLifetime();
+
+ base.OnParametersSet();
+ }
+}
diff --git a/samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj b/samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj
new file mode 100644
index 0000000000..03fb31f0d3
--- /dev/null
+++ b/samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj
@@ -0,0 +1,29 @@
+
+
+ net7.0
+ browser-wasm
+ enable
+ 16777216
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Web/Pages/Index.razor b/samples/ControlCatalog.Blazor.Web/Pages/Index.razor
similarity index 100%
rename from samples/ControlCatalog.Web/Pages/Index.razor
rename to samples/ControlCatalog.Blazor.Web/Pages/Index.razor
diff --git a/samples/ControlCatalog.Blazor.Web/Program.cs b/samples/ControlCatalog.Blazor.Web/Program.cs
new file mode 100644
index 0000000000..d71b125fa1
--- /dev/null
+++ b/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");
+
+ builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
+
+ return builder;
+ }
+}
+
+
+
+
diff --git a/samples/ControlCatalog.Web/Properties/launchSettings.json b/samples/ControlCatalog.Blazor.Web/Properties/launchSettings.json
similarity index 100%
rename from samples/ControlCatalog.Web/Properties/launchSettings.json
rename to samples/ControlCatalog.Blazor.Web/Properties/launchSettings.json
diff --git a/samples/ControlCatalog.Web/Shared/MainLayout.razor b/samples/ControlCatalog.Blazor.Web/Shared/MainLayout.razor
similarity index 100%
rename from samples/ControlCatalog.Web/Shared/MainLayout.razor
rename to samples/ControlCatalog.Blazor.Web/Shared/MainLayout.razor
diff --git a/samples/ControlCatalog.Web/_Imports.razor b/samples/ControlCatalog.Blazor.Web/_Imports.razor
similarity index 85%
rename from samples/ControlCatalog.Web/_Imports.razor
rename to samples/ControlCatalog.Blazor.Web/_Imports.razor
index 04c7a8690e..0e6d11b419 100644
--- a/samples/ControlCatalog.Web/_Imports.razor
+++ b/samples/ControlCatalog.Blazor.Web/_Imports.razor
@@ -6,6 +6,5 @@
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
-@using ControlCatalog.Web
-@using ControlCatalog.Web.Shared
+@using ControlCatalog.Blazor.Web.Shared
@using SkiaSharp
diff --git a/samples/ControlCatalog.Web/wwwroot/css/app.css b/samples/ControlCatalog.Blazor.Web/wwwroot/css/app.css
similarity index 100%
rename from samples/ControlCatalog.Web/wwwroot/css/app.css
rename to samples/ControlCatalog.Blazor.Web/wwwroot/css/app.css
diff --git a/samples/ControlCatalog.Web/wwwroot/favicon.ico b/samples/ControlCatalog.Blazor.Web/wwwroot/favicon.ico
similarity index 100%
rename from samples/ControlCatalog.Web/wwwroot/favicon.ico
rename to samples/ControlCatalog.Blazor.Web/wwwroot/favicon.ico
diff --git a/samples/ControlCatalog.Web/wwwroot/index.html b/samples/ControlCatalog.Blazor.Web/wwwroot/index.html
similarity index 100%
rename from samples/ControlCatalog.Web/wwwroot/index.html
rename to samples/ControlCatalog.Blazor.Web/wwwroot/index.html
diff --git a/samples/ControlCatalog.Web/App.razor.cs b/samples/ControlCatalog.Web/App.razor.cs
deleted file mode 100644
index bcd2a6fefc..0000000000
--- a/samples/ControlCatalog.Web/App.razor.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Avalonia;
-using Avalonia.Web.Blazor;
-
-namespace ControlCatalog.Web;
-
-public partial class App
-{
- protected override void OnParametersSet()
- {
- WebAppBuilder.Configure()
- .AfterSetup(_ =>
- {
- ControlCatalog.Pages.EmbedSample.Implementation = new EmbedSampleWeb();
- })
- .With(new SkiaOptions { CustomGpuFactory = null }) // uncomment to disable GPU/GL rendering
- .SetupWithSingleViewLifetime();
-
- base.OnParametersSet();
- }
-}
diff --git a/samples/ControlCatalog.Web/ControlCatalog.Web.csproj b/samples/ControlCatalog.Web/ControlCatalog.Web.csproj
index b2c9ec72eb..0ddec3444b 100644
--- a/samples/ControlCatalog.Web/ControlCatalog.Web.csproj
+++ b/samples/ControlCatalog.Web/ControlCatalog.Web.csproj
@@ -1,57 +1,45 @@
-
+
- net6.0
- enable
-
- true
- 16777216
- false
- false
+ net7.0
+ browser-wasm
+ main.js
+ Exe
+ true
+ true
+ true
+ -sVERBOSE -sERROR_ON_UNDEFINED_SYMBOLS=0
-
-
- false
- -O1
- false
-
-
-
- true
- true
+
+ true
+ true
+ full
+ true
+ true
+ true
-O3
-O3
- false
- false
- false
- false
- false
- false
- true
- false
- true
- true
- true
- link
- true
-
-
+
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
diff --git a/samples/ControlCatalog.Web/EmbedSample.Browser.cs b/samples/ControlCatalog.Web/EmbedSample.Browser.cs
index 5fe14409de..5cfbb608cc 100644
--- a/samples/ControlCatalog.Web/EmbedSample.Browser.cs
+++ b/samples/ControlCatalog.Web/EmbedSample.Browser.cs
@@ -1,34 +1,42 @@
using System;
-
-using Avalonia;
+using System.Runtime.InteropServices.JavaScript;
using Avalonia.Platform;
-using Avalonia.Web.Blazor;
+using Avalonia.Web;
using ControlCatalog.Pages;
-using Microsoft.JSInterop;
-
namespace ControlCatalog.Web;
public class EmbedSampleWeb : INativeDemoControl
{
public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault)
{
- var runtime = AvaloniaLocator.Current.GetRequiredService();
-
if (isSecond)
{
- var iframe = runtime.Invoke("document.createElement", "iframe");
- iframe.InvokeVoid("setAttribute", "src", "https://www.youtube.com/embed/kZCIporjJ70");
+ var iframe = EmbedInterop.CreateElement("iframe");
+ iframe.SetProperty("src", "https://www.youtube.com/embed/kZCIporjJ70");
return new JSObjectControlHandle(iframe);
}
else
{
- // window.createAppButton source is defined in "app.js" file.
- var button = runtime.Invoke("window.createAppButton");
+ var defaultHandle = (JSObjectControlHandle)createDefault();
+
+ _ = JSHost.ImportAsync("embed.js", "./embed.js").ContinueWith(_ =>
+ {
+ EmbedInterop.AddAppButton(defaultHandle.Object);
+ });
- return new JSObjectControlHandle(button);
+ return defaultHandle;
}
}
}
+
+internal static partial class EmbedInterop
+{
+ [JSImport("globalThis.document.createElement")]
+ public static partial JSObject CreateElement(string tagName);
+
+ [JSImport("addAppButton", "embed.js")]
+ public static partial void AddAppButton(JSObject parentObject);
+}
diff --git a/samples/ControlCatalog.Web/Logo.svg b/samples/ControlCatalog.Web/Logo.svg
new file mode 100644
index 0000000000..9685a23af1
--- /dev/null
+++ b/samples/ControlCatalog.Web/Logo.svg
@@ -0,0 +1,5 @@
+
diff --git a/samples/ControlCatalog.Web/Program.cs b/samples/ControlCatalog.Web/Program.cs
index d1a7925813..7d05c8e462 100644
--- a/samples/ControlCatalog.Web/Program.cs
+++ b/samples/ControlCatalog.Web/Program.cs
@@ -1,29 +1,22 @@
-using System;
-using System.Net.Http;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
-using Microsoft.Extensions.DependencyInjection;
+using System.Runtime.Versioning;
+using Avalonia;
+using Avalonia.Web;
+using ControlCatalog;
using ControlCatalog.Web;
-public class Program
+[assembly:SupportedOSPlatform("browser")]
+
+internal partial class Program
{
- public static async Task Main(string[] args)
+ private static void Main(string[] args)
{
- await CreateHostBuilder(args).Build().RunAsync();
+ BuildAvaloniaApp()
+ .AfterSetup(_ =>
+ {
+ ControlCatalog.Pages.EmbedSample.Implementation = new EmbedSampleWeb();
+ }).SetupBrowserApp("out");
}
- public static WebAssemblyHostBuilder CreateHostBuilder(string[] args)
- {
- var builder = WebAssemblyHostBuilder.CreateDefault(args);
-
- builder.RootComponents.Add("#app");
-
- builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
-
- return builder;
- }
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure();
}
-
-
-
-
diff --git a/samples/ControlCatalog.Web/Roots.xml b/samples/ControlCatalog.Web/Roots.xml
new file mode 100644
index 0000000000..3c13098159
--- /dev/null
+++ b/samples/ControlCatalog.Web/Roots.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Web/app.css b/samples/ControlCatalog.Web/app.css
new file mode 100644
index 0000000000..27680f6e1a
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/samples/ControlCatalog.Web/embed.js b/samples/ControlCatalog.Web/embed.js
new file mode 100644
index 0000000000..f393c80314
--- /dev/null
+++ b/samples/ControlCatalog.Web/embed.js
@@ -0,0 +1,11 @@
+export function addAppButton(parent) {
+ var button = globalThis.document.createElement('button');
+ button.innerText = 'Hello world';
+ var clickCount = 0;
+ button.onclick = () => {
+ clickCount++;
+ button.innerText = 'Click count ' + clickCount;
+ };
+ parent.appendChild(button);
+ return button;
+}
diff --git a/samples/ControlCatalog.Web/favicon.ico b/samples/ControlCatalog.Web/favicon.ico
new file mode 100644
index 0000000000..da8d49ff9b
Binary files /dev/null and b/samples/ControlCatalog.Web/favicon.ico differ
diff --git a/samples/ControlCatalog.Web/index.html b/samples/ControlCatalog.Web/index.html
new file mode 100644
index 0000000000..226ae70695
--- /dev/null
+++ b/samples/ControlCatalog.Web/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ AvaloniaUI - ControlCatalog
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Web/main.js b/samples/ControlCatalog.Web/main.js
new file mode 100644
index 0000000000..87f8a4f943
--- /dev/null
+++ b/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!"]);
diff --git a/samples/ControlCatalog.Web/runtimeconfig.template.json b/samples/ControlCatalog.Web/runtimeconfig.template.json
new file mode 100644
index 0000000000..8f0557352c
--- /dev/null
+++ b/samples/ControlCatalog.Web/runtimeconfig.template.json
@@ -0,0 +1,11 @@
+{
+ "wasmHostProperties": {
+ "perHostConfig": [
+ {
+ "name": "browser",
+ "html-path": "index.html",
+ "Host": "browser"
+ }
+ ]
+ }
+}
diff --git a/samples/MobileSandbox.Android/MainActivity.cs b/samples/MobileSandbox.Android/MainActivity.cs
index ac9242dd52..d65f0dec92 100644
--- a/samples/MobileSandbox.Android/MainActivity.cs
+++ b/samples/MobileSandbox.Android/MainActivity.cs
@@ -5,8 +5,8 @@ using Avalonia.Android;
namespace MobileSandbox.Android
{
- [Activity(Label = "MobileSandbox.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
- public class MainActivity : AvaloniaActivity
+ [Activity(Label = "MobileSandbox.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AvaloniaMainActivity
{
}
}
diff --git a/samples/MobileSandbox.Android/SplashActivity.cs b/samples/MobileSandbox.Android/SplashActivity.cs
index c26371d6fe..ced092554d 100644
--- a/samples/MobileSandbox.Android/SplashActivity.cs
+++ b/samples/MobileSandbox.Android/SplashActivity.cs
@@ -1,11 +1,11 @@
using Android.App;
using Android.Content;
-using Android.OS;
+using Avalonia.Android;
namespace MobileSandbox.Android
{
[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : Activity
+ public class SplashActivity : AvaloniaSplashActivity
{
protected override void OnResume()
{
diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs
deleted file mode 100644
index 4ee4bc1375..0000000000
--- a/src/Android/Avalonia.Android/AvaloniaActivity.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using Android.OS;
-using AndroidX.AppCompat.App;
-using Android.Content.Res;
-using AndroidX.Lifecycle;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Controls;
-using Android.Runtime;
-using Android.App;
-using Android.Content;
-using System;
-
-namespace Avalonia.Android
-{
- public abstract class AvaloniaActivity : AppCompatActivity
- {
- internal class SingleViewLifetime : ISingleViewApplicationLifetime
- {
- public AvaloniaView View { get; internal set; }
-
- public Control MainView
- {
- get => (Control)View.Content;
- set => View.Content = value;
- }
- }
-
- internal Action ActivityResult;
- internal AvaloniaView View;
- internal AvaloniaViewModel _viewModel;
-
- protected abstract AppBuilder CreateAppBuilder();
-
- protected override void OnCreate(Bundle savedInstanceState)
- {
- var builder = CreateAppBuilder();
-
-
- var lifetime = new SingleViewLifetime();
-
- builder.AfterSetup(x =>
- {
- _viewModel = new ViewModelProvider(this).Get(Java.Lang.Class.FromType(typeof(AvaloniaViewModel))) as AvaloniaViewModel;
-
- View = new AvaloniaView(this);
- if (_viewModel.Content != null)
- {
- View.Content = _viewModel.Content;
- }
-
- SetContentView(View);
- lifetime.View = View;
-
- View.Prepare();
- });
-
- builder.SetupWithLifetime(lifetime);
-
- base.OnCreate(savedInstanceState);
- }
- public object Content
- {
- get
- {
- return _viewModel.Content;
- }
- set
- {
- _viewModel.Content = value;
- if (View != null)
- View.Content = value;
- }
- }
-
- public override void OnConfigurationChanged(Configuration newConfig)
- {
- base.OnConfigurationChanged(newConfig);
- }
-
- protected override void OnDestroy()
- {
- View.Content = null;
-
- base.OnDestroy();
- }
-
- protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
- {
- base.OnActivityResult(requestCode, resultCode, data);
-
- ActivityResult?.Invoke(requestCode, resultCode, data);
- }
- }
-
- public abstract class AvaloniaActivity : AvaloniaActivity where TApp : Application, new()
- {
- protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
-
- protected override AppBuilder CreateAppBuilder()
- {
- var builder = AppBuilder.Configure();
-
- return CustomizeAppBuilder(builder);
- }
- }
-}
diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
new file mode 100644
index 0000000000..705fa3c59d
--- /dev/null
+++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
@@ -0,0 +1,72 @@
+using System;
+using Android.App;
+using Android.Content;
+using Android.Content.Res;
+using Android.OS;
+using Android.Runtime;
+using AndroidX.AppCompat.App;
+using AndroidX.Lifecycle;
+
+namespace Avalonia.Android
+{
+ public abstract class AvaloniaMainActivity : AppCompatActivity
+ {
+ internal static object ViewContent;
+
+ internal Action ActivityResult;
+ internal AvaloniaView View;
+
+ protected override void OnCreate(Bundle savedInstanceState)
+ {
+ View = new AvaloniaView(this);
+ if (ViewContent != null)
+ {
+ View.Content = ViewContent;
+ }
+
+ View.Prepare();
+
+ if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime)
+ {
+ lifetime.View = View;
+ }
+
+ base.OnCreate(savedInstanceState);
+
+ SetContentView(View);
+ }
+
+ public object Content
+ {
+ get
+ {
+ return ViewContent;
+ }
+ set
+ {
+ ViewContent = value;
+ if (View != null)
+ View.Content = value;
+ }
+ }
+
+ public override void OnConfigurationChanged(Configuration newConfig)
+ {
+ base.OnConfigurationChanged(newConfig);
+ }
+
+ protected override void OnDestroy()
+ {
+ View.Content = null;
+
+ base.OnDestroy();
+ }
+
+ protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
+ {
+ base.OnActivityResult(requestCode, resultCode, data);
+
+ ActivityResult?.Invoke(requestCode, resultCode, data);
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs b/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
new file mode 100644
index 0000000000..5b5ebd1bd9
--- /dev/null
+++ b/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
@@ -0,0 +1,34 @@
+using Android.OS;
+using AndroidX.AppCompat.App;
+using AndroidX.Lifecycle;
+
+namespace Avalonia.Android
+{
+ public abstract class AvaloniaSplashActivity : AppCompatActivity
+ {
+ protected abstract AppBuilder CreateAppBuilder();
+
+ protected override void OnCreate(Bundle? savedInstanceState)
+ {
+ base.OnCreate(savedInstanceState);
+
+ var builder = CreateAppBuilder();
+
+ var lifetime = new SingleViewLifetime();
+
+ builder.SetupWithLifetime(lifetime);
+ }
+ }
+
+ public abstract class AvaloniaSplashActivity : AvaloniaSplashActivity where TApp : Application, new()
+ {
+ protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
+
+ protected override AppBuilder CreateAppBuilder()
+ {
+ var builder = AppBuilder.Configure();
+
+ return CustomizeAppBuilder(builder);
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/AvaloniaViewModel.cs b/src/Android/Avalonia.Android/AvaloniaViewModel.cs
deleted file mode 100644
index 1b2c00987a..0000000000
--- a/src/Android/Avalonia.Android/AvaloniaViewModel.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Avalonia.Android
-{
- internal class AvaloniaViewModel : AndroidX.Lifecycle.ViewModel
- {
- public object Content { get; set; }
- }
-}
diff --git a/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs b/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
index a9710039f8..e85ed11028 100644
--- a/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
+++ b/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
@@ -1,4 +1,5 @@
-using Avalonia.OpenGL.Egl;
+using Avalonia.OpenGL;
+using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
namespace Avalonia.Android.OpenGL
@@ -19,7 +20,8 @@ namespace Avalonia.Android.OpenGL
public static GlPlatformSurface TryCreate(IEglWindowGlPlatformSurfaceInfo info)
{
- if (EglPlatformOpenGlInterface.TryCreate() is EglPlatformOpenGlInterface egl)
+ var feature = AvaloniaLocator.Current.GetService();
+ if (feature is EglPlatformOpenGlInterface egl)
{
return new GlPlatformSurface(egl, info);
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index f8eaeba897..7ce72aaca5 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -3,20 +3,14 @@ using System.Collections.Generic;
using Android.Content;
using Android.Graphics;
-using Android.Media.TV;
-using Android.OS;
using Android.Runtime;
-using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
-using Android.Widget;
using Avalonia.Android.OpenGL;
-using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.Specific;
using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Android.Platform.Storage;
using Avalonia.Controls;
-using Avalonia.Controls.Documents;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Input;
@@ -29,7 +23,6 @@ using Avalonia.Platform.Storage;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Java.Lang;
-using static System.Net.Mime.MediaTypeNames;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@@ -59,7 +52,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling);
NativeControlHost = new AndroidNativeControlHostImpl(avaloniaView);
- StorageProvider = new AndroidStorageProvider((AvaloniaActivity)avaloniaView.Context);
+ StorageProvider = new AndroidStorageProvider((AvaloniaMainActivity)avaloniaView.Context);
}
public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) =>
@@ -301,7 +294,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
IsComposing = true;
- _inputMethod.Client.SetPreeditText(ComposingText);
+ _inputMethod.Client?.SetPreeditText(ComposingText);
return base.SetComposingText(text, newCursorPosition);
}
diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs
index 653f450ec8..3a1a9e76ea 100644
--- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs
+++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs
@@ -14,10 +14,10 @@ namespace Avalonia.Android.Platform.Storage;
internal class AndroidStorageProvider : IStorageProvider
{
- private readonly AvaloniaActivity _activity;
+ private readonly AvaloniaMainActivity _activity;
private int _lastRequestCode = 20000;
- public AndroidStorageProvider(AvaloniaActivity activity)
+ public AndroidStorageProvider(AvaloniaMainActivity activity)
{
_activity = activity;
}
diff --git a/src/Android/Avalonia.Android/SingleViewLifetime.cs b/src/Android/Avalonia.Android/SingleViewLifetime.cs
new file mode 100644
index 0000000000..eef763a932
--- /dev/null
+++ b/src/Android/Avalonia.Android/SingleViewLifetime.cs
@@ -0,0 +1,26 @@
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+
+namespace Avalonia.Android
+{
+ internal class SingleViewLifetime : ISingleViewApplicationLifetime
+ {
+ private AvaloniaView _view;
+
+ public AvaloniaView View
+ {
+ get => _view; internal set
+ {
+ if (_view != null)
+ {
+ _view.Content = null;
+ _view.Dispose();
+ }
+ _view = value;
+ _view.Content = MainView;
+ }
+ }
+
+ public Control MainView { get; set; }
+ }
+}
diff --git a/src/Avalonia.Base/Input/Cursor.cs b/src/Avalonia.Base/Input/Cursor.cs
index 98c4258a90..8e79206f93 100644
--- a/src/Avalonia.Base/Input/Cursor.cs
+++ b/src/Avalonia.Base/Input/Cursor.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Input
DragLink,
None,
- // Not available in GTK directly, see http://www.pixelbeat.org/programming/x_cursors/
+ // Not available in GTK directly, see https://www.pixelbeat.org/programming/x_cursors/
// We might enable them later, preferably, by loading pixmax directly from theme with fallback image
// SizeNorthWestSouthEast,
// SizeNorthEastSouthWest,
diff --git a/src/Avalonia.Base/Logging/LogArea.cs b/src/Avalonia.Base/Logging/LogArea.cs
index 98ef6d2530..972a9a1e9d 100644
--- a/src/Avalonia.Base/Logging/LogArea.cs
+++ b/src/Avalonia.Base/Logging/LogArea.cs
@@ -8,51 +8,66 @@ namespace Avalonia.Logging
///
/// The log event comes from the property system.
///
- public const string Property = "Property";
+ public const string Property = nameof(Property);
///
/// The log event comes from the binding system.
///
- public const string Binding = "Binding";
+ public const string Binding = nameof(Binding);
///
/// The log event comes from the animations system.
///
- public const string Animations = "Animations";
+ public const string Animations = nameof(Animations);
///
/// The log event comes from the visual system.
///
- public const string Visual = "Visual";
+ public const string Visual = nameof(Visual);
///
/// The log event comes from the layout system.
///
- public const string Layout = "Layout";
+ public const string Layout = nameof(Layout);
///
/// The log event comes from the control system.
///
- public const string Control = "Control";
+ public const string Control = nameof(Control);
///
- /// The log event comes from Win32Platform.
+ /// The log event comes from Win32 Platform.
///
public const string Win32Platform = nameof(Win32Platform);
///
- /// The log event comes from X11Platform.
+ /// The log event comes from X11 Platform.
///
public const string X11Platform = nameof(X11Platform);
///
- /// The log event comes from AndroidPlatform.
+ /// The log event comes from Android Platform.
///
public const string AndroidPlatform = nameof(AndroidPlatform);
///
- /// The log event comes from IOSPlatform.
+ /// The log event comes from iOS Platform.
///
public const string IOSPlatform = nameof(IOSPlatform);
+
+ ///
+ /// The log event comes from LinuxFramebuffer Platform
+ ///
+ public const string LinuxFramebufferPlatform = nameof(LinuxFramebufferPlatform);
+
+ ///
+ /// The log event comes from FreeDesktop Platform
+ ///
+ public const string FreeDesktopPlatform = nameof(FreeDesktopPlatform);
+
+ ///
+ /// The log event comes from macOS Platform
+ ///
+ public const string macOSPlatform = nameof(macOSPlatform);
}
}
diff --git a/src/Avalonia.Base/Media/PreciseEllipticArcHelper.cs b/src/Avalonia.Base/Media/PreciseEllipticArcHelper.cs
index 5dd647e8ca..49dfe3c7b3 100644
--- a/src/Avalonia.Base/Media/PreciseEllipticArcHelper.cs
+++ b/src/Avalonia.Base/Media/PreciseEllipticArcHelper.cs
@@ -1081,7 +1081,7 @@ namespace Avalonia.Media
Point c = rest * (cs) + translation;
- // See "http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter" to understand
+ // See "https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter" to understand
// how the ellipse center is calculated
diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/BinaryReaderExtensions.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/BinaryReaderExtensions.cs
index 412007c6e0..ccbceb6a7b 100644
--- a/src/Avalonia.Base/Media/TextFormatting/Unicode/BinaryReaderExtensions.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/BinaryReaderExtensions.cs
@@ -5,7 +5,7 @@
// not use this product except in compliance with the License. You may obtain
// a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs
index ab17263806..ce9cdde044 100644
--- a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs
@@ -104,7 +104,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
///
/// Gets the canonical representation of a given codepoint.
- ///
+ ///
///
/// The code point to be mapped.
/// The mapped canonical code point, or the passed .
diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreak.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreak.cs
index 34b14f008f..59c4df0a2e 100644
--- a/src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreak.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreak.cs
@@ -5,7 +5,7 @@
// not use this product except in compliance with the License. You may obtain
// a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrie.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrie.cs
index cf03ed7cd3..079f830ddc 100644
--- a/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrie.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrie.cs
@@ -5,7 +5,7 @@
// not use this product except in compliance with the License. You may obtain
// a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.Constants.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.Constants.cs
index 29ee45acc2..de0304f4c9 100644
--- a/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.Constants.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.Constants.cs
@@ -5,7 +5,7 @@
// not use this product except in compliance with the License. You may obtain
// a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.cs
index 87f96984c5..755d603539 100644
--- a/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.cs
@@ -5,7 +5,7 @@
// not use this product except in compliance with the License. You may obtain
// a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
diff --git a/src/Avalonia.Base/Platform/Storage/IStorageFile.cs b/src/Avalonia.Base/Platform/Storage/IStorageFile.cs
index 46aa6efa72..4aa84e3ec4 100644
--- a/src/Avalonia.Base/Platform/Storage/IStorageFile.cs
+++ b/src/Avalonia.Base/Platform/Storage/IStorageFile.cs
@@ -18,6 +18,7 @@ public interface IStorageFile : IStorageItem
///
/// Opens a stream for read access.
///
+ ///
Task OpenReadAsync();
///
@@ -28,5 +29,6 @@ public interface IStorageFile : IStorageItem
///
/// Opens stream for writing to the file.
///
+ ///
Task OpenWriteAsync();
}
diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs
index c8368e6d7a..d5e01087ef 100644
--- a/src/Avalonia.Base/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs
@@ -30,4 +30,5 @@ using Avalonia.Metadata;
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Web.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
+[assembly: InternalsVisibleTo("Avalonia.Web, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
diff --git a/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs b/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
index bd3b86f06d..b8692bb771 100644
--- a/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
+++ b/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
@@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
-using System.Runtime.Serialization.Json;
using System.Xml.Linq;
using System.Linq;
diff --git a/src/Avalonia.Base/Utilities/BinarySearchExtension.cs b/src/Avalonia.Base/Utilities/BinarySearchExtension.cs
index a4f6ae89c1..b7060d2e21 100644
--- a/src/Avalonia.Base/Utilities/BinarySearchExtension.cs
+++ b/src/Avalonia.Base/Utilities/BinarySearchExtension.cs
@@ -5,7 +5,7 @@
// not use this product except in compliance with the License. You may obtain
// a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
index 8387c62cad..74debed828 100644
--- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
+++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
@@ -9,6 +9,11 @@
NU1605;CS8632
+
+
+ false
+
+
Shared/AvaloniaResourcesIndex.cs
@@ -105,7 +110,7 @@
-
+
diff --git a/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs b/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
index c20b2f656e..75758d1315 100644
--- a/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
+++ b/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
-using System.Runtime.Serialization.Json;
using System.Text;
using Avalonia.Markup.Xaml.PortableXaml;
using Avalonia.Utilities;
diff --git a/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs b/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs
new file mode 100644
index 0000000000..5cf5662ede
--- /dev/null
+++ b/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs
@@ -0,0 +1,359 @@
+using Avalonia.Media;
+using Avalonia.Utilities;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Implements a reduced version of the 2014 Material Design color palette.
+ ///
+ ///
+ /// This palette is based on the one outlined here:
+ ///
+ /// https://material.io/design/color/the-color-system.html#tools-for-picking-colors
+ ///
+ /// In order to make the palette uniform and rectangular the following
+ /// alterations were made:
+ ///
+ /// 1. The A100-A700 shades of each color are excluded.
+ /// These shades do not exist for all colors (brown/gray).
+ /// 2. Black/White are stand-alone and are also excluded.
+ ///
+ ///
+ public class MaterialColorPalette : IColorPalette
+ {
+ // See: https://material.io/design/color/the-color-system.html#tools-for-picking-colors
+ // This is a reduced palette for uniformity
+ private static Color[,]? _colorChart = null;
+ private static int _colorChartColorCount = 0;
+ private static int _colorChartShadeCount = 0;
+ private static object _colorChartMutex = new object();
+
+ ///
+ /// Initializes all color chart colors.
+ ///
+ ///
+ /// This is pulled out separately to lazy load for performance.
+ /// If no material color palette is ever used, no colors will be created.
+ ///
+ private void InitColorChart()
+ {
+ lock (_colorChartMutex)
+ {
+ _colorChart = new Color[,]
+ {
+ // Red
+ {
+ Color.FromArgb(0xFF, 0xFF, 0xEB, 0xEE),
+ Color.FromArgb(0xFF, 0xFF, 0xCD, 0xD2),
+ Color.FromArgb(0xFF, 0xEF, 0x9A, 0x9A),
+ Color.FromArgb(0xFF, 0xE5, 0x73, 0x73),
+ Color.FromArgb(0xFF, 0xEF, 0x53, 0x50),
+ Color.FromArgb(0xFF, 0xF4, 0x43, 0x36),
+ Color.FromArgb(0xFF, 0xE5, 0x39, 0x35),
+ Color.FromArgb(0xFF, 0xD3, 0x2F, 0x2F),
+ Color.FromArgb(0xFF, 0xC6, 0x28, 0x28),
+ Color.FromArgb(0xFF, 0xB7, 0x1C, 0x1C),
+ },
+
+ // Pink
+ {
+ Color.FromArgb(0xFF, 0xFC, 0xE4, 0xEC),
+ Color.FromArgb(0xFF, 0xF8, 0xBB, 0xD0),
+ Color.FromArgb(0xFF, 0xF4, 0x8F, 0xB1),
+ Color.FromArgb(0xFF, 0xF0, 0x62, 0x92),
+ Color.FromArgb(0xFF, 0xEC, 0x40, 0x7A),
+ Color.FromArgb(0xFF, 0xE9, 0x1E, 0x63),
+ Color.FromArgb(0xFF, 0xD8, 0x1B, 0x60),
+ Color.FromArgb(0xFF, 0xC2, 0x18, 0x5B),
+ Color.FromArgb(0xFF, 0xAD, 0x14, 0x57),
+ Color.FromArgb(0xFF, 0x88, 0x0E, 0x4F),
+ },
+
+ // Purple
+ {
+ Color.FromArgb(0xFF, 0xF3, 0xE5, 0xF5),
+ Color.FromArgb(0xFF, 0xE1, 0xBE, 0xE7),
+ Color.FromArgb(0xFF, 0xCE, 0x93, 0xD8),
+ Color.FromArgb(0xFF, 0xBA, 0x68, 0xC8),
+ Color.FromArgb(0xFF, 0xAB, 0x47, 0xBC),
+ Color.FromArgb(0xFF, 0x9C, 0x27, 0xB0),
+ Color.FromArgb(0xFF, 0x8E, 0x24, 0xAA),
+ Color.FromArgb(0xFF, 0x7B, 0x1F, 0xA2),
+ Color.FromArgb(0xFF, 0x6A, 0x1B, 0x9A),
+ Color.FromArgb(0xFF, 0x4A, 0x14, 0x8C),
+ },
+
+ // Deep Purple
+ {
+ Color.FromArgb(0xFF, 0xED, 0xE7, 0xF6),
+ Color.FromArgb(0xFF, 0xD1, 0xC4, 0xE9),
+ Color.FromArgb(0xFF, 0xB3, 0x9D, 0xDB),
+ Color.FromArgb(0xFF, 0x95, 0x75, 0xCD),
+ Color.FromArgb(0xFF, 0x7E, 0x57, 0xC2),
+ Color.FromArgb(0xFF, 0x67, 0x3A, 0xB7),
+ Color.FromArgb(0xFF, 0x5E, 0x35, 0xB1),
+ Color.FromArgb(0xFF, 0x51, 0x2D, 0xA8),
+ Color.FromArgb(0xFF, 0x45, 0x27, 0xA0),
+ Color.FromArgb(0xFF, 0x31, 0x1B, 0x92),
+ },
+
+ // Indigo
+ {
+ Color.FromArgb(0xFF, 0xE8, 0xEA, 0xF6),
+ Color.FromArgb(0xFF, 0xC5, 0xCA, 0xE9),
+ Color.FromArgb(0xFF, 0x9F, 0xA8, 0xDA),
+ Color.FromArgb(0xFF, 0x79, 0x86, 0xCB),
+ Color.FromArgb(0xFF, 0x5C, 0x6B, 0xC0),
+ Color.FromArgb(0xFF, 0x3F, 0x51, 0xB5),
+ Color.FromArgb(0xFF, 0x39, 0x49, 0xAB),
+ Color.FromArgb(0xFF, 0x30, 0x3F, 0x9F),
+ Color.FromArgb(0xFF, 0x28, 0x35, 0x93),
+ Color.FromArgb(0xFF, 0x1A, 0x23, 0x7E),
+ },
+
+ // Blue
+ {
+ Color.FromArgb(0xFF, 0xE3, 0xF2, 0xFD),
+ Color.FromArgb(0xFF, 0xBB, 0xDE, 0xFB),
+ Color.FromArgb(0xFF, 0x90, 0xCA, 0xF9),
+ Color.FromArgb(0xFF, 0x64, 0xB5, 0xF6),
+ Color.FromArgb(0xFF, 0x42, 0xA5, 0xF5),
+ Color.FromArgb(0xFF, 0x21, 0x96, 0xF3),
+ Color.FromArgb(0xFF, 0x1E, 0x88, 0xE5),
+ Color.FromArgb(0xFF, 0x19, 0x76, 0xD2),
+ Color.FromArgb(0xFF, 0x15, 0x65, 0xC0),
+ Color.FromArgb(0xFF, 0x0D, 0x47, 0xA1),
+ },
+
+ // Light Blue
+ {
+ Color.FromArgb(0xFF, 0xE1, 0xF5, 0xFE),
+ Color.FromArgb(0xFF, 0xB3, 0xE5, 0xFC),
+ Color.FromArgb(0xFF, 0x81, 0xD4, 0xFA),
+ Color.FromArgb(0xFF, 0x4F, 0xC3, 0xF7),
+ Color.FromArgb(0xFF, 0x29, 0xB6, 0xF6),
+ Color.FromArgb(0xFF, 0x03, 0xA9, 0xF4),
+ Color.FromArgb(0xFF, 0x03, 0x9B, 0xE5),
+ Color.FromArgb(0xFF, 0x02, 0x88, 0xD1),
+ Color.FromArgb(0xFF, 0x02, 0x77, 0xBD),
+ Color.FromArgb(0xFF, 0x01, 0x57, 0x9B),
+ },
+
+ // Cyan
+ {
+ Color.FromArgb(0xFF, 0xE0, 0xF7, 0xFA),
+ Color.FromArgb(0xFF, 0xB2, 0xEB, 0xF2),
+ Color.FromArgb(0xFF, 0x80, 0xDE, 0xEA),
+ Color.FromArgb(0xFF, 0x4D, 0xD0, 0xE1),
+ Color.FromArgb(0xFF, 0x26, 0xC6, 0xDA),
+ Color.FromArgb(0xFF, 0x00, 0xBC, 0xD4),
+ Color.FromArgb(0xFF, 0x00, 0xAC, 0xC1),
+ Color.FromArgb(0xFF, 0x00, 0x97, 0xA7),
+ Color.FromArgb(0xFF, 0x00, 0x83, 0x8F),
+ Color.FromArgb(0xFF, 0x00, 0x60, 0x64),
+ },
+
+ // Teal
+ {
+ Color.FromArgb(0xFF, 0xE0, 0xF2, 0xF1),
+ Color.FromArgb(0xFF, 0xB2, 0xDF, 0xDB),
+ Color.FromArgb(0xFF, 0x80, 0xCB, 0xC4),
+ Color.FromArgb(0xFF, 0x4D, 0xB6, 0xAC),
+ Color.FromArgb(0xFF, 0x26, 0xA6, 0x9A),
+ Color.FromArgb(0xFF, 0x00, 0x96, 0x88),
+ Color.FromArgb(0xFF, 0x00, 0x89, 0x7B),
+ Color.FromArgb(0xFF, 0x00, 0x79, 0x6B),
+ Color.FromArgb(0xFF, 0x00, 0x69, 0x5C),
+ Color.FromArgb(0xFF, 0x00, 0x4D, 0x40),
+ },
+
+ // Green
+ {
+ Color.FromArgb(0xFF, 0xE8, 0xF5, 0xE9),
+ Color.FromArgb(0xFF, 0xC8, 0xE6, 0xC9),
+ Color.FromArgb(0xFF, 0xA5, 0xD6, 0xA7),
+ Color.FromArgb(0xFF, 0x81, 0xC7, 0x84),
+ Color.FromArgb(0xFF, 0x66, 0xBB, 0x6A),
+ Color.FromArgb(0xFF, 0x4C, 0xAF, 0x50),
+ Color.FromArgb(0xFF, 0x43, 0xA0, 0x47),
+ Color.FromArgb(0xFF, 0x38, 0x8E, 0x3C),
+ Color.FromArgb(0xFF, 0x2E, 0x7D, 0x32),
+ Color.FromArgb(0xFF, 0x1B, 0x5E, 0x20),
+ },
+
+ // Light Green
+ {
+ Color.FromArgb(0xFF, 0xF1, 0xF8, 0xE9),
+ Color.FromArgb(0xFF, 0xDC, 0xED, 0xC8),
+ Color.FromArgb(0xFF, 0xC5, 0xE1, 0xA5),
+ Color.FromArgb(0xFF, 0xAE, 0xD5, 0x81),
+ Color.FromArgb(0xFF, 0x9C, 0xCC, 0x65),
+ Color.FromArgb(0xFF, 0x8B, 0xC3, 0x4A),
+ Color.FromArgb(0xFF, 0x7C, 0xB3, 0x42),
+ Color.FromArgb(0xFF, 0x68, 0x9F, 0x38),
+ Color.FromArgb(0xFF, 0x55, 0x8B, 0x2F),
+ Color.FromArgb(0xFF, 0x33, 0x69, 0x1E),
+ },
+
+ // Lime
+ {
+ Color.FromArgb(0xFF, 0xF9, 0xFB, 0xE7),
+ Color.FromArgb(0xFF, 0xF0, 0xF4, 0xC3),
+ Color.FromArgb(0xFF, 0xE6, 0xEE, 0x9C),
+ Color.FromArgb(0xFF, 0xDC, 0xE7, 0x75),
+ Color.FromArgb(0xFF, 0xD4, 0xE1, 0x57),
+ Color.FromArgb(0xFF, 0xCD, 0xDC, 0x39),
+ Color.FromArgb(0xFF, 0xC0, 0xCA, 0x33),
+ Color.FromArgb(0xFF, 0xAF, 0xB4, 0x2B),
+ Color.FromArgb(0xFF, 0x9E, 0x9D, 0x24),
+ Color.FromArgb(0xFF, 0x82, 0x77, 0x17),
+ },
+
+ // Yellow
+ {
+ Color.FromArgb(0xFF, 0xFF, 0xFD, 0xE7),
+ Color.FromArgb(0xFF, 0xFF, 0xF9, 0xC4),
+ Color.FromArgb(0xFF, 0xFF, 0xF5, 0x9D),
+ Color.FromArgb(0xFF, 0xFF, 0xF1, 0x76),
+ Color.FromArgb(0xFF, 0xFF, 0xEE, 0x58),
+ Color.FromArgb(0xFF, 0xFF, 0xEB, 0x3B),
+ Color.FromArgb(0xFF, 0xFD, 0xD8, 0x35),
+ Color.FromArgb(0xFF, 0xFB, 0xC0, 0x2D),
+ Color.FromArgb(0xFF, 0xF9, 0xA8, 0x25),
+ Color.FromArgb(0xFF, 0xF5, 0x7F, 0x17),
+ },
+
+ // Amber
+ {
+ Color.FromArgb(0xFF, 0xFF, 0xF8, 0xE1),
+ Color.FromArgb(0xFF, 0xFF, 0xEC, 0xB3),
+ Color.FromArgb(0xFF, 0xFF, 0xE0, 0x82),
+ Color.FromArgb(0xFF, 0xFF, 0xD5, 0x4F),
+ Color.FromArgb(0xFF, 0xFF, 0xCA, 0x28),
+ Color.FromArgb(0xFF, 0xFF, 0xC1, 0x07),
+ Color.FromArgb(0xFF, 0xFF, 0xB3, 0x00),
+ Color.FromArgb(0xFF, 0xFF, 0xA0, 0x00),
+ Color.FromArgb(0xFF, 0xFF, 0x8F, 0x00),
+ Color.FromArgb(0xFF, 0xFF, 0x6F, 0x00),
+ },
+
+ // Orange
+ {
+ Color.FromArgb(0xFF, 0xFF, 0xF3, 0xE0),
+ Color.FromArgb(0xFF, 0xFF, 0xE0, 0xB2),
+ Color.FromArgb(0xFF, 0xFF, 0xCC, 0x80),
+ Color.FromArgb(0xFF, 0xFF, 0xB7, 0x4D),
+ Color.FromArgb(0xFF, 0xFF, 0xA7, 0x26),
+ Color.FromArgb(0xFF, 0xFF, 0x98, 0x00),
+ Color.FromArgb(0xFF, 0xFB, 0x8C, 0x00),
+ Color.FromArgb(0xFF, 0xF5, 0x7C, 0x00),
+ Color.FromArgb(0xFF, 0xEF, 0x6C, 0x00),
+ Color.FromArgb(0xFF, 0xE6, 0x51, 0x00),
+ },
+
+ // Deep Orange
+ {
+ Color.FromArgb(0xFF, 0xFB, 0xE9, 0xE7),
+ Color.FromArgb(0xFF, 0xFF, 0xCC, 0xBC),
+ Color.FromArgb(0xFF, 0xFF, 0xAB, 0x91),
+ Color.FromArgb(0xFF, 0xFF, 0x8A, 0x65),
+ Color.FromArgb(0xFF, 0xFF, 0x70, 0x43),
+ Color.FromArgb(0xFF, 0xFF, 0x57, 0x22),
+ Color.FromArgb(0xFF, 0xF4, 0x51, 0x1E),
+ Color.FromArgb(0xFF, 0xE6, 0x4A, 0x19),
+ Color.FromArgb(0xFF, 0xD8, 0x43, 0x15),
+ Color.FromArgb(0xFF, 0xBF, 0x36, 0x0C),
+ },
+
+ // Brown
+ {
+ Color.FromArgb(0xFF, 0xEF, 0xEB, 0xE9),
+ Color.FromArgb(0xFF, 0xD7, 0xCC, 0xC8),
+ Color.FromArgb(0xFF, 0xBC, 0xAA, 0xA4),
+ Color.FromArgb(0xFF, 0xA1, 0x88, 0x7F),
+ Color.FromArgb(0xFF, 0x8D, 0x6E, 0x63),
+ Color.FromArgb(0xFF, 0x79, 0x55, 0x48),
+ Color.FromArgb(0xFF, 0x6D, 0x4C, 0x41),
+ Color.FromArgb(0xFF, 0x5D, 0x40, 0x37),
+ Color.FromArgb(0xFF, 0x4E, 0x34, 0x2E),
+ Color.FromArgb(0xFF, 0x3E, 0x27, 0x23),
+ },
+
+ // Gray
+ {
+ Color.FromArgb(0xFF, 0xFA, 0xFA, 0xFA),
+ Color.FromArgb(0xFF, 0xF5, 0xF5, 0xF5),
+ Color.FromArgb(0xFF, 0xEE, 0xEE, 0xEE),
+ Color.FromArgb(0xFF, 0xE0, 0xE0, 0xE0),
+ Color.FromArgb(0xFF, 0xBD, 0xBD, 0xBD),
+ Color.FromArgb(0xFF, 0x9E, 0x9E, 0x9E),
+ Color.FromArgb(0xFF, 0x75, 0x75, 0x75),
+ Color.FromArgb(0xFF, 0x61, 0x61, 0x61),
+ Color.FromArgb(0xFF, 0x42, 0x42, 0x42),
+ Color.FromArgb(0xFF, 0x21, 0x21, 0x21),
+ },
+
+ // Blue Gray
+ {
+ Color.FromArgb(0xFF, 0xEC, 0xEF, 0xF1),
+ Color.FromArgb(0xFF, 0xCF, 0xD8, 0xDC),
+ Color.FromArgb(0xFF, 0xB0, 0xBE, 0xC5),
+ Color.FromArgb(0xFF, 0x90, 0xA4, 0xAE),
+ Color.FromArgb(0xFF, 0x78, 0x90, 0x9C),
+ Color.FromArgb(0xFF, 0x60, 0x7D, 0x8B),
+ Color.FromArgb(0xFF, 0x54, 0x6E, 0x7A),
+ Color.FromArgb(0xFF, 0x45, 0x5A, 0x64),
+ Color.FromArgb(0xFF, 0x37, 0x47, 0x4F),
+ Color.FromArgb(0xFF, 0x26, 0x32, 0x38),
+ },
+ };
+
+ _colorChartColorCount = _colorChart.GetLength(0);
+ _colorChartShadeCount = _colorChart.GetLength(1);
+ }
+
+ return;
+ }
+
+ ///
+ public int ColorCount
+ {
+ get
+ {
+ if (_colorChart == null)
+ {
+ InitColorChart();
+ }
+
+ return _colorChartColorCount;
+ }
+ }
+
+ ///
+ public int ShadeCount
+ {
+ get
+ {
+ if (_colorChart == null)
+ {
+ InitColorChart();
+ }
+
+ return _colorChartShadeCount;
+ }
+ }
+
+ ///
+ public Color GetColor(int colorIndex, int shadeIndex)
+ {
+ if (_colorChart == null)
+ {
+ InitColorChart();
+ }
+
+ return _colorChart![
+ MathUtilities.Clamp(colorIndex, 0, _colorChartColorCount - 1),
+ MathUtilities.Clamp(shadeIndex, 0, _colorChartShadeCount - 1)];
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index c675139831..8a8c4ead86 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/Calendar.cs b/src/Avalonia.Controls/Calendar/Calendar.cs
index 0de068a416..9c88bae5f6 100644
--- a/src/Avalonia.Controls/Calendar/Calendar.cs
+++ b/src/Avalonia.Controls/Calendar/Calendar.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
index 5d883f2d14..a92feec509 100644
--- a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/CalendarButton.cs b/src/Avalonia.Controls/Calendar/CalendarButton.cs
index 0a8e4dfae8..d8672cbf18 100644
--- a/src/Avalonia.Controls/Calendar/CalendarButton.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarButton.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Controls.Metadata;
diff --git a/src/Avalonia.Controls/Calendar/CalendarDateRange.cs b/src/Avalonia.Controls/Calendar/CalendarDateRange.cs
index 88bc5ed7bd..793ef7a2ee 100644
--- a/src/Avalonia.Controls/Calendar/CalendarDateRange.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarDateRange.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/CalendarDayButton.cs b/src/Avalonia.Controls/Calendar/CalendarDayButton.cs
index 2ba4e36260..3d0befdba7 100644
--- a/src/Avalonia.Controls/Calendar/CalendarDayButton.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarDayButton.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/CalendarExtensions.cs b/src/Avalonia.Controls/Calendar/CalendarExtensions.cs
index 00b5ce10bc..cb3ee06a9e 100644
--- a/src/Avalonia.Controls/Calendar/CalendarExtensions.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarExtensions.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Input;
diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs
index e2eabb5f28..eec3bdc9f2 100644
--- a/src/Avalonia.Controls/Calendar/CalendarItem.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/DateTimeHelper.cs b/src/Avalonia.Controls/Calendar/DateTimeHelper.cs
index 7a5c74a51b..bfff03a926 100644
--- a/src/Avalonia.Controls/Calendar/DateTimeHelper.cs
+++ b/src/Avalonia.Controls/Calendar/DateTimeHelper.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs b/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
index f4bc2528ba..211b5edb0d 100644
--- a/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
+++ b/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Threading;
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
index 3d592e9ab5..ec1273ca98 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerDateValidationErrorEventArgs.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerDateValidationErrorEventArgs.cs
index 647910cb6b..b58b549030 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerDateValidationErrorEventArgs.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerDateValidationErrorEventArgs.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerFormat.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerFormat.cs
index 4d96859d75..ffd1f6f594 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerFormat.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePickerFormat.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs
index 05be5ad00d..54196bdf1a 100644
--- a/src/Avalonia.Controls/ComboBox.cs
+++ b/src/Avalonia.Controls/ComboBox.cs
@@ -21,8 +21,11 @@ namespace Avalonia.Controls
/// A drop-down list control.
///
[TemplatePart("PART_Popup", typeof(Popup))]
+ [PseudoClasses(pcDropdownOpen, pcPressed)]
public class ComboBox : SelectingItemsControl
{
+ public const string pcDropdownOpen = ":dropdownopen";
+ public const string pcPressed = ":pressed";
///
/// The default value for the property.
///
@@ -95,6 +98,7 @@ namespace Avalonia.Controls
SelectedItemProperty.Changed.AddClassHandler((x, e) => x.SelectedItemChanged(e));
KeyDownEvent.AddClassHandler((x, e) => x.OnKeyDown(e), Interactivity.RoutingStrategies.Tunnel);
IsTextSearchEnabledProperty.OverrideDefaultValue(true);
+ IsDropDownOpenProperty.Changed.AddClassHandler((x, e) => x.DropdownChanged(e));
}
///
@@ -267,6 +271,20 @@ namespace Avalonia.Controls
}
}
+ ///
+ protected override void OnPointerPressed(PointerPressedEventArgs e)
+ {
+ base.OnPointerPressed(e);
+ if(!e.Handled && e.Source is IVisual source)
+ {
+ if (_popup?.IsInsidePopup(source) == true)
+ {
+ return;
+ }
+ }
+ PseudoClasses.Set(pcPressed, true);
+ }
+
///
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
@@ -286,10 +304,12 @@ namespace Avalonia.Controls
e.Handled = true;
}
}
-
+ PseudoClasses.Set(pcPressed, false);
base.OnPointerReleased(e);
+
}
+
///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
@@ -470,5 +490,11 @@ namespace Avalonia.Controls
MoveSelection(NavigationDirection.Previous, WrapSelection);
}
}
+
+ private void DropdownChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ bool newValue = e.GetNewValue();
+ PseudoClasses.Set(pcDropdownOpen, newValue);
+ }
}
}
diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
index d8de813d47..615eb69fe3 100644
--- a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
+++ b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
@@ -35,7 +35,7 @@ DEALINGS IN THE SOFTWARE.
The above is the version of the MIT "Expat" License used by X.org:
- http://cgit.freedesktop.org/xorg/xserver/tree/COPYING
+ https://cgit.freedesktop.org/xorg/xserver/tree/COPYING
Adjustments for Avalonia needs:
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 964a153c8b..da4e90fb66 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -18,6 +18,7 @@ using Avalonia.Media.TextFormatting;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Automation.Peers;
using System.Diagnostics;
+using Avalonia.Threading;
namespace Avalonia.Controls
{
@@ -159,18 +160,41 @@ namespace Avalonia.Controls
(o, v) => o.UndoLimit = v,
unsetValue: -1);
+ ///
+ /// Defines the event.
+ ///
public static readonly RoutedEvent CopyingToClipboardEvent =
RoutedEvent.Register(
nameof(CopyingToClipboard), RoutingStrategies.Bubble);
+ ///
+ /// Defines the event.
+ ///
public static readonly RoutedEvent CuttingToClipboardEvent =
RoutedEvent.Register(
nameof(CuttingToClipboard), RoutingStrategies.Bubble);
+ ///
+ /// Defines the event.
+ ///
public static readonly RoutedEvent PastingFromClipboardEvent =
RoutedEvent.Register(
nameof(PastingFromClipboard), RoutingStrategies.Bubble);
+ ///
+ /// Defines the event.
+ ///
+ public static readonly RoutedEvent TextChangedEvent =
+ RoutedEvent.Register(
+ nameof(TextChanged), RoutingStrategies.Bubble);
+
+ ///
+ /// Defines the event.
+ ///
+ public static readonly RoutedEvent TextChangingEvent =
+ RoutedEvent.Register(
+ nameof(TextChanging), RoutingStrategies.Bubble);
+
readonly struct UndoRedoState : IEquatable
{
public string? Text { get; }
@@ -359,8 +383,8 @@ namespace Avalonia.Controls
///
public double LineHeight
{
- get { return GetValue(LineHeightProperty); }
- set { SetValue(LineHeightProperty, value); }
+ get => GetValue(LineHeightProperty);
+ set => SetValue(LineHeightProperty, value);
}
[Content]
@@ -376,11 +400,19 @@ namespace Avalonia.Controls
CaretIndex = CoerceCaretIndex(caretIndex, value);
SelectionStart = CoerceCaretIndex(selectionStart, value);
SelectionEnd = CoerceCaretIndex(selectionEnd, value);
- if (SetAndRaise(TextProperty, ref _text, value) && IsUndoEnabled && !_isUndoingRedoing)
+
+ var textChanged = SetAndRaise(TextProperty, ref _text, value);
+
+ if (textChanged && IsUndoEnabled && !_isUndoingRedoing)
{
_undoRedoHelper.Clear();
SnapshotUndoRedo(); // so we always have an initial state
}
+
+ if (textChanged)
+ {
+ RaiseTextChangeEvents();
+ }
}
}
@@ -564,6 +596,27 @@ namespace Avalonia.Controls
remove => RemoveHandler(PastingFromClipboardEvent, value);
}
+ ///
+ /// Occurs asynchronously after text changes and the new text is rendered.
+ ///
+ public event EventHandler? TextChanged
+ {
+ add => AddHandler(TextChangedEvent, value);
+ remove => RemoveHandler(TextChangedEvent, value);
+ }
+
+ ///
+ /// Occurs synchronously when text starts to change but before it is rendered.
+ ///
+ ///
+ /// This event occurs just after the property value has been updated.
+ ///
+ public event EventHandler? TextChanging
+ {
+ add => AddHandler(TextChangingEvent, value);
+ remove => RemoveHandler(TextChangingEvent, value);
+ }
+
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
_presenter = e.NameScope.Get("PART_TextPresenter");
@@ -1252,7 +1305,7 @@ namespace Avalonia.Controls
if (text != null && _wordSelectionStart >= 0)
{
- var distance = caretIndex - _wordSelectionStart;
+ var distance = caretIndex - _wordSelectionStart;
if (distance <= 0)
{
@@ -1539,11 +1592,39 @@ namespace Avalonia.Controls
return text.Substring(start, end - start);
}
+ ///
+ /// Raises both the and events.
+ ///
+ ///
+ /// This must be called after the property is set.
+ ///
+ private void RaiseTextChangeEvents()
+ {
+ // Note the following sequence of these events (following WinUI)
+ // 1. TextChanging occurs synchronously when text starts to change but before it is rendered.
+ // This occurs after the Text property is set.
+ // 2. TextChanged occurs asynchronously after text changes and the new text is rendered.
+
+ var textChangingEventArgs = new TextChangingEventArgs(TextChangingEvent);
+ RaiseEvent(textChangingEventArgs);
+
+ Dispatcher.UIThread.Post(() =>
+ {
+ var textChangedEventArgs = new TextChangedEventArgs(TextChangedEvent);
+ RaiseEvent(textChangedEventArgs);
+ }, DispatcherPriority.Normal);
+ }
+
private void SetTextInternal(string value, bool raiseTextChanged = true)
{
if (raiseTextChanged)
{
- SetAndRaise(TextProperty, ref _text, value);
+ bool textChanged = SetAndRaise(TextProperty, ref _text, value);
+
+ if (textChanged)
+ {
+ RaiseTextChangeEvents();
+ }
}
else
{
diff --git a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
index d39d964277..5d5ffcc381 100644
--- a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
+++ b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
@@ -64,7 +64,7 @@ namespace Avalonia.Controls
return new TextInputMethodSurroundingText
{
- Text = lineText ?? "",
+ Text = lineText ?? "",
AnchorOffset = anchorOffset,
CursorOffset = cursorOffset
};
diff --git a/src/Avalonia.Controls/TextChangedEventArgs.cs b/src/Avalonia.Controls/TextChangedEventArgs.cs
new file mode 100644
index 0000000000..77c609f19b
--- /dev/null
+++ b/src/Avalonia.Controls/TextChangedEventArgs.cs
@@ -0,0 +1,20 @@
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Provides data specific to a TextChanged event.
+ ///
+ public class TextChangedEventArgs : RoutedEventArgs
+ {
+ public TextChangedEventArgs(RoutedEvent? routedEvent)
+ : base (routedEvent)
+ {
+ }
+
+ public TextChangedEventArgs(RoutedEvent? routedEvent, IInteractive? source)
+ : base(routedEvent, source)
+ {
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/TextChangingEventArgs.cs b/src/Avalonia.Controls/TextChangingEventArgs.cs
new file mode 100644
index 0000000000..4dedbc927b
--- /dev/null
+++ b/src/Avalonia.Controls/TextChangingEventArgs.cs
@@ -0,0 +1,20 @@
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Provides data specific to a TextChanging event.
+ ///
+ public class TextChangingEventArgs : RoutedEventArgs
+ {
+ public TextChangingEventArgs(RoutedEvent? routedEvent)
+ : base (routedEvent)
+ {
+ }
+
+ public TextChangingEventArgs(RoutedEvent? routedEvent, IInteractive? source)
+ : base(routedEvent, source)
+ {
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/Utils/ISelectionAdapter.cs b/src/Avalonia.Controls/Utils/ISelectionAdapter.cs
index c5fb12197f..3ede518ffa 100644
--- a/src/Avalonia.Controls/Utils/ISelectionAdapter.cs
+++ b/src/Avalonia.Controls/Utils/ISelectionAdapter.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Controls/Utils/SelectingItemsControlSelectionAdapter.cs b/src/Avalonia.Controls/Utils/SelectingItemsControlSelectionAdapter.cs
index 0288f99dce..3c1b1262ae 100644
--- a/src/Avalonia.Controls/Utils/SelectingItemsControlSelectionAdapter.cs
+++ b/src/Avalonia.Controls/Utils/SelectingItemsControlSelectionAdapter.cs
@@ -1,6 +1,6 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
-// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
diff --git a/src/Avalonia.Native/IconLoader.cs b/src/Avalonia.Native/IconLoader.cs
index edb8b94e83..04779a43aa 100644
--- a/src/Avalonia.Native/IconLoader.cs
+++ b/src/Avalonia.Native/IconLoader.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Native
// OSX doesn't have a concept of *window* icon.
// Icons in the title bar are only shown if there is
// an opened file (on disk) associated with the current window
- // see http://stackoverflow.com/a/7038671/2231814
+ // see https://stackoverflow.com/a/7038671/2231814
class IconLoader : IPlatformIconLoader
{
class IconStub : IWindowIconImpl
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf
index 847ffd191b..a372c5fcca 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-Bold.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf
index 33267cd799..13ef261fff 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-ExtraLight.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf
index c22eafe9fb..9f75ff2780 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-Light.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf
index f782894eea..2c5e25453c 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-Medium.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf
index 3b7e686e54..c28fe4d744 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-Regular.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf
index 556e972f48..d085eb4994 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-SemiBold.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf b/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf
index e49058e33d..016a13482b 100644
Binary files a/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf and b/src/Avalonia.Themes.Fluent/Assets/Inter-Thin.ttf differ
diff --git a/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml b/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
index 7042f51c71..9c66ea9b84 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
@@ -1,7 +1,7 @@
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
index d1aee7ee9a..06b6cf30c2 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
@@ -1,7 +1,7 @@
-
-
+
-
diff --git a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
index 0cfd491b21..6f1e4fccfe 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
@@ -1,7 +1,7 @@
@@ -153,11 +153,11 @@
-
-
-
diff --git a/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml b/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml
index be664b375d..7500ac7bca 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml
@@ -1,7 +1,7 @@
diff --git a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
index fcd661a4b5..cb88eac2ba 100644
--- a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
@@ -1,7 +1,7 @@
@@ -181,11 +181,11 @@
-
-
diff --git a/src/Avalonia.Themes.Simple/Controls/CalendarItem.xaml b/src/Avalonia.Themes.Simple/Controls/CalendarItem.xaml
index d9acd0d25a..2a9ae7cf8d 100644
--- a/src/Avalonia.Themes.Simple/Controls/CalendarItem.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/CalendarItem.xaml
@@ -1,7 +1,7 @@
diff --git a/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml b/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml
index 317a27435a..b4cf6313a6 100644
--- a/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/DatePicker.xaml
@@ -170,7 +170,7 @@
-
diff --git a/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml b/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml
index 5909a1abbf..8639a2baa2 100644
--- a/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/DateTimePickerShared.xaml
@@ -1,7 +1,7 @@
diff --git a/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml b/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml
index 5aa717e9ee..e02e3d8194 100644
--- a/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/TimePicker.xaml
@@ -189,7 +189,7 @@
-
diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs
index 424db94e0a..b00879bd1d 100644
--- a/src/Avalonia.X11/X11Atoms.cs
+++ b/src/Avalonia.X11/X11Atoms.cs
@@ -17,7 +17,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2006 Novell, Inc. (https://www.novell.com)
//
//
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 869602e452..55a1014188 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -2,6 +2,7 @@
+
Shared\_ModuleInitializer.cs
diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.CompilationTuning.props b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.CompilationTuning.props
deleted file mode 100644
index eb5e5dd733..0000000000
--- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.CompilationTuning.props
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- 16777216
- false
- false
-
-
diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
index 693a6a1462..1c31e0eb5d 100644
--- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
+++ b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
@@ -1,53 +1,40 @@
- net6.0
- enable
+ net7.0
Avalonia.Web.Blazor
- preview
- false
- true
+ _IncludeGeneratedAvaloniaStaticFiles;$(ResolveStaticWebAssetsInputsDependsOn)
-
-
-
-
- true
- build\
-
-
- true
- build\;buildTransitive\
-
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+ <_AvaloniaWebAssets Include="$(MSBuildThisFileDirectory)../Avalonia.Web/wwwroot/**/*.*" />
+
+
+
+
diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.props b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.props
deleted file mode 100644
index dd96a60c6a..0000000000
--- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.props
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs
deleted file mode 100644
index 11d9bcc98f..0000000000
--- a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Platform;
-
-namespace Avalonia.Web.Blazor
-{
- public class AvaloniaBlazorAppBuilder : AppBuilderBase
- {
- public AvaloniaBlazorAppBuilder(IRuntimePlatform platform, Action platformServices)
- : base(platform, platformServices)
- {
- }
-
- public AvaloniaBlazorAppBuilder()
- : base(new StandardRuntimePlatform(),
- builder => StandardRuntimePlatformServices.Register(builder.ApplicationType!.Assembly))
- {
- UseWindowingSubsystem(BlazorWindowingPlatform.Register);
- }
- }
-}
diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.cs
new file mode 100644
index 0000000000..909e2dd441
--- /dev/null
+++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.cs
@@ -0,0 +1,44 @@
+using System.Runtime.InteropServices.JavaScript;
+using System.Runtime.Versioning;
+using System.Threading.Tasks;
+using System;
+using Avalonia.Controls.ApplicationLifetimes;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Rendering;
+using BrowserView = Avalonia.Web.AvaloniaView;
+
+namespace Avalonia.Web.Blazor;
+
+[SupportedOSPlatform("browser")]
+public class AvaloniaView : ComponentBase
+{
+ private BrowserView? _browserView;
+ private readonly string _containerId;
+
+ public AvaloniaView()
+ {
+ _containerId = "av_container_" + Guid.NewGuid();
+ }
+
+ protected override void BuildRenderTree(RenderTreeBuilder builder)
+ {
+ builder.OpenElement(0, "div");
+ builder.AddAttribute(1, "id", _containerId);
+ builder.AddAttribute(2, "style", "width:100vw;height:100vh");
+ builder.CloseElement();
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (OperatingSystem.IsBrowser())
+ {
+ await Avalonia.Web.Interop.AvaloniaModule.ImportMain();
+
+ _browserView = new BrowserView(_containerId);
+ if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime lifetime)
+ {
+ _browserView.Content = lifetime.MainView;
+ }
+ }
+ }
+}
diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
deleted file mode 100644
index 5a3b9d5f71..0000000000
--- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs
deleted file mode 100644
index 5b5951e800..0000000000
--- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs
+++ /dev/null
@@ -1,501 +0,0 @@
-using System.Diagnostics;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Controls.Embedding;
-using Avalonia.Controls.Platform;
-using Avalonia.Input;
-using Avalonia.Input.Raw;
-using Avalonia.Input.TextInput;
-using Avalonia.Platform.Storage;
-using Avalonia.Rendering;
-using Avalonia.Rendering.Composition;
-using Avalonia.Web.Blazor.Interop;
-using Avalonia.Web.Blazor.Interop.Storage;
-
-using Microsoft.AspNetCore.Components;
-using Microsoft.AspNetCore.Components.Forms;
-using Microsoft.AspNetCore.Components.Web;
-using Microsoft.JSInterop;
-
-using SkiaSharp;
-using HTMLPointerEventArgs = Microsoft.AspNetCore.Components.Web.PointerEventArgs;
-
-namespace Avalonia.Web.Blazor
-{
- public partial class AvaloniaView : ITextInputMethodImpl
- {
- private readonly RazorViewTopLevelImpl _topLevelImpl;
- private EmbeddableControlRoot _topLevel;
-
- // Interop
- private SKHtmlCanvasInterop? _interop = null;
- private SizeWatcherInterop? _sizeWatcher = null;
- private DpiWatcherInterop? _dpiWatcher = null;
- private SKHtmlCanvasInterop.GLInfo? _jsGlInfo = null;
- private AvaloniaModule? _avaloniaModule = null;
- private InputHelperInterop? _inputHelper = null;
- private FocusHelperInterop? _canvasHelper = null;
- private FocusHelperInterop? _containerHelper = null;
- private NativeControlHostInterop? _nativeControlHost = null;
- private StorageProviderInterop? _storageProvider = null;
- private ElementReference _htmlCanvas;
- private ElementReference _inputElement;
- private ElementReference _containerElement;
- private ElementReference _nativeControlsContainer;
- private double _dpi = 1;
- private SKSize _canvasSize = new (100, 100);
-
- private GRContext? _context;
- private GRGlInterface? _glInterface;
- private const SKColorType ColorType = SKColorType.Rgba8888;
-
- private bool _useGL;
- private bool _inputElementFocused;
-
- private ITextInputMethodClient? _client;
-
-
- [Inject] private IJSRuntime Js { get; set; } = null!;
-
- public AvaloniaView()
- {
- _topLevelImpl = new RazorViewTopLevelImpl(this);
-
- _topLevel = new EmbeddableControlRoot(_topLevelImpl);
-
- if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime lifetime)
- {
- _topLevel.Content = lifetime.MainView;
- }
- }
-
- public bool KeyPreventDefault { get; set; }
-
- public ITextInputMethodClient? Client => _client;
-
- public bool IsActive => _client != null;
-
- public bool IsComposing { get; private set; }
-
- internal INativeControlHostImpl GetNativeControlHostImpl()
- {
- return _nativeControlHost ?? throw new InvalidOperationException("Blazor View wasn't initialized yet");
- }
-
- internal IStorageProvider GetStorageProvider()
- {
- return _storageProvider ?? throw new InvalidOperationException("Blazor View wasn't initialized yet");
- }
-
- private void OnPointerCancel(HTMLPointerEventArgs e)
- {
- if (e.PointerType == "touch")
- {
- _topLevelImpl.RawPointerEvent(RawPointerEventType.TouchCancel, e.PointerType, GetPointFromEventArgs(e),
- GetModifiers(e), e.PointerId);
- }
- }
-
- private void OnPointerMove(HTMLPointerEventArgs e)
- {
- var type = e.PointerType switch
- {
- "touch" => RawPointerEventType.TouchUpdate,
- _ => RawPointerEventType.Move
- };
-
- _topLevelImpl.RawPointerEvent(type, e.PointerType, GetPointFromEventArgs(e), GetModifiers(e), e.PointerId);
- }
-
- private void OnPointerUp(HTMLPointerEventArgs e)
- {
- var type = e.PointerType switch
- {
- "touch" => RawPointerEventType.TouchEnd,
- _ => e.Button switch
- {
- 0 => RawPointerEventType.LeftButtonUp,
- 1 => RawPointerEventType.MiddleButtonUp,
- 2 => RawPointerEventType.RightButtonUp,
- 3 => RawPointerEventType.XButton1Up,
- 4 => RawPointerEventType.XButton2Up,
- // 5 => Pen eraser button,
- _ => RawPointerEventType.Move
- }
- };
-
- _topLevelImpl.RawPointerEvent(type, e.PointerType, GetPointFromEventArgs(e), GetModifiers(e), e.PointerId);
- }
-
- private void OnPointerDown(HTMLPointerEventArgs e)
- {
- var type = e.PointerType switch
- {
- "touch" => RawPointerEventType.TouchBegin,
- _ => e.Button switch
- {
- 0 => RawPointerEventType.LeftButtonDown,
- 1 => RawPointerEventType.MiddleButtonDown,
- 2 => RawPointerEventType.RightButtonDown,
- 3 => RawPointerEventType.XButton1Down,
- 4 => RawPointerEventType.XButton2Down,
- // 5 => Pen eraser button,
- _ => RawPointerEventType.Move
- }
- };
-
- _topLevelImpl.RawPointerEvent(type, e.PointerType, GetPointFromEventArgs(e), GetModifiers(e), e.PointerId);
- }
-
- private static RawPointerPoint GetPointFromEventArgs(HTMLPointerEventArgs args)
- {
- return new RawPointerPoint
- {
- Position = new Point(args.ClientX, args.ClientY),
- Pressure = args.Pressure,
- XTilt = args.TiltX,
- YTilt = args.TiltY
- // Twist = args.Twist - read from JS code directly when
- };
- }
-
- private void OnWheel(WheelEventArgs e)
- {
- _topLevelImpl.RawMouseWheelEvent( new Point(e.ClientX, e.ClientY),
- new Vector(-(e.DeltaX / 50), -(e.DeltaY / 50)), GetModifiers(e));
- }
-
- private static RawInputModifiers GetModifiers(MouseEventArgs e)
- {
- var modifiers = RawInputModifiers.None;
-
- if (e.CtrlKey)
- modifiers |= RawInputModifiers.Control;
- if (e.AltKey)
- modifiers |= RawInputModifiers.Alt;
- if (e.ShiftKey)
- modifiers |= RawInputModifiers.Shift;
- if (e.MetaKey)
- modifiers |= RawInputModifiers.Meta;
-
- if ((e.Buttons & 1L) == 1)
- modifiers |= RawInputModifiers.LeftMouseButton;
-
- if ((e.Buttons & 2L) == 2)
- modifiers |= e.Type == "pen" ? RawInputModifiers.PenBarrelButton : RawInputModifiers.RightMouseButton;
-
- if ((e.Buttons & 4L) == 4)
- modifiers |= RawInputModifiers.MiddleMouseButton;
-
- if ((e.Buttons & 8L) == 8)
- modifiers |= RawInputModifiers.XButton1MouseButton;
-
- if ((e.Buttons & 16L) == 16)
- modifiers |= RawInputModifiers.XButton2MouseButton;
-
- if ((e.Buttons & 32L) == 32)
- modifiers |= RawInputModifiers.PenEraser;
-
- return modifiers;
- }
-
- private static RawInputModifiers GetModifiers(KeyboardEventArgs e)
- {
- var modifiers = RawInputModifiers.None;
-
- if (e.CtrlKey)
- modifiers |= RawInputModifiers.Control;
- if (e.AltKey)
- modifiers |= RawInputModifiers.Alt;
- if (e.ShiftKey)
- modifiers |= RawInputModifiers.Shift;
- if (e.MetaKey)
- modifiers |= RawInputModifiers.Meta;
-
- return modifiers;
- }
-
- private void OnKeyDown(KeyboardEventArgs e)
- {
- KeyPreventDefault = _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, e.Code, e.Key, GetModifiers(e));
- }
-
- private void OnKeyUp(KeyboardEventArgs e)
- {
- KeyPreventDefault = _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyUp, e.Code, e.Key, GetModifiers(e));
- }
-
- private void OnFocus(FocusEventArgs e)
- {
- // if focus has unexpectedly moved from the input element to the container element,
- // shift it back to the input element
- if (_inputElementFocused && _inputHelper is not null)
- {
- _inputHelper.Focus();
- }
- }
-
- [Parameter(CaptureUnmatchedValues = true)]
- public IReadOnlyDictionary? AdditionalAttributes { get; set; }
-
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (firstRender)
- {
- AvaloniaLocator.CurrentMutable.Bind().ToConstant((IJSInProcessRuntime)Js);
-
- _avaloniaModule = await AvaloniaModule.ImportAsync(Js);
-
- _canvasHelper = new FocusHelperInterop(_avaloniaModule, _htmlCanvas);
- _containerHelper = new FocusHelperInterop(_avaloniaModule, _containerElement);
- _inputHelper = new InputHelperInterop(_avaloniaModule, _inputElement);
-
- _inputHelper.CompositionEvent += InputHelperOnCompositionEvent;
- _inputHelper.InputEvent += InputHelperOnInputEvent;
-
- HideIme();
- _canvasHelper.SetCursor("default");
- _topLevelImpl.SetCssCursor = x =>
- {
- _inputHelper.SetCursor(x); //macOS
- _canvasHelper.SetCursor(x); //windows
- };
-
- _nativeControlHost = new NativeControlHostInterop(_avaloniaModule, _nativeControlsContainer);
- _storageProvider = await StorageProviderInterop.ImportAsync(Js);
-
- Console.WriteLine("starting html canvas setup");
- _interop = new SKHtmlCanvasInterop(_avaloniaModule, _htmlCanvas, OnRenderFrame);
-
- Console.WriteLine("Interop created");
-
- var skiaOptions = AvaloniaLocator.Current.GetService();
- _useGL = skiaOptions?.CustomGpuFactory != null;
-
- if (_useGL)
- {
- _jsGlInfo = _interop.InitGL();
- Console.WriteLine("jsglinfo created - init gl");
- }
- else
- {
- var rasterInitialized = _interop.InitRaster();
- Console.WriteLine("raster initialized: {0}", rasterInitialized);
- }
-
- if (_useGL)
- {
- // create the SkiaSharp context
- if (_context == null)
- {
- Console.WriteLine("create glcontext");
- _glInterface = GRGlInterface.Create();
- _context = GRContext.CreateGl(_glInterface);
-
-
- // bump the default resource cache limit
- _context.SetResourceCacheLimit(skiaOptions?.MaxGpuResourceSizeBytes ?? 32 * 1024 * 1024);
- Console.WriteLine("glcontext created and resource limit set");
- }
-
- _topLevelImpl.SetSurface(_context, _jsGlInfo!, ColorType,
- new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi);
- }
- else
- {
- _topLevelImpl.SetSurface(ColorType,
- new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi, _interop.PutImageData);
- }
-
- _interop.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi));
-
- Threading.Dispatcher.UIThread.Post(async () =>
- {
- _interop.RequestAnimationFrame(true);
-
- _sizeWatcher = new SizeWatcherInterop(_avaloniaModule, _htmlCanvas, OnSizeChanged);
- _dpiWatcher = new DpiWatcherInterop(_avaloniaModule, OnDpiChanged);
-
- _sizeWatcher.Start();
- _topLevel.Prepare();
-
- _topLevel.Renderer.Start();
- });
- }
- }
-
- private void InputHelperOnInputEvent(object? sender, WebInputEventArgs e)
- {
- if (IsComposing)
- {
- return;
- }
-
- _topLevelImpl.RawTextEvent(e.Data);
-
- e.Handled = true;
- }
-
- private void InputHelperOnCompositionEvent(object? sender, WebCompositionEventArgs e)
- {
- if(_client == null)
- {
- return;
- }
-
- switch (e.Type)
- {
- case WebCompositionEventArgs.WebCompositionEventType.Start:
- _client.SetPreeditText(null);
- IsComposing = true;
- break;
- case WebCompositionEventArgs.WebCompositionEventType.Update:
- _client.SetPreeditText(e.Data);
- break;
- case WebCompositionEventArgs.WebCompositionEventType.End:
- IsComposing = false;
- _client.SetPreeditText(null);
- _topLevelImpl.RawTextEvent(e.Data);
- break;
- }
- }
-
- private void OnRenderFrame()
- {
- if (_useGL && (_jsGlInfo == null))
- {
- Console.WriteLine("nothing to render");
- return;
- }
- if (_canvasSize.Width <= 0 || _canvasSize.Height <= 0 || _dpi <= 0)
- {
- Console.WriteLine("nothing to render");
- return;
- }
-
- ManualTriggerRenderTimer.Instance.RaiseTick();
- }
-
- public void Dispose()
- {
- _dpiWatcher?.Unsubscribe(OnDpiChanged);
- _sizeWatcher?.Dispose();
- _interop?.Dispose();
- }
-
- private void ForceBlit()
- {
- // Note: this is technically a hack, but it's a kinda unique use case when
- // we want to blit the previous frame
- // renderer doesn't have much control over the render target
- // we render on the UI thread
- // We also don't want to have it as a meaningful public API.
- // Therefore we have InternalsVisibleTo hack here.
-
- if (_topLevel.Renderer is CompositingRenderer dr)
- {
- dr.CompositionTarget.ImmediateUIThreadRender();
- }
- }
-
- private void OnDpiChanged(double newDpi)
- {
- if (Math.Abs(_dpi - newDpi) > 0.0001)
- {
- _dpi = newDpi;
-
- _interop!.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi));
-
- _topLevelImpl.SetClientSize(_canvasSize, _dpi);
-
- ForceBlit();
- }
- }
-
- private void OnSizeChanged(SKSize newSize)
- {
- if (_canvasSize != newSize)
- {
- _canvasSize = newSize;
-
- _interop!.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi));
-
- _topLevelImpl.SetClientSize(_canvasSize, _dpi);
-
- ForceBlit();
- }
- }
-
- private void HideIme()
- {
- _inputHelper?.Hide();
- _containerHelper?.Focus();
- }
-
- public void SetClient(ITextInputMethodClient? client)
- {
- if (_inputHelper is null)
- {
- return;
- }
-
- if(_client != null)
- {
- _client.SurroundingTextChanged -= SurroundingTextChanged;
- }
-
- if(client != null)
- {
- client.SurroundingTextChanged += SurroundingTextChanged;
- }
-
- _inputHelper.Clear();
-
- _client = client;
-
- if (IsActive && _client != null)
- {
- _inputHelper.Show();
- _inputElementFocused = true;
- _inputHelper.Focus();
-
- var surroundingText = _client.SurroundingText;
-
- _inputHelper?.SetSurroundingText(surroundingText.Text, surroundingText.AnchorOffset, surroundingText.CursorOffset);
- }
- else
- {
- _inputElementFocused = false;
- HideIme();
- }
- }
-
- private void SurroundingTextChanged(object? sender, EventArgs e)
- {
- if(_client != null)
- {
- var surroundingText = _client.SurroundingText;
-
- _inputHelper?.SetSurroundingText(surroundingText.Text, surroundingText.AnchorOffset, surroundingText.CursorOffset);
- }
- }
-
- public void SetCursorRect(Rect rect)
- {
- _inputHelper?.Focus();
- var bounds = new PixelRect((int)rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height);
-
- _inputHelper?.SetBounds(bounds, _client?.SurroundingText.CursorOffset ?? 0);
- _inputHelper?.Focus();
- }
-
- public void SetOptions(TextInputOptions options)
- {
- }
-
- public void Reset()
- {
- _inputHelper?.Clear();
- _inputHelper?.SetSurroundingText("", 0, 0);
- }
- }
-}
diff --git a/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs b/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs
index 7970f09a58..f38779f834 100644
--- a/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs
+++ b/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs
@@ -1,31 +1,39 @@
-using Avalonia.Controls;
+using System.Runtime.Versioning;
+
+using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Media;
-namespace Avalonia.Web.Blazor
+namespace Avalonia.Web.Blazor;
+
+[SupportedOSPlatform("browser")]
+public static class WebAppBuilder
{
- public class BlazorSingleViewLifetime : ISingleViewApplicationLifetime
+ public static T SetupWithSingleViewLifetime(
+ this T builder)
+ where T : AppBuilderBase, new()
{
- public Control? MainView { get; set; }
+ return builder.SetupWithLifetime(new BlazorSingleViewLifetime());
}
- public static class WebAppBuilder
+ public static T UseBlazor(this T builder) where T : AppBuilderBase, new()
{
- public static T SetupWithSingleViewLifetime(
- this T builder)
- where T : AppBuilderBase, new()
- {
- return builder.SetupWithLifetime(new BlazorSingleViewLifetime());
- }
+ return builder
+ .UseBrowser()
+ .With(new BrowserPlatformOptions
+ {
+ FrameworkAssetPathResolver = new(filePath => $"/_content/Avalonia.Web.Blazor/{filePath}")
+ });
+ }
- public static AvaloniaBlazorAppBuilder Configure()
- where TApp : Application, new()
- {
- var builder = AvaloniaBlazorAppBuilder.Configure()
- .UseSkia()
- .With(new SkiaOptions { CustomGpuFactory = () => new BlazorSkiaGpu() });
+ public static AppBuilder Configure()
+ where TApp : Application, new()
+ {
+ return AppBuilder.Configure()
+ .UseBlazor();
+ }
- return builder;
- }
+ internal class BlazorSingleViewLifetime : ISingleViewApplicationLifetime
+ {
+ public Control? MainView { get; set; }
}
}
diff --git a/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpuRenderSession.cs b/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpuRenderSession.cs
deleted file mode 100644
index 0c53825131..0000000000
--- a/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpuRenderSession.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using Avalonia.Skia;
-using SkiaSharp;
-
-namespace Avalonia.Web.Blazor
-{
- internal class BlazorSkiaGpuRenderSession : ISkiaGpuRenderSession
- {
- private readonly SKSurface _surface;
-
-
- public BlazorSkiaGpuRenderSession(BlazorSkiaSurface blazorSkiaSurface, GRBackendRenderTarget renderTarget)
- {
- _surface = SKSurface.Create(blazorSkiaSurface.Context, renderTarget, blazorSkiaSurface.Origin, blazorSkiaSurface.ColorType);
-
- GrContext = blazorSkiaSurface.Context;
-
- ScaleFactor = blazorSkiaSurface.Scaling;
-
- SurfaceOrigin = blazorSkiaSurface.Origin;
- }
-
- public void Dispose()
- {
- _surface.Flush();
-
- _surface.Dispose();
- }
-
- public GRContext GrContext { get; }
-
- public SKSurface SkSurface => _surface;
-
- public double ScaleFactor { get; }
-
- public GRSurfaceOrigin SurfaceOrigin { get; }
- }
-}
diff --git a/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpuRenderTarget.cs b/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpuRenderTarget.cs
deleted file mode 100644
index fa6a39f210..0000000000
--- a/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpuRenderTarget.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using Avalonia.Skia;
-using SkiaSharp;
-
-namespace Avalonia.Web.Blazor
-{
- internal class BlazorSkiaGpuRenderTarget : ISkiaGpuRenderTarget
- {
- private readonly GRBackendRenderTarget _renderTarget;
- private readonly BlazorSkiaSurface _blazorSkiaSurface;
- private readonly PixelSize _size;
-
- public BlazorSkiaGpuRenderTarget(BlazorSkiaSurface blazorSkiaSurface)
- {
- _size = blazorSkiaSurface.Size;
-
- var glFbInfo = new GRGlFramebufferInfo(blazorSkiaSurface.GlInfo.FboId, blazorSkiaSurface.ColorType.ToGlSizedFormat());
- {
- _blazorSkiaSurface = blazorSkiaSurface;
- _renderTarget = new GRBackendRenderTarget(
- (int)(blazorSkiaSurface.Size.Width * blazorSkiaSurface.Scaling),
- (int)(blazorSkiaSurface.Size.Height * blazorSkiaSurface.Scaling),
- blazorSkiaSurface.GlInfo.Samples,
- blazorSkiaSurface.GlInfo.Stencils, glFbInfo);
- }
- }
-
- public void Dispose()
- {
- _renderTarget.Dispose();
- }
-
- public ISkiaGpuRenderSession BeginRenderingSession()
- {
- return new BlazorSkiaGpuRenderSession(_blazorSkiaSurface, _renderTarget);
- }
-
- public bool IsCorrupted => _blazorSkiaSurface.Size != _size;
- }
-}
diff --git a/src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs b/src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs
deleted file mode 100644
index bafc07ca15..0000000000
--- a/src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Input;
-using Avalonia.Input.Platform;
-using Microsoft.JSInterop;
-
-namespace Avalonia.Web.Blazor
-{
- internal class ClipboardImpl : IClipboard
- {
- public async Task GetTextAsync()
- {
- return await AvaloniaLocator.Current.GetRequiredService().
- InvokeAsync("navigator.clipboard.readText");
- }
-
- public async Task SetTextAsync(string text)
- {
- await AvaloniaLocator.Current.GetRequiredService().
- InvokeAsync("navigator.clipboard.writeText",text);
- }
-
- public async Task ClearAsync() => await SetTextAsync("");
-
- public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask;
-
- public Task GetFormatsAsync() => Task.FromResult(Array.Empty());
-
- public Task