Browse Source

Merge branch 'master' into pull_refresh

pull/9437/head
Emmanuel Hansen 4 years ago
committed by GitHub
parent
commit
1810a18d26
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      .editorconfig
  2. 0
      .ncrunch/Avalonia.Benchmarks.v3.ncrunchproject
  3. 0
      .ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject
  4. 0
      .ncrunch/Avalonia.Browser.v3.ncrunchproject
  5. 0
      .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject
  6. 5
      .ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject
  7. 5
      .ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject
  8. 5
      .ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject
  9. 5
      .ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject
  10. 5
      .ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject
  11. 5
      .ncrunch/ControlCatalog.Browser.v3.ncrunchproject
  12. 5
      .ncrunch/MobileSandbox.v3.ncrunchproject
  13. 5
      .ncrunch/ReactiveUIDemo.v3.ncrunchproject
  14. 1
      Avalonia.Desktop.slnf
  15. 13
      Avalonia.sln
  16. 2
      build/SharedVersion.props
  17. 16
      build/TrimmingEnable.props
  18. 9
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  19. 1
      nukebuild/Build.cs
  20. 2
      nukebuild/_build.csproj
  21. 19
      packages/Avalonia/AvaloniaBuildTasks.targets
  22. 14
      samples/BindingDemo/App.xaml
  23. 9
      samples/ControlCatalog.NetCore/Program.cs
  24. 11
      samples/ControlCatalog.NetCore/Properties/launchSettings.json
  25. 10
      samples/ControlCatalog/ControlCatalog.csproj
  26. 29
      samples/ControlCatalog/Converter/DegToRadConverter.cs
  27. 3
      samples/ControlCatalog/MainView.xaml
  28. 25
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  29. 2
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  30. 107
      samples/ControlCatalog/Pages/CustomDrawing.xaml
  31. 67
      samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
  32. 215
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  33. 51
      samples/ControlCatalog/Pages/DataGridPage.xaml
  34. 18
      samples/ControlCatalog/Pages/ExpanderPage.xaml
  35. 6
      samples/ControlCatalog/Pages/ExpanderPage.xaml.cs
  36. 2
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  37. 1
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  38. 2
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  39. 3
      samples/ControlCatalog/Pages/ScreenPage.cs
  40. 8
      samples/ControlCatalog/Pages/TabControlPage.xaml
  41. 2
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  42. 36
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  43. 6
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  44. 3
      samples/Directory.Build.props
  45. 15
      samples/IntegrationTestApp/MainWindow.axaml
  46. 3
      samples/IntegrationTestApp/MainWindow.axaml.cs
  47. 8
      samples/IntegrationTestApp/ShowWindowTest.axaml
  48. 8
      samples/ReactiveUIDemo/App.axaml
  49. 37
      samples/ReactiveUIDemo/App.axaml.cs
  50. 19
      samples/ReactiveUIDemo/MainWindow.axaml
  51. 22
      samples/ReactiveUIDemo/MainWindow.axaml.cs
  52. 28
      samples/ReactiveUIDemo/ReactiveUIDemo.csproj
  53. 11
      samples/ReactiveUIDemo/ViewModels/BarViewModel.cs
  54. 11
      samples/ReactiveUIDemo/ViewModels/FooViewModel.cs
  55. 9
      samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs
  56. 21
      samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs
  57. 16
      samples/ReactiveUIDemo/Views/BarView.axaml
  58. 28
      samples/ReactiveUIDemo/Views/BarView.axaml.cs
  59. 16
      samples/ReactiveUIDemo/Views/FooView.axaml
  60. 28
      samples/ReactiveUIDemo/Views/FooView.axaml.cs
  61. 4
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  62. 1
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  63. 25
      src/Android/Avalonia.Android/AvaloniaMainActivity.cs
  64. 24
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  65. 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  66. 2
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
  67. 2
      src/Avalonia.Base/Animation/Animation.cs
  68. 4
      src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
  69. 3
      src/Avalonia.Base/Animation/Animators/Animator`1.cs
  70. 2
      src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
  71. 2
      src/Avalonia.Base/Animation/CrossFade.cs
  72. 2
      src/Avalonia.Base/Animation/KeySpline.cs
  73. 2
      src/Avalonia.Base/Animation/PageSlide.cs
  74. 2
      src/Avalonia.Base/AttachedProperty.cs
  75. 10
      src/Avalonia.Base/Avalonia.Base.csproj
  76. 2
      src/Avalonia.Base/AvaloniaObject.cs
  77. 100
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  78. 26
      src/Avalonia.Base/AvaloniaProperty.cs
  79. 6
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
  80. 4
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
  81. 14
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  82. 4
      src/Avalonia.Base/AvaloniaProperty`1.cs
  83. 4
      src/Avalonia.Base/ClassBindingManager.cs
  84. 4
      src/Avalonia.Base/Collections/AvaloniaListConverter.cs
  85. 121
      src/Avalonia.Base/Compatibility/TrimmingAttributes.cs
  86. 6
      src/Avalonia.Base/Controls/Classes.cs
  87. 2
      src/Avalonia.Base/Controls/ISetInheritanceParent.cs
  88. 3
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  89. 2
      src/Avalonia.Base/CornerRadius.cs
  90. 4
      src/Avalonia.Base/Data/BindingOperations.cs
  91. 22
      src/Avalonia.Base/Data/BindingPriority.cs
  92. 3
      src/Avalonia.Base/Data/BindingValue.cs
  93. 2
      src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
  94. 2
      src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs
  95. 4
      src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
  96. 2
      src/Avalonia.Base/Data/Core/BindingExpression.cs
  97. 2
      src/Avalonia.Base/Data/Core/ExpressionNode.cs
  98. 5
      src/Avalonia.Base/Data/Core/ExpressionObserver.cs
  99. 4
      src/Avalonia.Base/Data/Core/Parsers/ExpressionTreeParser.cs
  100. 6
      src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs

18
.editorconfig

@ -64,7 +64,7 @@ dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case
dotnet_naming_style.static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
@ -137,14 +137,30 @@ space_within_single_line_array_initializer_braces = true
#Net Analyzer
dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed.
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = suggestion
# CA1304: Specify CultureInfo
dotnet_diagnostic.CA1304.severity = warning
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
# CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers
dotnet_diagnostic.CA1821.severity = warning
# CA1822: Mark members as static
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_code_quality.CA1822.api_surface = private, internal
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
# CA1826: Use property instead of Linq Enumerable method
dotnet_diagnostic.CA1826.severity = suggestion
# CA1827: Do not use Count/LongCount when Any can be used
dotnet_diagnostic.CA1827.severity = warning
# CA1828: Do not use CountAsync/LongCountAsync when AnyAsync can be used
dotnet_diagnostic.CA1828.severity = warning
# CA1829: Use Length/Count property instead of Enumerable.Count method
dotnet_diagnostic.CA1829.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning

0
.ncrunch/Avalonia.Web.Blazor.v3.ncrunchproject → .ncrunch/Avalonia.Benchmarks.v3.ncrunchproject

0
.ncrunch/Avalonia.Web.v3.ncrunchproject → .ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject

0
.ncrunch/ControlCatalog.Blazor.Web.v3.ncrunchproject → .ncrunch/Avalonia.Browser.v3.ncrunchproject

0
.ncrunch/ControlCatalog.Web.v3.ncrunchproject → .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject

5
.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<InstrumentOutputAssembly>False</InstrumentOutputAssembly>
</Settings>
</ProjectConfiguration>

5
.ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject

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

5
.ncrunch/ControlCatalog.Browser.v3.ncrunchproject

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

5
.ncrunch/MobileSandbox.v3.ncrunchproject

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

5
.ncrunch/ReactiveUIDemo.v3.ncrunchproject

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

1
Avalonia.Desktop.slnf

@ -9,6 +9,7 @@
"samples\\MiniMvvm\\MiniMvvm.csproj",
"samples\\SampleControls\\ControlSamples.csproj",
"samples\\Sandbox\\Sandbox.csproj",
"samples\\ReactiveUIDemo\\ReactiveUIDemo.csproj",
"src\\Avalonia.Base\\Avalonia.Base.csproj",
"src\\Avalonia.Build.Tasks\\Avalonia.Build.Tasks.csproj",
"src\\Avalonia.Controls.ColorPicker\\Avalonia.Controls.ColorPicker.csproj",

13
Avalonia.sln

@ -40,6 +40,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
.editorconfig = .editorconfig
src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
src\Shared\NullableAttributes.cs = src\Shared\NullableAttributes.cs
src\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs
src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs = src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs
EndProjectSection
@ -119,6 +120,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\SourceLink.props = build\SourceLink.props
build\System.Drawing.Common.props = build\System.Drawing.Common.props
build\System.Memory.props = build\System.Memory.props
build\TrimmingEnable.props = build\TrimmingEnable.props
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\XUnit.props = build\XUnit.props
EndProjectSection
@ -222,14 +224,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.iOS", "sample
EndProject
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}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser.Blazor", "samples\ControlCatalog.Browser.Blazor\ControlCatalog.Browser.Blazor.csproj", "{90B08091-9BBD-4362-B712-E9F2CC62B218}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\ReactiveUIDemo\ReactiveUIDemo.csproj", "{75C47156-C5D8-44BC-A5A7-E8657C2248D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -541,6 +545,10 @@ Global
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.Build.0 = Release|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -605,6 +613,7 @@ Global
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{15B93A4C-1B46-43F6-B534-7B25B6E99932} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

2
build/SharedVersion.props

@ -7,7 +7,7 @@
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>CS1591</NoWarn>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<LangVersion>preview</LangVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>

16
build/TrimmingEnable.props

@ -0,0 +1,16 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
<!-- Remove check for the AOT when we get rid of dependencies with reflection -->
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0' and '$(PublishAot)' != 'true'">
<ILLinkTreatWarningsAsErrors>true</ILLinkTreatWarningsAsErrors>
<!-- Trim warnings -->
<WarningsAsErrors>$(WarningsAsErrors);IL2000;IL2001;IL2002;IL2003;IL2004;IL2005;IL2006;IL2007;IL2008;IL2009;IL2010;IL2011;IL2012;IL2013;IL2014;IL2015;IL2016;IL2017;IL2018;IL2019;IL2020;IL2021;IL2022;IL2023;IL2024;IL2025;IL2026;IL2027;IL2028;IL2029;IL2030;IL2031;IL2032;IL2033;IL2034;IL2035;IL2036;IL2037;IL2038;IL2039;IL2040;IL2041;IL2042;IL2043;IL2044;IL2045;IL2046;IL2047;IL2048;IL2049;IL2050;IL2051;IL2052;IL2053;IL2054;IL2055;IL2056;IL2057;IL2058;IL2059;IL2060;IL2061;IL2062;IL2063;IL2064;IL2065;IL2066;IL2067;IL2068;IL2069;IL2070;IL2071;IL2072;IL2073;IL2074;IL2075;IL2076;IL2077;IL2078;IL2079;IL2080;IL2081;IL2082;IL2083;IL2084;IL2085;IL2086;IL2087;IL2088;IL2089;IL2090;IL2091;IL2092;IL2093;IL2094;IL2095;IL2096;IL2097;IL2098;IL2099;IL2100;IL2101;IL2102;IL2103;IL2104;IL2105;IL2106;IL2107;IL2108;IL2109;IL2110;IL2111;IL2112;IL2113;IL2114;IL2115;IL2116;IL2117;IL2118;IL2119;IL2120;IL2121;IL2122;IL2123;IL2124;IL2125;IL2126;IL2127;IL2128;IL2129;IL2130;IL2131;IL2132;IL2133;IL2134;IL2135;IL2136;IL2137;IL2138;IL2139;IL2140;IL2141;IL2142;IL2143;IL2144;IL2145;IL2146;IL2147;IL2148;IL2149;IL2150;IL2151;IL2152;IL2153;IL2154;IL2155;IL2156;IL2157</WarningsAsErrors>
<!-- NativeAOT warnings -->
<WarningsAsErrors>$(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056</WarningsAsErrors>
</PropertyGroup>
</Project>

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

@ -137,7 +137,11 @@ void WindowImpl::BringToFront()
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
(*iterator)->BringToFront();
auto window = (*iterator)->Window;
// #9565: Only bring window to front if it's on the currently active space
if ([window isOnActiveSpace])
(*iterator)->BringToFront();
}
}
}
@ -161,6 +165,9 @@ void WindowImpl::StartStateTransition() {
void WindowImpl::EndStateTransition() {
_transitioningWindowState = false;
// Ensure correct order of child windows after fullscreen transition.
BringToFront();
}
SystemDecorations WindowImpl::Decorations() {

1
nukebuild/Build.cs

@ -80,7 +80,6 @@ partial class Build : NukeBuild
if (Parameters.IsRunningOnAzure)
c.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64"));
c.AddProperty("PackageVersion", Parameters.Version)
.AddProperty("iOSRoslynPathHackRequired", true)
.SetConfiguration(Parameters.Configuration)
.SetVerbosity(DotNetVerbosity.Minimal);
return c;

2
nukebuild/_build.csproj

@ -4,7 +4,7 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace></RootNamespace>
<IsPackable>False</IsPackable>
<NoWarn>CS0649;CS0169;SYSLIB0011</NoWarn>
<NoWarn>$(NoWarn);CS0649;CS0169;SYSLIB0011</NoWarn>
<NukeTelemetryVersion>1</NukeTelemetryVersion>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

19
packages/Avalonia/AvaloniaBuildTasks.targets

@ -30,7 +30,9 @@
/>
<Target Name="AddAvaloniaResources" BeforeTargets="ResolveReferences">
<Target Name="AddAvaloniaResources"
BeforeTargets="ResolveReferences"
Condition="('@(AvaloniaResource->Count())' &gt; 0) or ('@(AvaloniaXaml->Count())' &gt; 0)">
<PropertyGroup>
<AvaloniaResourcesTemporaryFilePath Condition="'$(AvaloniaResourcesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/resources</AvaloniaResourcesTemporaryFilePath>
</PropertyGroup>
@ -62,7 +64,9 @@
BeforeTargets="CoreCompile;CoreResGen"
Inputs="@(AvaloniaResource);@(AvaloniaXaml);@(CustomAdditionalGenerateAvaloniaResourcesInputs);$(MSBuildAllProjects)"
Outputs="$(AvaloniaResourcesTemporaryFilePath)"
DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)">
DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)"
Condition="('@(AvaloniaResource->Count())' &gt; 0) or ('@(AvaloniaXaml->Count())' &gt; 0)"
>
<ItemGroup>
<AvaloniaResource Include="@(AvaloniaXaml)"/>
</ItemGroup>
@ -74,14 +78,19 @@
ReportImportance="$(AvaloniaXamlReportImportance)"/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
</Target>
<Target
Name="CompileAvaloniaXaml"
AfterTargets="AfterCompile"
Condition="Exists('@(IntermediateAssembly)') And $(DesignTimeBuild) != true And $(EnableAvaloniaXamlCompilation) != false"
Condition="
(('@(AvaloniaResource->Count())' &gt; 0)
or ('@(AvaloniaXaml->Count())' &gt; 0))
and Exists('@(IntermediateAssembly)')
And $(DesignTimeBuild) != true
And $(EnableAvaloniaXamlCompilation) != false"
>
<PropertyGroup>
<AvaloniaXamlReferencesTemporaryFilePath Condition="'$(AvaloniaXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/references</AvaloniaXamlReferencesTemporaryFilePath>
@ -112,7 +121,7 @@
/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
</Target>

14
samples/BindingDemo/App.xaml

@ -2,8 +2,14 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BindingDemo.App">
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Themes.Simple/Accents/BaseLight.xaml"/>
</Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://Avalonia.Themes.Simple/Accents/BaseLight.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

9
samples/ControlCatalog.NetCore/Program.cs

@ -99,6 +99,15 @@ namespace ControlCatalog.NetCore
SilenceConsole();
return builder.StartLinuxDrm(args, scaling: GetScaling());
}
else if (args.Contains("--dxgi"))
{
builder.With(new Win32PlatformOptions()
{
UseLowLatencyDxgiSwapChain = true,
UseWindowsUIComposition = false
});
return builder.StartWithClassicDesktopLifetime(args);
}
else
return builder.StartWithClassicDesktopLifetime(args);
}

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

@ -0,0 +1,11 @@
{
"profiles": {
"ControlCatalog.NetCore": {
"commandName": "Project"
},
"Dxgi": {
"commandName": "Project",
"commandLineArgs": "--dxgi"
}
}
}

10
samples/ControlCatalog/ControlCatalog.csproj

@ -33,4 +33,14 @@
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
<ItemGroup>
<None Remove="Pages\CustomDrawing.xaml" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Update="Pages\CustomDrawing.xaml">
<Generator></Generator>
</AvaloniaResource>
</ItemGroup>
</Project>

29
samples/ControlCatalog/Converter/DegToRadConverter.cs

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Avalonia.Data.Converters;
namespace ControlCatalog.Converter
{
public class DegToRadConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is double rad)
{
return rad * 180.0d / Math.PI;
}
return 0.0d;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is double deg)
{
return deg / 180.0d * Math.PI;
}
return 0.0d;
}
}
}

3
samples/ControlCatalog/MainView.xaml

@ -66,6 +66,9 @@
<TabItem Header="Cursor" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CursorPage />
</TabItem>
<TabItem Header="Custom Drawing" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CustomDrawing/>
</TabItem>
<TabItem Header="DataGrid"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled">

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

@ -14,7 +14,26 @@ namespace ControlCatalog.Pages
{
public class AutoCompleteBoxPage : UserControl
{
private StateData[] BuildAllStates()
public class StateData
{
public string Name { get; private set; }
public string Abbreviation { get; private set; }
public string Capital { get; private set; }
public StateData(string name, string abbreviatoin, string capital)
{
Name = name;
Abbreviation = abbreviatoin;
Capital = capital;
}
public override string ToString()
{
return Name;
}
}
private static StateData[] BuildAllStates()
{
return new StateData[]
{
@ -72,7 +91,7 @@ namespace ControlCatalog.Pages
}
public StateData[] States { get; private set; }
private LinkedList<string>[] BuildAllSentences()
private static LinkedList<string>[] BuildAllSentences()
{
return new string[]
{
@ -124,7 +143,7 @@ namespace ControlCatalog.Pages
.OfType<AutoCompleteBox>();
}
private bool StringContains(string str, string? query)
private static bool StringContains(string str, string? query)
{
if (query == null) return false;
return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;

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

@ -25,7 +25,7 @@ public partial class CompositionPage : UserControl
this.Get<ItemsControl>("Items").Items = CreateColorItems();
}
private List<CompositionPageColorItem> CreateColorItems()
private static List<CompositionPageColorItem> CreateColorItems()
{
var list = new List<CompositionPageColorItem>();

107
samples/ControlCatalog/Pages/CustomDrawing.xaml

@ -0,0 +1,107 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:ControlCatalog.Pages"
xmlns:converters="using:ControlCatalog.Converter"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ControlCatalog.Pages.CustomDrawing">
<UserControl.Resources>
<converters:DegToRadConverter x:Key="DegToRadConverter"/>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical">
<TextBlock Text="Translation" HorizontalAlignment="Center"/>
<Grid ColumnDefinitions="*,*"
RowDefinitions="Auto,Auto"
>
<TextBlock Text="Horizontal"/>
<TextBlock Text="Vertical" Grid.Column="1"/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=ViewportCenterX,
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1"
/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=ViewportCenterY,
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1" Grid.Column="1"
/>
</Grid>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Column="1"
>
<TextBlock Text="Rotation" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
>
<Button Content="➖" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="RotateMinus"
/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=Rotation,
Converter={StaticResource DegToRadConverter},
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1" Grid.Column="1"
/>
<Button Content="➕" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="RotatePlus"
/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Column="2"
>
<TextBlock Text="Scale" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
>
<Button Content="➖" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="ZoomOut"
/>
<TextBox IsEnabled="False"
Text="{Binding ElementName=CustomDrawingControl,
Path=Scale,
Mode=OneWay,
StringFormat=\{0:g4\}}"
Grid.Row="1" Grid.Column="1"
/>
<Button Content="➕" Width="40" Height="40"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Click="ZoomIn"
/>
</StackPanel>
</StackPanel>
<Grid Grid.Row="1" Grid.ColumnSpan="3" ClipToBounds="True">
<local:CustomDrawingExampleControl
x:Name="CustomDrawingControl"
/>
</Grid>
</Grid>
</UserControl>

67
samples/ControlCatalog/Pages/CustomDrawing.xaml.cs

@ -0,0 +1,67 @@
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages
{
public partial class CustomDrawing : UserControl
{
public CustomDrawing()
{
InitializeComponent();
}
private CustomDrawingExampleControl? _customControl;
public CustomDrawingExampleControl CustomDrawingControl
{
get
{
if (_customControl is not null)
return _customControl;
throw new System.Exception("Control did not get initialized");
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
var cntrl = this.FindControl<CustomDrawingExampleControl>("CustomDrawingControl");
if (cntrl != null)
{
_customControl = cntrl;
}
else
{
// be sad about it
}
}
private void RotateMinus (object? sender, RoutedEventArgs e)
{
if (_customControl is null) return;
_customControl.Rotation -= Math.PI / 20.0d;
}
private void RotatePlus(object? sender, RoutedEventArgs e)
{
if (_customControl is null)
return;
_customControl.Rotation += Math.PI / 20.0d;
}
private void ZoomIn(object? sender, RoutedEventArgs e)
{
if (_customControl is null)
return;
_customControl.Scale *= 1.2d;
}
private void ZoomOut(object? sender, RoutedEventArgs e)
{
if (_customControl is null)
return;
_customControl.Scale /= 1.2d;
}
}
}

215
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

@ -0,0 +1,215 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Input;
using Avalonia.Threading;
using Avalonia.Controls.Shapes;
namespace ControlCatalog.Pages
{
public class CustomDrawingExampleControl : Control
{
private Point _cursorPoint;
public StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
public StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation));
/// <summary>
/// Rotation, measured in Radians!
/// </summary>
public double Rotation
{
get => GetValue(RotationProperty);
set
{
double valueToUse = value % (Math.PI * 2);
SetValue(RotationProperty, valueToUse);
}
}
public StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); }
public StyledProperty<double> ViewportCenterXProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterX), 0.0d);
public double ViewportCenterX { get => GetValue(ViewportCenterXProperty); set => SetValue(ViewportCenterXProperty, value); }
private IPen _pen;
private System.Diagnostics.Stopwatch _timeKeeper = System.Diagnostics.Stopwatch.StartNew();
private bool _isPointerCaptured = false;
public CustomDrawingExampleControl()
{
_pen = new Pen(new SolidColorBrush(Colors.Black), lineCap: PenLineCap.Round);
var _arc = new ArcSegment()
{
IsLargeArc = false,
Point = new Point(0, 0),
RotationAngle = 0,
Size = new Size(25, 25),
SweepDirection = SweepDirection.Clockwise,
};
StreamGeometry sg = new StreamGeometry();
var cntx = sg.Open();
cntx.BeginFigure(new Point(-25.0d, -10.0d), false);
cntx.ArcTo(new Point(25.0d, -10.0d), new Size(10.0d, 10.0d), 0.0d, false, SweepDirection.Clockwise);
cntx.EndFigure(true);
_smileGeometry = sg.Clone();
}
private Geometry _smileGeometry;
protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);
Point previousPoint = _cursorPoint;
_cursorPoint = e.GetPosition(this);
if (_isPointerCaptured)
{
Point oldWorldPoint = UIPointToWorldPoint(previousPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
Vector diff = newWorldPoint - oldWorldPoint;
ViewportCenterX -= diff.X;
ViewportCenterY -= diff.Y;
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
e.Handled = true;
e.Pointer.Capture(this);
_isPointerCaptured = true;
base.OnPointerPressed(e);
}
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
base.OnPointerWheelChanged(e);
var oldScale = Scale;
Scale *= (1.0d + e.Delta.Y / 12.0d);
Point oldWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, oldScale, Rotation);
Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
Vector diff = newWorldPoint - oldWorldPoint;
ViewportCenterX -= diff.X;
ViewportCenterY -= diff.Y;
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
e.Pointer.Capture(null);
_isPointerCaptured = false;
base.OnPointerReleased(e);
}
public override void Render(DrawingContext context)
{
var localBounds = new Rect(new Size(this.Bounds.Width, this.Bounds.Height));
var clip = context.PushClip(this.Bounds);
context.DrawRectangle(Brushes.White, _pen, localBounds, 1.0d);
var halfMax = Math.Max(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) * Math.Sqrt(2.0d);
var halfMin = Math.Min(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) / 1.3d;
var halfWidth = this.Bounds.Width / 2.0d;
var halfHeight = this.Bounds.Height / 2.0d;
// 0,0 refers to the top-left of the control now. It is not prime time to draw gui stuff because it'll be under the world
var translateModifier = context.PushPreTransform(Avalonia.Matrix.CreateTranslation(new Avalonia.Vector(halfWidth, halfHeight)));
// now 0,0 refers to the ViewportCenter(X,Y).
var rotationMatrix = Avalonia.Matrix.CreateRotation(Rotation);
var rotationModifier = context.PushPreTransform(rotationMatrix);
// everything is rotated but not scaled
var scaleModifier = context.PushPreTransform(Avalonia.Matrix.CreateScale(Scale, -Scale));
var mapPositionModifier = context.PushPreTransform(Matrix.CreateTranslation(new Vector(-ViewportCenterX, -ViewportCenterY)));
// now everything is rotated and scaled, and at the right position, now we're drawing strictly in world coordinates
context.DrawEllipse(Brushes.White, _pen, new Point(0.0d, 0.0d), 50.0d, 50.0d);
context.DrawLine(_pen, new Point(-25.0d, -5.0d), new Point(-25.0d, 15.0d));
context.DrawLine(_pen, new Point(25.0d, -5.0d), new Point(25.0d, 15.0d));
context.DrawGeometry(null, _pen, _smileGeometry);
Point cursorInWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
context.DrawEllipse(Brushes.Gray, _pen, cursorInWorldPoint, 20.0d, 20.0d);
for (int i = 0; i < 10; i++)
{
double orbitRadius = i * 100 + 200;
var orbitInput = ((_timeKeeper.Elapsed.TotalMilliseconds + 987654d) / orbitRadius) / 10.0d;
if (i % 3 == 0)
orbitInput *= -1;
Point orbitPosition = new Point(Math.Sin(orbitInput) * orbitRadius, Math.Cos(orbitInput) * orbitRadius);
context.DrawEllipse(Brushes.Gray, _pen, orbitPosition, 20.0d, 20.0d);
}
// end drawing the world
mapPositionModifier.Dispose();
scaleModifier.Dispose();
rotationModifier.Dispose();
translateModifier.Dispose();
// this is prime time to draw gui stuff
context.DrawLine(_pen, _cursorPoint + new Vector(-20, 0), _cursorPoint + new Vector(20, 0));
context.DrawLine(_pen, _cursorPoint + new Vector(0, -20), _cursorPoint + new Vector(0, 20));
clip.Dispose();
// oh and draw again when you can, no rush, right?
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
}
private Point UIPointToWorldPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
{
Point workingPoint = new Point(inPoint.X, -inPoint.Y);
workingPoint += new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
workingPoint /= scale;
workingPoint = Matrix.CreateRotation(rotation).Transform(workingPoint);
workingPoint += new Vector(viewportCenterX, viewportCenterY);
return workingPoint;
}
private Point WorldPointToUIPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
{
Point workingPoint = new Point(inPoint.X, inPoint.Y);
workingPoint -= new Vector(viewportCenterX, viewportCenterY);
// undo rotation
workingPoint = Matrix.CreateRotation(-rotation).Transform(workingPoint);
workingPoint *= scale;
workingPoint -= new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
workingPoint = new Point(workingPoint.X, -workingPoint.Y);
return workingPoint;
}
}
}

51
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -14,22 +14,6 @@
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</ControlTheme>
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="DataGridColumnHeader:nth-last-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="DataGridCell:nth-last-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="DataGrid#dataGridGrouping DataGridRow:nth-child(5n+3)">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="DataGrid#dataGridGrouping DataGridRow:nth-last-child(5n+1)">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,Auto,*">
<StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
<TextBlock Classes="h2">A control for displaying and interacting with a data source.</TextBlock>
@ -45,8 +29,7 @@
<CheckBox x:Name="ShowGDP" IsChecked="True" Content="Toggle GDP Column Visibility"
DockPanel.Dock="Top"/>
<DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All"
RowBackground="#1000"
AlternatingRowBackground="#1fff">
RowBackground="#1000">
<DataGrid.Columns>
<!-- Using HeaderTemplate -->
<DataGridTextColumn Header="Country" HeaderTemplate="{StaticResource Demo.DataTemplates.CountryHeader}" Binding="{Binding Name}" Width="6*" x:DataType="local:Country" />
@ -59,6 +42,24 @@
IsVisible="{Binding #ShowGDP.IsChecked}"
x:DataType="local:Country" />
</DataGrid.Columns>
<DataGrid.CellTheme>
<ControlTheme TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<ControlTheme.Children>
<Style Selector="^:nth-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme.Children>
</ControlTheme>
</DataGrid.CellTheme>
<DataGrid.ColumnHeaderTheme>
<ControlTheme TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<ControlTheme.Children>
<Style Selector="^:nth-child(1)">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme.Children>
</ControlTheme>
</DataGrid.ColumnHeaderTheme>
</DataGrid>
</DockPanel>
</TabItem>
@ -71,6 +72,20 @@
<DataGridTextColumn DisplayIndex="2" Header="Area" Binding="{Binding Area}" Width="3*" x:DataType="local:Country" />
<DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" x:DataType="local:Country" />
</DataGrid.Columns>
<DataGrid.RowTheme>
<ControlTheme TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<ControlTheme.Children>
<Style Selector="^:nth-child(5n+3)">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="^:nth-last-child(5n+1)">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme.Children>
</ControlTheme>
</DataGrid.RowTheme>
</DataGrid>
</TabItem>
<TabItem x:Name="EditableTab" Header="Editable">

18
samples/ControlCatalog/Pages/ExpanderPage.xaml

@ -52,6 +52,24 @@
</StackPanel>
</Expander>
<CheckBox IsChecked="{Binding Rounded}">Rounded</CheckBox>
<Expander x:Name="CollapsingDisabledExpander"
Header="Collapsing Disabled"
IsExpanded="True"
ExpandDirection="Down"
CornerRadius="{Binding CornerRadius}">
<StackPanel>
<TextBlock>Expanded content</TextBlock>
</StackPanel>
</Expander>
<Expander x:Name="ExpandingDisabledExpander"
Header="Expanding Disabled"
IsExpanded="False"
ExpandDirection="Down"
CornerRadius="{Binding CornerRadius}">
<StackPanel>
<TextBlock>Expanded content</TextBlock>
</StackPanel>
</Expander>
</StackPanel>
</StackPanel>
</UserControl>

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

@ -10,6 +10,12 @@ namespace ControlCatalog.Pages
{
this.InitializeComponent();
DataContext = new ExpanderPageViewModel();
var CollapsingDisabledExpander = this.Get<Expander>("CollapsingDisabledExpander");
var ExpandingDisabledExpander = this.Get<Expander>("ExpandingDisabledExpander");
CollapsingDisabledExpander.Collapsing += (s, e) => { e.Handled = true; };
ExpandingDisabledExpander.Expanding += (s, e) => { e.Handled = true; };
}
private void InitializeComponent()

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

@ -58,7 +58,7 @@ namespace ControlCatalog.Pages
}
}
private PixelRect GetCropRect(int index)
private static PixelRect GetCropRect(int index)
{
var bitmapWidth = 640;
var bitmapHeight = 426;

1
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -32,6 +32,7 @@
</StackPanel>
<ListBox Items="{Binding Items}"
Selection="{Binding Selection}"
DisplayMemberBinding="{Binding (viewModels:ItemModel).ID, StringFormat='{}Item {0:N0}'}"
AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}"
SelectionMode="{Binding SelectionMode^}"
WrapSelection="{Binding WrapSelection}"/>

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

@ -247,7 +247,7 @@ namespace ControlCatalog.Pages
}
private void CheckError(GlInterface gl)
private static void CheckError(GlInterface gl)
{
int err;
while ((err = gl.GetError()) != GL_NO_ERROR)

3
samples/ControlCatalog/Pages/ScreenPage.cs

@ -66,6 +66,7 @@ namespace ControlCatalog.Pages
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText =
@ -77,7 +78,7 @@ namespace ControlCatalog.Pages
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10));
}
private FormattedText CreateFormattedText(string textToFormat)
private static FormattedText CreateFormattedText(string textToFormat)
{
return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
Typeface.Default, 12, Brushes.Green);

8
samples/ControlCatalog/Pages/TabControlPage.xaml

@ -53,14 +53,8 @@
<TabControl
Items="{Binding Tabs}"
Margin="0 16"
HeaderDisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
TabStripPlacement="{Binding TabPlacement}">
<TabControl.ItemTemplate>
<DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
<TextBlock
Text="{Binding Header}">
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
<StackPanel Orientation="Vertical" Spacing="8">

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

@ -49,7 +49,7 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
private IBitmap LoadBitmap(string uri)
private static IBitmap LoadBitmap(string uri)
{
var assets = AvaloniaLocator.Current!.GetService<IAssetLoader>()!;
return new Bitmap(assets.Open(new Uri(uri)));

36
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
using ControlCatalog.Pages;
using MiniMvvm;
namespace ControlCatalog.ViewModels
@ -20,9 +21,9 @@ namespace ControlCatalog.ViewModels
public ListBoxPageViewModel()
{
Items = new ObservableCollection<string>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
Items = new ObservableCollection<ItemModel>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
Selection = new SelectionModel<string>();
Selection = new SelectionModel<ItemModel>();
Selection.Select(1);
_selectionMode = this.WhenAnyValue(
@ -58,8 +59,8 @@ namespace ControlCatalog.ViewModels
});
}
public ObservableCollection<string> Items { get; }
public SelectionModel<string> Selection { get; }
public ObservableCollection<ItemModel> Items { get; }
public SelectionModel<ItemModel> Selection { get; }
public IObservable<SelectionMode> SelectionMode => _selectionMode;
public bool Multiple
@ -96,6 +97,31 @@ namespace ControlCatalog.ViewModels
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }
private string GenerateItem() => $"Item {_counter++.ToString()}";
private ItemModel GenerateItem() => new ItemModel(_counter ++);
}
/// <summary>
/// An Item model for the <see cref="ListBoxPage"/>
/// </summary>
public class ItemModel
{
/// <summary>
/// Creates a new ItemModel with the given ID
/// </summary>
/// <param name="id">The ID to display</param>
public ItemModel(int id)
{
ID = id;
}
/// <summary>
/// The ID of this Item
/// </summary>
public int ID { get; }
public override string ToString()
{
return $"Item {ID}";
}
}
}

6
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@ -293,10 +293,10 @@ namespace ControlCatalog.ViewModels
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
private static IVisual GetVisualParent(IVisual? from, IVisual? to)
private static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;
var p1 = (from ?? to)!.GetVisualParent();
var p2 = (to ?? from)!.GetVisualParent();
if (p1 != null && p2 != null && p1 != p2)
{

3
samples/Directory.Build.props

@ -4,4 +4,7 @@
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\netcoreapp2.0\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
</PropertyGroup>
<Import Project="..\build\SharedVersion.props" />
<PropertyGroup>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
</PropertyGroup>
</Project>

15
samples/IntegrationTestApp/MainWindow.axaml

@ -17,11 +17,15 @@
</NativeMenuItem>
<NativeMenuItem Header="View">
<NativeMenu/>
</NativeMenuItem>
</NativeMenuItem>
</NativeMenu>
</NativeMenu.Menu>
<DockPanel>
<NativeMenuBar DockPanel.Dock="Top"/>
<StackPanel DockPanel.Dock="Bottom" Margin="4" Orientation="Horizontal">
<TextBlock Margin="0,0,4,0">WindowState:</TextBlock>
<TextBlock Name="MainWindowState" Text="{Binding WindowState}"/>
</StackPanel>
<TabControl TabStripPlacement="Left" Name="MainTabs">
<TabItem Header="Automation">
@ -129,13 +133,14 @@
<ComboBoxItem>CenterOwner</ComboBoxItem>
</ComboBox>
<ComboBox Name="ShowWindowState" SelectedIndex="0">
<ComboBoxItem>Normal</ComboBoxItem>
<ComboBoxItem>Minimized</ComboBoxItem>
<ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>FullScreen</ComboBoxItem>
<ComboBoxItem Name="ShowWindowStateNormal">Normal</ComboBoxItem>
<ComboBoxItem Name="ShowWindowStateMinimized">Minimized</ComboBoxItem>
<ComboBoxItem Name="ShowWindowStateMaximized">Maximized</ComboBoxItem>
<ComboBoxItem Name="ShowWindowStateFullScreen">FullScreen</ComboBoxItem>
</ComboBox>
<Button Name="ShowWindow">Show Window</Button>
<Button Name="SendToBack">Send to Back</Button>
<Button Name="EnterFullscreen">Enter Fullscreen</Button>
<Button Name="ExitFullscreen">Exit Fullscreen</Button>
<Button Name="RestoreAll">Restore All</Button>
</StackPanel>

3
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia;
@ -178,6 +179,8 @@ namespace IntegrationTestApp
ShowWindow();
if (source?.Name == "SendToBack")
SendToBack();
if (source?.Name == "EnterFullscreen")
WindowState = WindowState.FullScreen;
if (source?.Name == "ExitFullscreen")
WindowState = WindowState.Normal;
if (source?.Name == "RestoreAll")

8
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -27,10 +27,10 @@
<Label Grid.Column="0" Grid.Row="7">WindowState</Label>
<ComboBox Name="WindowState" Grid.Column="1" Grid.Row="7" SelectedIndex="{Binding WindowState}">
<ComboBoxItem>Normal</ComboBoxItem>
<ComboBoxItem>Minimized</ComboBoxItem>
<ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>FullScreen</ComboBoxItem>
<ComboBoxItem Name="WindowStateNormal">Normal</ComboBoxItem>
<ComboBoxItem Name="WindowStateMinimized">Minimized</ComboBoxItem>
<ComboBoxItem Name="WindowStateMaximized">Maximized</ComboBoxItem>
<ComboBoxItem Name="WindowStateFullScreen">FullScreen</ComboBoxItem>
</ComboBox>
<Label Grid.Column="0" Grid.Row="8">Order (mac)</Label>

8
samples/ReactiveUIDemo/App.axaml

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

37
samples/ReactiveUIDemo/App.axaml.cs

@ -0,0 +1,37 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using ReactiveUI;
using ReactiveUIDemo.ViewModels;
using ReactiveUIDemo.Views;
using Splat;
namespace ReactiveUIDemo
{
public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
Locator.CurrentMutable.Register(() => new FooView(), typeof(IViewFor<FooViewModel>));
Locator.CurrentMutable.Register(() => new BarView(), typeof(IViewFor<BarViewModel>));
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace();
}
}

19
samples/ReactiveUIDemo/MainWindow.axaml

@ -0,0 +1,19 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="ReactiveUIDemo.MainWindow"
xmlns:vm="using:ReactiveUIDemo.ViewModels"
xmlns:rxui="using:Avalonia.ReactiveUI"
Title="AvaloniaUI ReactiveUI Demo"
x:DataType="vm:MainWindowViewModel">
<TabControl TabStripPlacement="Left">
<TabItem Header="RoutedViewHost">
<DockPanel DataContext="{Binding RoutedViewHost}">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Spacing="8">
<Button Command="{Binding ShowFoo}">Foo</Button>
<Button Command="{Binding ShowBar}">Bar</Button>
</StackPanel>
<rxui:RoutedViewHost Router="{Binding Router}"/>
</DockPanel>
</TabItem>
</TabControl>
</Window>

22
samples/ReactiveUIDemo/MainWindow.axaml.cs

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

28
samples/ReactiveUIDemo/ReactiveUIDemo.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Views\BarView.axaml.cs">
<DependentUpon>BarView.axaml</DependentUpon>
</Compile>
<Compile Update="Views\FooView.axaml.cs">
<DependentUpon>FooView.axaml</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
</Project>

11
samples/ReactiveUIDemo/ViewModels/BarViewModel.cs

@ -0,0 +1,11 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class BarViewModel : ReactiveObject, IRoutableViewModel
{
public BarViewModel(IScreen screen) => HostScreen = screen;
public string UrlPathSegment => "Bar";
public IScreen HostScreen { get; }
}
}

11
samples/ReactiveUIDemo/ViewModels/FooViewModel.cs

@ -0,0 +1,11 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class FooViewModel : ReactiveObject, IRoutableViewModel
{
public FooViewModel(IScreen screen) => HostScreen = screen;
public string UrlPathSegment => "Foo";
public IScreen HostScreen { get; }
}
}

9
samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs

@ -0,0 +1,9 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class MainWindowViewModel : ReactiveObject
{
public RoutedViewHostPageViewModel RoutedViewHost { get; } = new();
}
}

21
samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs

@ -0,0 +1,21 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class RoutedViewHostPageViewModel : ReactiveObject, IScreen
{
public RoutedViewHostPageViewModel()
{
Foo = new(this);
Bar = new(this);
Router.Navigate.Execute(Foo);
}
public RoutingState Router { get; } = new();
public FooViewModel Foo { get; }
public BarViewModel Bar { get; }
public void ShowFoo() => Router.Navigate.Execute(Foo);
public void ShowBar() => Router.Navigate.Execute(Bar);
}
}

16
samples/ReactiveUIDemo/Views/BarView.axaml

@ -0,0 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ReactiveUIDemo.Views.BarView"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Border Background="Blue">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48">
Bar!
</TextBlock>
</Border>
</UserControl>

28
samples/ReactiveUIDemo/Views/BarView.axaml.cs

@ -0,0 +1,28 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ReactiveUI;
using ReactiveUIDemo.ViewModels;
namespace ReactiveUIDemo.Views
{
internal partial class BarView : UserControl, IViewFor<BarViewModel>
{
public BarView()
{
InitializeComponent();
}
public BarViewModel? ViewModel { get; set; }
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (BarViewModel?)value;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

16
samples/ReactiveUIDemo/Views/FooView.axaml

@ -0,0 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ReactiveUIDemo.Views.FooView"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Border Background="Red">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48">
Foo!
</TextBlock>
</Border>
</UserControl>

28
samples/ReactiveUIDemo/Views/FooView.axaml.cs

@ -0,0 +1,28 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ReactiveUI;
using ReactiveUIDemo.ViewModels;
namespace ReactiveUIDemo.Views
{
internal partial class FooView : UserControl, IViewFor<FooViewModel>
{
public FooView()
{
InitializeComponent();
}
public FooViewModel? ViewModel { get; set; }
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (FooViewModel?)value;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

4
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -95,6 +95,10 @@ namespace Avalonia.Android
_imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset);
}
else
{
_imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.ImplicitOnly);
}
}
private void SurroundingTextChanged(object sender, EventArgs e)

1
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -16,4 +16,5 @@
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
<Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" />
</Project>

25
src/Android/Avalonia.Android/AvaloniaMainActivity.cs

@ -4,9 +4,12 @@ using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android
{
public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler
@ -15,6 +18,7 @@ namespace Avalonia.Android
public Action<int, Result, Intent> ActivityResult { get; set; }
internal AvaloniaView View;
private GlobalLayoutListener _listener;
protected override void OnCreate(Bundle savedInstanceState)
{
@ -32,6 +36,10 @@ namespace Avalonia.Android
base.OnCreate(savedInstanceState);
SetContentView(View);
_listener = new GlobalLayoutListener(View);
View.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener);
}
public object Content
@ -57,6 +65,8 @@ namespace Avalonia.Android
{
View.Content = null;
View.ViewTreeObserver?.RemoveOnGlobalLayoutListener(_listener);
base.OnDestroy();
}
@ -66,5 +76,20 @@ namespace Avalonia.Android
ActivityResult?.Invoke(requestCode, resultCode, data);
}
class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
private AvaloniaView _view;
public GlobalLayoutListener(AvaloniaView view)
{
_view = view;
}
public void OnGlobalLayout()
{
_view.TopLevelImpl?.Resize(_view.TopLevelImpl.ClientSize);
}
}
}
}

24
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -26,6 +26,7 @@ using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Java.Lang;
using Math = System.Math;
using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@ -63,7 +64,21 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IInputRoot InputRoot { get; private set; }
public virtual Size ClientSize => Size.ToSize(RenderScaling);
public virtual Size ClientSize
{
get
{
AndroidRect rect = new AndroidRect();
AndroidRect intersection = new AndroidRect();
_view.GetWindowVisibleDisplayFrame(intersection);
_view.GetGlobalVisibleRect(rect);
intersection.Intersect(rect);
return new PixelSize(intersection.Right - intersection.Left, intersection.Bottom - intersection.Top).ToSize(RenderScaling);
}
}
public Size? FrameSize => null;
@ -94,7 +109,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
? new CompositingRenderer(root, AndroidPlatform.Compositor)
: AndroidPlatform.Options.UseDeferredRendering
? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService<IRenderLoop>()) { RenderOnlyOnRenderThread = true }
: new ImmediateRenderer(root);
: new ImmediateRenderer((Visual)root);
public virtual void Hide()
{
@ -149,6 +164,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
Resized?.Invoke(size, PlatformResizeReason.Unspecified);
}
internal void Resize(Size size)
{
Resized?.Invoke(size, PlatformResizeReason.Layout);
}
class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo
{
private readonly TopLevelImpl _tl;

2
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -30,7 +30,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return DispatchKeyEventInternal(e, out callBase);
}
string UnicodeTextInput(KeyEvent keyEvent)
static string UnicodeTextInput(KeyEvent keyEvent)
{
return keyEvent.Action == KeyEventActions.Multiple
&& keyEvent.RepeatCount == 0

2
src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

@ -178,7 +178,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
return false;
}
private Stream? GetVirtualFileStream(Context context, AndroidUri uri, bool isOutput)
private static Stream? GetVirtualFileStream(Context context, AndroidUri uri, bool isOutput)
{
var mimeTypes = context.ContentResolver?.GetStreamTypes(uri, FilePickerFileTypes.All.MimeTypes![0]);
if (mimeTypes?.Length >= 1)

2
src/Avalonia.Base/Animation/Animation.cs

@ -202,9 +202,7 @@ namespace Avalonia.Animation
/// <param name="setter">The animation setter.</param>
/// <param name="value">The property animator value.</param>
public static void SetAnimator(IAnimationSetter setter,
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
#endif
Type value)
{
s_animators[setter] = (value, () => (IAnimator)Activator.CreateInstance(value)!);

4
src/Avalonia.Base/Animation/AnimatorKeyFrame.cs

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation.Animators;
using Avalonia.Data;
using Avalonia.Reactive;
@ -66,7 +67,8 @@ namespace Avalonia.Animation
}
}
public T GetTypedValue<T>()
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
public T GetTypedValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
{
var typeConv = TypeDescriptor.GetConverter(typeof(T));

3
src/Avalonia.Base/Animation/Animators/Animator`1.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Animation.Utils;
using Avalonia.Collections;
@ -39,7 +40,7 @@ namespace Avalonia.Animation.Animators
VerifyConvertKeyFrames();
var subject = new DisposeAnimationInstanceSubject<T>(this, animation, control, clock, onComplete);
return match.Subscribe(subject);
return new CompositeDisposable(match.Subscribe(subject), subject);
}
protected T InterpolationHandler(double animationTime, T neutralValue)

2
src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs

@ -72,7 +72,7 @@ namespace Avalonia.Animation.Animators
return control.Bind((AvaloniaProperty<IBrush?>)Property, instance, BindingPriority.Animation);
}
private IReadOnlyList<ImmutableGradientStop> InterpolateStops(double progress, IReadOnlyList<IGradientStop> oldValue, IReadOnlyList<IGradientStop> newValue)
private static IReadOnlyList<ImmutableGradientStop> InterpolateStops(double progress, IReadOnlyList<IGradientStop> oldValue, IReadOnlyList<IGradientStop> newValue)
{
var resultCount = Math.Max(oldValue.Count, newValue.Count);
var stops = new ImmutableGradientStop[resultCount];

2
src/Avalonia.Base/Animation/CrossFade.cs

@ -10,7 +10,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Animation
{
/// <summary>
/// Defines a cross-fade animation between two <see cref="IVisual"/>s.
/// Defines a cross-fade animation between two <see cref="Visual"/>s.
/// </summary>
public class CrossFade : IPageTransition
{

2
src/Avalonia.Base/Animation/KeySpline.cs

@ -196,7 +196,7 @@ namespace Avalonia.Animation
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private bool IsValidXValue(double value)
private static bool IsValidXValue(double value)
{
return value >= 0.0 && value <= 1.0;
}

2
src/Avalonia.Base/Animation/PageSlide.cs

@ -157,7 +157,7 @@ namespace Avalonia.Animation
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
protected static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;

2
src/Avalonia.Base/AttachedProperty.cs

@ -34,7 +34,7 @@ namespace Avalonia
/// </summary>
/// <typeparam name="TOwner">The owner type.</typeparam>
/// <returns>The property.</returns>
public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : IAvaloniaObject
public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : AvaloniaObject
{
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this);
return this;

10
src/Avalonia.Base/Avalonia.Base.csproj

@ -19,6 +19,7 @@
<Import Project="..\..\build\System.Memory.props" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
<Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\DevAnalyzers.props" />
<Import Project="..\..\build\SourceGenerators.props" />
<ItemGroup>
@ -30,6 +31,8 @@
<InternalsVisibleTo Include="Avalonia.Base.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Benchmarks, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.ColorPicker, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.DataGrid, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
@ -41,6 +44,7 @@
<InternalsVisibleTo Include="Avalonia.Skia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Benchmarks, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.X11, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Win32, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Dialogs, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Diagnostics, PublicKey=$(AvaloniaPublicKey)" />
@ -48,14 +52,10 @@
</ItemGroup>
<ItemGroup Label="Build dependency">
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj"
SetTargetFramework="TargetFramework=netstandard2.0"
ReferenceOutputAssembly="false"
SkipGetTargetFrameworkProperties="true" />
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj" SetTargetFramework="TargetFramework=netstandard2.0" ReferenceOutputAssembly="false" SkipGetTargetFrameworkProperties="true" />
</ItemGroup>
<ItemGroup>
<Folder Include="Compatibility\" />
<Folder Include="Rendering\Composition\Utils" />
</ItemGroup>
</Project>

2
src/Avalonia.Base/AvaloniaObject.cs

@ -16,7 +16,7 @@ namespace Avalonia
/// <remarks>
/// This class is analogous to DependencyObject in WPF.
/// </remarks>
public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
public class AvaloniaObject : IAvaloniaObjectDebug, INotifyPropertyChanged
{
private readonly ValueStore _values;
private AvaloniaObject? _inheritanceParent;

100
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@ -36,7 +36,7 @@ namespace Avalonia
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<object?> GetObservable(this IAvaloniaObject o, AvaloniaProperty property)
public static IObservable<object?> GetObservable(this AvaloniaObject o, AvaloniaProperty property)
{
return new AvaloniaPropertyObservable<object?>(
o ?? throw new ArgumentNullException(nameof(o)),
@ -56,7 +56,7 @@ namespace Avalonia
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<T> GetObservable<T>(this IAvaloniaObject o, AvaloniaProperty<T> property)
public static IObservable<T> GetObservable<T>(this AvaloniaObject o, AvaloniaProperty<T> property)
{
return new AvaloniaPropertyObservable<T>(
o ?? throw new ArgumentNullException(nameof(o)),
@ -76,7 +76,7 @@ namespace Avalonia
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<BindingValue<object?>> GetBindingObservable(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property)
{
return new AvaloniaPropertyBindingObservable<object?>(
@ -98,7 +98,7 @@ namespace Avalonia
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<BindingValue<T>> GetBindingObservable<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property)
{
return new AvaloniaPropertyBindingObservable<T>(
@ -115,11 +115,11 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <returns>
/// An observable which when subscribed pushes the property changed event args
/// each time a <see cref="IAvaloniaObject.PropertyChanged"/> event is raised
/// each time a <see cref="AvaloniaObject.PropertyChanged"/> event is raised
/// for the specified property.
/// </returns>
public static IObservable<AvaloniaPropertyChangedEventArgs> GetPropertyChangedObservable(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property)
{
return new AvaloniaPropertyChangedObservable(
@ -140,7 +140,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<object?> GetSubject(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -163,7 +163,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<T> GetSubject<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -185,7 +185,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<BindingValue<object?>> GetBindingSubject(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -214,7 +214,7 @@ namespace Avalonia
/// property.
/// </returns>
public static ISubject<BindingValue<T>> GetBindingSubject<T>(
this IAvaloniaObject o,
this AvaloniaObject o,
AvaloniaProperty<T> property,
BindingPriority priority = BindingPriority.LocalValue)
{
@ -241,7 +241,7 @@ namespace Avalonia
/// A disposable which can be used to terminate the binding.
/// </returns>
public static IDisposable Bind<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property,
IObservable<BindingValue<T>> source,
BindingPriority priority = BindingPriority.LocalValue)
@ -250,17 +250,12 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
source = source ?? throw new ArgumentNullException(nameof(source));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
DirectPropertyBase<T> direct => ao.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
DirectPropertyBase<T> direct => target.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
/// <summary>
@ -274,22 +269,17 @@ namespace Avalonia
/// A disposable which can be used to terminate the binding.
/// </returns>
public static IDisposable Bind<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property,
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue)
{
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
DirectPropertyBase<T> direct => ao.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
DirectPropertyBase<T> direct => target.Bind(direct, source),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
};
}
/// <summary>
@ -306,7 +296,7 @@ namespace Avalonia
/// </param>
/// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
public static IDisposable Bind(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty property,
IBinding binding,
object? anchor = null)
@ -340,23 +330,17 @@ namespace Avalonia
/// <param name="target">The object.</param>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
public static T GetValue<T>(this IAvaloniaObject target, AvaloniaProperty<T> property)
public static T GetValue<T>(this AvaloniaObject target, AvaloniaProperty<T> property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.GetValue(styled),
DirectPropertyBase<T> direct => ao.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.GetValue(styled),
DirectPropertyBase<T> direct => target.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
/// <summary>
@ -372,15 +356,13 @@ namespace Avalonia
/// For direct properties returns the current value of the property.
/// </remarks>
public static object? GetBaseValue(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property.RouteGetBaseValue(ao);
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
return property.RouteGetBaseValue(target);
}
/// <summary>
@ -396,24 +378,18 @@ namespace Avalonia
/// For direct properties returns the current value of the property.
/// </remarks>
public static Optional<T> GetBaseValue<T>(
this IAvaloniaObject target,
this AvaloniaObject target,
AvaloniaProperty<T> property)
{
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
if (target is AvaloniaObject ao)
return property switch
{
return property switch
{
StyledPropertyBase<T> styled => ao.GetBaseValue(styled),
DirectPropertyBase<T> direct => ao.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
StyledPropertyBase<T> styled => target.GetBaseValue(styled),
DirectPropertyBase<T> direct => target.GetValue(direct),
_ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
};
}
/// <summary>
@ -474,7 +450,7 @@ namespace Avalonia
}
public InstancedBinding? Initiate(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor = null,
bool enableDataValidation = false)

26
src/Avalonia.Base/AvaloniaProperty.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.PropertyStore;
@ -38,7 +39,7 @@ namespace Avalonia
Type valueType,
Type ownerType,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool>? notifying = null)
Action<AvaloniaObject, bool>? notifying = null)
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -145,7 +146,7 @@ namespace Avalonia
/// will be true before the property change notifications are sent and false afterwards. This
/// callback is intended to support Control.IsDataContextChanging.
/// </remarks>
public Action<IAvaloniaObject, bool>? Notifying { get; }
public Action<AvaloniaObject, bool>? Notifying { get; }
/// <summary>
/// Gets the integer ID that represents this property.
@ -177,7 +178,7 @@ namespace Avalonia
{
return new IndexerDescriptor
{
Priority = BindingPriority.TemplatedParent,
Priority = BindingPriority.Template,
Property = property,
};
}
@ -238,9 +239,9 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null,
Action<IAvaloniaObject, bool>? notifying = null)
where TOwner : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null,
Action<AvaloniaObject, bool>? notifying = null)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -279,8 +280,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null)
where THost : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where THost : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -316,8 +317,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<IAvaloniaObject, TValue, TValue>? coerce = null)
where THost : IAvaloniaObject
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where THost : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -354,7 +355,7 @@ namespace Avalonia
TValue unsetValue = default!,
BindingMode defaultBindingMode = BindingMode.OneWay,
bool enableDataValidation = false)
where TOwner : IAvaloniaObject
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
_ = getter ?? throw new ArgumentNullException(nameof(getter));
@ -415,7 +416,7 @@ namespace Avalonia
/// <returns>
/// The property metadata.
/// </returns>
public AvaloniaPropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
public AvaloniaPropertyMetadata GetMetadata<T>() where T : AvaloniaObject
{
return GetMetadata(typeof(T));
}
@ -442,6 +443,7 @@ namespace Avalonia
/// </summary>
/// <param name="value">The value.</param>
/// <returns>True if the value is valid, otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public bool IsValidValue(object? value)
{
return TypeUtilities.TryConvertImplicit(PropertyType, value, out _);

6
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs

@ -9,7 +9,7 @@ namespace Avalonia
public abstract class AvaloniaPropertyChangedEventArgs : EventArgs
{
public AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
BindingPriority priority)
{
Sender = sender;
@ -18,7 +18,7 @@ namespace Avalonia
}
internal AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
BindingPriority priority,
bool isEffectiveValueChange)
{
@ -31,7 +31,7 @@ namespace Avalonia
/// Gets the <see cref="AvaloniaObject"/> that the property changed on.
/// </summary>
/// <value>The sender object.</value>
public IAvaloniaObject Sender { get; }
public AvaloniaObject Sender { get; }
/// <summary>
/// Gets the property that changed.

4
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs

@ -16,7 +16,7 @@ namespace Avalonia
/// <param name="newValue">The new value of the property.</param>
/// <param name="priority">The priority of the binding that produced the value.</param>
public AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
AvaloniaProperty<T> property,
Optional<T> oldValue,
BindingValue<T> newValue,
@ -26,7 +26,7 @@ namespace Avalonia
}
internal AvaloniaPropertyChangedEventArgs(
IAvaloniaObject sender,
AvaloniaObject sender,
AvaloniaProperty<T> property,
Optional<T> oldValue,
BindingValue<T> newValue,

14
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Avalonia
@ -42,6 +43,7 @@ namespace Avalonia
/// </summary>
/// <param name="type">The type.</param>
/// <returns>A collection of <see cref="AvaloniaProperty"/> definitions.</returns>
[UnconditionalSuppressMessage("Trimming", "IL2059", Justification = "If type was trimmed out, no properties were referenced")]
public IReadOnlyList<AvaloniaProperty> GetRegistered(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));
@ -189,7 +191,7 @@ namespace Avalonia
/// </summary>
/// <param name="o">The object.</param>
/// <returns>A collection of <see cref="AvaloniaProperty"/> definitions.</returns>
public IReadOnlyList<AvaloniaProperty> GetRegistered(IAvaloniaObject o)
public IReadOnlyList<AvaloniaProperty> GetRegistered(AvaloniaObject o)
{
_ = o ?? throw new ArgumentNullException(nameof(o));
@ -205,7 +207,7 @@ namespace Avalonia
/// The registered.
/// </returns>
public DirectPropertyBase<T> GetRegisteredDirect<T>(
IAvaloniaObject o,
AvaloniaObject o,
DirectPropertyBase<T> property)
{
return FindRegisteredDirect(o, property) ??
@ -260,7 +262,7 @@ namespace Avalonia
/// <exception cref="InvalidOperationException">
/// The property name contains a '.'.
/// </exception>
public AvaloniaProperty? FindRegistered(IAvaloniaObject o, string name)
public AvaloniaProperty? FindRegistered(AvaloniaObject o, string name)
{
_ = o ?? throw new ArgumentNullException(nameof(o));
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -277,7 +279,7 @@ namespace Avalonia
/// The registered property or null if no matching property found.
/// </returns>
public DirectPropertyBase<T>? FindRegisteredDirect<T>(
IAvaloniaObject o,
AvaloniaObject o,
DirectPropertyBase<T> property)
{
if (property.Owner == o.GetType())
@ -362,7 +364,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <remarks>
/// You won't usually want to call this method directly, instead use the
/// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue}, Action{IAvaloniaObject, bool})"/>
/// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue}, Action{AvaloniaObject, bool})"/>
/// method.
/// </remarks>
public void Register(Type type, AvaloniaProperty property)
@ -413,7 +415,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <remarks>
/// You won't usually want to call this method directly, instead use the
/// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue})"/>
/// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue})"/>
/// method.
/// </remarks>
public void RegisterAttached(Type type, AvaloniaProperty property)

4
src/Avalonia.Base/AvaloniaProperty`1.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Subjects;
using Avalonia.Data;
using Avalonia.Utilities;
@ -24,7 +25,7 @@ namespace Avalonia
string name,
Type ownerType,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool>? notifying = null)
Action<AvaloniaObject, bool>? notifying = null)
: base(name, typeof(TValue), ownerType, metadata, notifying)
{
_changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();
@ -67,6 +68,7 @@ namespace Avalonia
protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
protected BindingValue<object?> TryConvert(object? value)
{
if (value == UnsetValue)

4
src/Avalonia.Base/ClassBindingManager.cs

@ -9,7 +9,7 @@ namespace Avalonia
private static readonly Dictionary<string, AvaloniaProperty> s_RegisteredProperties =
new Dictionary<string, AvaloniaProperty>();
public static IDisposable Bind(IStyledElement target, string className, IBinding source, object anchor)
public static IDisposable Bind(StyledElement target, string className, IBinding source, object anchor)
{
if (!s_RegisteredProperties.TryGetValue(className, out var prop))
s_RegisteredProperties[className] = prop = RegisterClassProxyProperty(className);
@ -21,7 +21,7 @@ namespace Avalonia
var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);
prop.Changed.Subscribe(args =>
{
var classes = ((IStyledElement)args.Sender).Classes;
var classes = ((StyledElement)args.Sender).Classes;
classes.Set(className, args.NewValue.GetValueOrDefault());
});

4
src/Avalonia.Base/Collections/AvaloniaListConverter.cs

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Avalonia.Utilities;
@ -8,7 +9,8 @@ namespace Avalonia.Collections
/// <summary>
/// Creates an <see cref="AvaloniaList{T}"/> from a string representation.
/// </summary>
public class AvaloniaListConverter<T> : TypeConverter
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
public class AvaloniaListConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{

121
src/Avalonia.Base/Compatibility/TrimmingAttributes.cs

@ -0,0 +1,121 @@
#pragma warning disable MA0048 // File name must match type name
// https://github.com/dotnet/runtime/tree/main/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Diagnostics.CodeAnalysis
{
#nullable enable
#if !NET6_0_OR_GREATER
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
Inherited = false)]
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
{
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
{
MemberTypes = memberTypes;
}
public DynamicallyAccessedMemberTypes MemberTypes { get; }
}
[Flags]
internal enum DynamicallyAccessedMemberTypes
{
None = 0,
PublicParameterlessConstructor = 0x0001,
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
NonPublicConstructors = 0x0004,
PublicMethods = 0x0008,
NonPublicMethods = 0x0010,
PublicFields = 0x0020,
NonPublicFields = 0x0040,
PublicNestedTypes = 0x0080,
NonPublicNestedTypes = 0x0100,
PublicProperties = 0x0200,
NonPublicProperties = 0x0400,
PublicEvents = 0x0800,
NonPublicEvents = 0x1000,
Interfaces = 0x2000,
All = ~None
}
[AttributeUsage(
AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method,
AllowMultiple = true, Inherited = false)]
internal sealed class DynamicDependencyAttribute : Attribute
{
public DynamicDependencyAttribute(string memberSignature)
{
MemberSignature = memberSignature;
}
public DynamicDependencyAttribute(string memberSignature, Type type)
{
MemberSignature = memberSignature;
Type = type;
}
public DynamicDependencyAttribute(string memberSignature, string typeName, string assemblyName)
{
MemberSignature = memberSignature;
TypeName = typeName;
AssemblyName = assemblyName;
}
public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, Type type)
{
MemberTypes = memberTypes;
Type = type;
}
public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName)
{
MemberTypes = memberTypes;
TypeName = typeName;
AssemblyName = assemblyName;
}
public string? MemberSignature { get; }
public DynamicallyAccessedMemberTypes MemberTypes { get; }
public Type? Type { get; }
public string? TypeName { get; }
public string? AssemblyName { get; }
public string? Condition { get; set; }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
internal sealed class RequiresUnreferencedCodeAttribute : Attribute
{
public RequiresUnreferencedCodeAttribute(string message)
{
Message = message;
}
public string Message { get; }
public string? Url { get; set; }
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class UnconditionalSuppressMessageAttribute : Attribute
{
public UnconditionalSuppressMessageAttribute(string category, string checkId)
{
Category = category;
CheckId = checkId;
}
public string Category { get; }
public string CheckId { get; }
public string? Scope { get; set; }
public string? Target { get; set; }
public string? MessageId { get; set; }
public string? Justification { get; set; }
}
#endif
}

6
src/Avalonia.Base/Controls/Classes.cs

@ -6,7 +6,7 @@ using Avalonia.Utilities;
namespace Avalonia.Controls
{
/// <summary>
/// Holds a collection of style classes for an <see cref="IStyledElement"/>.
/// Holds a collection of style classes for an <see cref="StyledElement"/>.
/// </summary>
/// <remarks>
/// Similar to CSS, each control may have any number of styling classes applied.
@ -37,7 +37,7 @@ namespace Avalonia.Controls
/// <param name="items">The initial items.</param>
public Classes(params string[] items)
: base(items)
{
{
}
/// <summary>
@ -320,7 +320,7 @@ namespace Avalonia.Controls
listener.Changed();
}
private void ThrowIfPseudoclass(string name, string operation)
private static void ThrowIfPseudoclass(string name, string operation)
{
if (name.StartsWith(":"))
{

2
src/Avalonia.Base/Controls/ISetInheritanceParent.cs

@ -17,6 +17,6 @@ namespace Avalonia.Controls
/// Sets the control's inheritance parent.
/// </summary>
/// <param name="parent">The parent.</param>
void SetParent(IAvaloniaObject? parent);
void SetParent(AvaloniaObject? parent);
}
}

3
src/Avalonia.Base/Controls/ResourceNodeExtensions.cs

@ -2,6 +2,7 @@
using Avalonia.Data.Converters;
using Avalonia.LogicalTree;
using Avalonia.Reactive;
using Avalonia.Styling;
#nullable enable
@ -49,7 +50,7 @@ namespace Avalonia.Controls
return true;
}
current = (current as IStyledElement)?.StylingParent as IResourceNode;
current = (current as IStyleHost)?.StylingParent as IResourceNode;
}
value = null;

2
src/Avalonia.Base/CornerRadius.cs

@ -100,7 +100,7 @@ namespace Avalonia
public override string ToString()
{
return $"{TopLeft},{TopRight},{BottomRight},{BottomLeft}";
return FormattableString.Invariant($"{TopLeft},{TopRight},{BottomRight},{BottomLeft}");
}
public static CornerRadius Parse(string s)

4
src/Avalonia.Base/Data/BindingOperations.cs

@ -9,7 +9,7 @@ namespace Avalonia.Data
public static readonly object DoNothing = new DoNothingType();
/// <summary>
/// Applies an <see cref="InstancedBinding"/> a property on an <see cref="IAvaloniaObject"/>.
/// Applies an <see cref="InstancedBinding"/> a property on an <see cref="AvaloniaObject"/>.
/// </summary>
/// <param name="target">The target object.</param>
/// <param name="property">The property to bind.</param>
@ -22,7 +22,7 @@ namespace Avalonia.Data
/// </param>
/// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
public static IDisposable Apply(
IAvaloniaObject target,
AvaloniaObject target,
AvaloniaProperty property,
InstancedBinding binding,
object? anchor)

22
src/Avalonia.Base/Data/BindingPriority.cs

@ -1,7 +1,9 @@
using System;
namespace Avalonia.Data
{
/// <summary>
/// The priority of a binding.
/// The priority of a value or binding.
/// </summary>
public enum BindingPriority
{
@ -16,23 +18,22 @@ namespace Avalonia.Data
LocalValue = 0,
/// <summary>
/// A triggered style binding.
/// A triggered style value.
/// </summary>
/// <remarks>
/// A style trigger is a selector such as .class which overrides a
/// <see cref="TemplatedParent"/> binding. In this way, a basic control can have
/// for example a Background from the templated parent which changes when the
/// control has the :pointerover class.
/// <see cref="Template"/> value. In this way, a control can have, e.g. a Background from
/// the template which changes when the control has the :pointerover class.
/// </remarks>
StyleTrigger,
/// <summary>
/// A binding to a property on the templated parent.
/// A value from the control's template.
/// </summary>
TemplatedParent,
Template,
/// <summary>
/// A style binding.
/// A style value.
/// </summary>
Style,
@ -42,8 +43,11 @@ namespace Avalonia.Data
Inherited,
/// <summary>
/// The binding is uninitialized.
/// The value is uninitialized.
/// </summary>
Unset = int.MaxValue,
[Obsolete("Use Template priority")]
TemplatedParent = Template,
}
}

3
src/Avalonia.Base/Data/BindingValue.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Utilities;
namespace Avalonia.Data
@ -236,6 +237,7 @@ namespace Avalonia.Data
/// </summary>
/// <param name="value">The untyped value.</param>
/// <returns>The typed binding value.</returns>
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public static BindingValue<T> FromUntyped(object? value)
{
return FromUntyped(value, typeof(T));
@ -249,6 +251,7 @@ namespace Avalonia.Data
/// <param name="value">The untyped value.</param>
/// <param name="targetType">The runtime target type.</param>
/// <returns>The typed binding value.</returns>
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public static BindingValue<T> FromUntyped(object? value, Type targetType)
{
if (value == AvaloniaProperty.UnsetValue)

2
src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Windows.Input;
using Avalonia.Utilities;
@ -9,6 +10,7 @@ namespace Avalonia.Data.Converters
/// Provides a default set of value conversions for bindings that do not specify a value
/// converter.
/// </summary>
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
public class DefaultValueConverter : IValueConverter
{
/// <summary>

2
src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
@ -9,6 +10,7 @@ using Avalonia.Utilities;
namespace Avalonia.Data.Converters
{
[RequiresUnreferencedCode(TrimmingMessages.ReflectionBindingRequiresUnreferencedCodeMessage)]
class MethodToCommandConverter : ICommand
{
readonly static Func<object?, bool> AlwaysEnabled = (_) => true;

4
src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs

@ -24,7 +24,7 @@ namespace Avalonia.Data.Core
{
try
{
if (Target.TryGetTarget(out var target) && target is IAvaloniaObject obj)
if (Target.TryGetTarget(out var target) && target is AvaloniaObject obj)
{
obj.SetValue(_property, value, priority);
return true;
@ -39,7 +39,7 @@ namespace Avalonia.Data.Core
protected override void StartListeningCore(WeakReference<object?> reference)
{
if (reference.TryGetTarget(out var target) && target is IAvaloniaObject obj)
if (reference.TryGetTarget(out var target) && target is AvaloniaObject obj)
{
_subscription = new AvaloniaPropertyObservable<object?>(obj, _property).Subscribe(ValueChanged);
}

2
src/Avalonia.Base/Data/Core/BindingExpression.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reactive.Linq;
using System.Reactive.Subjects;
@ -13,6 +14,7 @@ namespace Avalonia.Data.Core
/// Binds to an expression on an object using a type value converter to convert the values
/// that are sent and received.
/// </summary>
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
public class BindingExpression : LightweightObservableBase<object?>, ISubject<object?>, IDescription
{
private readonly ExpressionObserver _inner;

2
src/Avalonia.Base/Data/Core/ExpressionNode.cs

@ -159,7 +159,7 @@ namespace Avalonia.Data.Core
_listening = false;
}
private BindingNotification TargetNullNotification()
private static BindingNotification TargetNullNotification()
{
return new BindingNotification(
new MarkupBindingChainException("Null value"),

5
src/Avalonia.Base/Data/Core/ExpressionObserver.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Reactive;
using System.Reactive.Linq;
@ -126,6 +127,7 @@ namespace Avalonia.Data.Core
/// <param name="description">
/// A description of the expression. If null, <paramref name="expression"/>'s string representation will be used.
/// </param>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ExpressionSafeSupressWarningMessage)]
public static ExpressionObserver Create<T, U>(
T? root,
Expression<Func<T, U>> expression,
@ -144,6 +146,7 @@ namespace Avalonia.Data.Core
/// <param name="description">
/// A description of the expression. If null, <paramref name="expression"/>'s string representation will be used.
/// </param>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ExpressionSafeSupressWarningMessage)]
public static ExpressionObserver Create<T, U>(
IObservable<T> rootObservable,
Expression<Func<T, U>> expression,
@ -168,6 +171,7 @@ namespace Avalonia.Data.Core
/// <param name="description">
/// A description of the expression. If null, <paramref name="expression"/>'s string representation will be used.
/// </param>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ExpressionSafeSupressWarningMessage)]
public static ExpressionObserver Create<T, U>(
Func<T> rootGetter,
Expression<Func<T, U>> expression,
@ -283,6 +287,7 @@ namespace Avalonia.Data.Core
}
}
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
private static ExpressionNode Parse(LambdaExpression expression, bool enableDataValidation)
{
return ExpressionTreeParser.Parse(expression, enableDataValidation);

4
src/Avalonia.Base/Data/Core/Parsers/ExpressionTreeParser.cs

@ -1,10 +1,12 @@
using System.Linq;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
namespace Avalonia.Data.Core.Parsers
{
static class ExpressionTreeParser
{
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
public static ExpressionNode Parse(Expression expr, bool enableDataValidation)
{
var visitor = new ExpressionVisitorNodeBuilder(enableDataValidation);

6
src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs

@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Avalonia.Data.Core.Parsers
{
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
class ExpressionVisitorNodeBuilder : ExpressionVisitor
{
private const string MultiDimensionalArrayGetterMethodName = "Get";
@ -81,7 +83,7 @@ namespace Avalonia.Data.Core.Parsers
return node;
}
private T GetArgumentExpressionValue<T>(Expression expr)
private static T GetArgumentExpressionValue<T>(Expression expr)
{
try
{
@ -193,7 +195,7 @@ namespace Avalonia.Data.Core.Parsers
throw new ExpressionParseException(0, $"Invalid method call in binding expression: '{node.Method.DeclaringType!.AssemblyQualifiedName}.{node.Method.Name}'.");
}
private PropertyInfo? TryGetPropertyFromMethod(MethodInfo method)
private static PropertyInfo? TryGetPropertyFromMethod(MethodInfo method)
{
var type = method.DeclaringType;
return type?.GetRuntimeProperties().FirstOrDefault(prop => prop.GetMethod == method);

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

Loading…
Cancel
Save