Browse Source

Merge branch 'AvaloniaUI:master' into fix-datagrid-grouping-arrows

pull/9634/head
kivarsen 4 years ago
committed by GitHub
parent
commit
0b76ab251e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      .editorconfig
  2. 6
      Avalonia.sln
  3. 2
      build/SharedVersion.props
  4. 16
      build/TrimmingEnable.props
  5. 1
      nukebuild/Build.cs
  6. 2
      nukebuild/_build.csproj
  7. 25
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  8. 2
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  9. 2
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  10. 2
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  11. 3
      samples/ControlCatalog/Pages/ScreenPage.cs
  12. 2
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  13. 1
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  14. 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  15. 2
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
  16. 2
      src/Avalonia.Base/Animation/Animation.cs
  17. 4
      src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
  18. 2
      src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
  19. 2
      src/Avalonia.Base/Animation/KeySpline.cs
  20. 10
      src/Avalonia.Base/Avalonia.Base.csproj
  21. 2
      src/Avalonia.Base/AvaloniaProperty.cs
  22. 2
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  23. 2
      src/Avalonia.Base/AvaloniaProperty`1.cs
  24. 4
      src/Avalonia.Base/Collections/AvaloniaListConverter.cs
  25. 121
      src/Avalonia.Base/Compatibility/TrimmingAttributes.cs
  26. 4
      src/Avalonia.Base/Controls/Classes.cs
  27. 3
      src/Avalonia.Base/Data/BindingValue.cs
  28. 2
      src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
  29. 2
      src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs
  30. 2
      src/Avalonia.Base/Data/Core/BindingExpression.cs
  31. 2
      src/Avalonia.Base/Data/Core/ExpressionNode.cs
  32. 5
      src/Avalonia.Base/Data/Core/ExpressionObserver.cs
  33. 4
      src/Avalonia.Base/Data/Core/Parsers/ExpressionTreeParser.cs
  34. 6
      src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs
  35. 3
      src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
  36. 6
      src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
  37. 3
      src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
  38. 3
      src/Avalonia.Base/Data/Core/Plugins/IDataValidationPlugin.cs
  39. 3
      src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessorPlugin.cs
  40. 3
      src/Avalonia.Base/Data/Core/Plugins/IStreamPlugin.cs
  41. 5
      src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
  42. 10
      src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
  43. 9
      src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
  44. 5
      src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
  45. 9
      src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
  46. 3
      src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
  47. 2
      src/Avalonia.Base/Data/Core/StreamNode.cs
  48. 30
      src/Avalonia.Base/Diagnostics/TrimmingMessages.cs
  49. 18
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  50. 4
      src/Avalonia.Base/Input/DragDropDevice.cs
  51. 5
      src/Avalonia.Base/Input/KeyGesture.cs
  52. 2
      src/Avalonia.Base/Input/KeyboardDevice.cs
  53. 9
      src/Avalonia.Base/Input/MouseDevice.cs
  54. 2
      src/Avalonia.Base/Input/PenDevice.cs
  55. 6
      src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs
  56. 4
      src/Avalonia.Base/Input/Pointer.cs
  57. 2
      src/Avalonia.Base/Input/TouchDevice.cs
  58. 2
      src/Avalonia.Base/Layout/AttachedLayout.cs
  59. 4
      src/Avalonia.Base/Layout/StackLayout.cs
  60. 2
      src/Avalonia.Base/Layout/UniformGridLayout.cs
  61. 12
      src/Avalonia.Base/Media/PathMarkupParser.cs
  62. 4
      src/Avalonia.Base/Platform/AssetLoader.cs
  63. 2
      src/Avalonia.Base/PropertyStore/DirectUntypedBindingObserver.cs
  64. 2
      src/Avalonia.Base/PropertyStore/UntypedValueUtils.cs
  65. 12
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
  66. 2
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  67. 4
      src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
  68. 2
      src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
  69. 2
      src/Avalonia.Base/Rendering/DeferredRenderer.cs
  70. 2
      src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs
  71. 2
      src/Avalonia.Base/StyledPropertyBase.cs
  72. 5
      src/Avalonia.Base/Styling/PropertyEqualsSelector.cs
  73. 2
      src/Avalonia.Base/Styling/Setter.cs
  74. 3
      src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
  75. 13
      src/Avalonia.Base/Utilities/TypeUtilities.cs
  76. 8
      src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
  77. 3
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  78. 1
      src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs
  79. 119
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  80. 1
      src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj
  81. 2
      src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
  82. 2
      src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs
  83. 2
      src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs
  84. 50
      src/Avalonia.Controls/AppBuilderBase.cs
  85. 2
      src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs
  86. 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  87. 2
      src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
  88. 3
      src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
  89. 8
      src/Avalonia.Controls/Grid.cs
  90. 2
      src/Avalonia.Controls/GridSplitter.cs
  91. 11
      src/Avalonia.Controls/MenuItemAccessKeyHandler.cs
  92. 12
      src/Avalonia.Controls/NativeMenuBar.cs
  93. 6
      src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
  94. 4
      src/Avalonia.Controls/Platform/InProcessDragSource.cs
  95. 6
      src/Avalonia.Controls/Primitives/Popup.cs
  96. 5
      src/Avalonia.Controls/ProgressBar.cs
  97. 2
      src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs
  98. 7
      src/Avalonia.Controls/SplitView.cs
  99. 2
      src/Avalonia.Controls/TextBox.cs
  100. 2
      src/Avalonia.Controls/TopLevel.cs

10
.editorconfig

@ -64,7 +64,7 @@ dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_style.static_prefix_style.required_prefix = s_ 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 # internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
@ -137,12 +137,20 @@ space_within_single_line_array_initializer_braces = true
#Net Analyzer #Net Analyzer
dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed. 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 # CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning dotnet_diagnostic.CA1802.severity = warning
# CA1820: Test for empty strings using string length # CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers # CA1821: Remove empty finalizers
dotnet_diagnostic.CA1821.severity = warning 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 # CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning dotnet_diagnostic.CA1825.severity = warning
# CA1826: Use property instead of Linq Enumerable method # CA1826: Use property instead of Linq Enumerable method

6
Avalonia.sln

@ -40,6 +40,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
.editorconfig = .editorconfig .editorconfig = .editorconfig
src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.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\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs
src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs = src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs = src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs
EndProjectSection EndProjectSection
@ -119,6 +120,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\SourceLink.props = build\SourceLink.props build\SourceLink.props = build\SourceLink.props
build\System.Drawing.Common.props = build\System.Drawing.Common.props build\System.Drawing.Common.props = build\System.Drawing.Common.props
build\System.Memory.props = build\System.Memory.props build\System.Memory.props = build\System.Memory.props
build\TrimmingEnable.props = build\TrimmingEnable.props
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\XUnit.props = build\XUnit.props build\XUnit.props = build\XUnit.props
EndProjectSection EndProjectSection
@ -222,9 +224,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.iOS", "sample
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}"
EndProject 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 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
EndProject EndProject

2
build/SharedVersion.props

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

1
nukebuild/Build.cs

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

2
nukebuild/_build.csproj

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

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

@ -14,7 +14,26 @@ namespace ControlCatalog.Pages
{ {
public class AutoCompleteBoxPage : UserControl 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[] return new StateData[]
{ {
@ -72,7 +91,7 @@ namespace ControlCatalog.Pages
} }
public StateData[] States { get; private set; } public StateData[] States { get; private set; }
private LinkedList<string>[] BuildAllSentences() private static LinkedList<string>[] BuildAllSentences()
{ {
return new string[] return new string[]
{ {
@ -124,7 +143,7 @@ namespace ControlCatalog.Pages
.OfType<AutoCompleteBox>(); .OfType<AutoCompleteBox>();
} }
private bool StringContains(string str, string? query) private static bool StringContains(string str, string? query)
{ {
if (query == null) return false; if (query == null) return false;
return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; 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(); this.Get<ItemsControl>("Items").Items = CreateColorItems();
} }
private List<CompositionPageColorItem> CreateColorItems() private static List<CompositionPageColorItem> CreateColorItems()
{ {
var list = new List<CompositionPageColorItem>(); var list = new List<CompositionPageColorItem>();

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 bitmapWidth = 640;
var bitmapHeight = 426; var bitmapHeight = 426;

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; int err;
while ((err = gl.GetError()) != GL_NO_ERROR) 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)); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}"); formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText = formattedText =
@ -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)); 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, return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
Typeface.Default, 12, Brushes.Green); Typeface.Default, 12, Brushes.Green);

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

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

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

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

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); return DispatchKeyEventInternal(e, out callBase);
} }
string UnicodeTextInput(KeyEvent keyEvent) static string UnicodeTextInput(KeyEvent keyEvent)
{ {
return keyEvent.Action == KeyEventActions.Multiple return keyEvent.Action == KeyEventActions.Multiple
&& keyEvent.RepeatCount == 0 && keyEvent.RepeatCount == 0

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

@ -178,7 +178,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
return false; 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]); var mimeTypes = context.ContentResolver?.GetStreamTypes(uri, FilePickerFileTypes.All.MimeTypes![0]);
if (mimeTypes?.Length >= 1) 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="setter">The animation setter.</param>
/// <param name="value">The property animator value.</param> /// <param name="value">The property animator value.</param>
public static void SetAnimator(IAnimationSetter setter, public static void SetAnimator(IAnimationSetter setter,
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
#endif
Type value) Type value)
{ {
s_animators[setter] = (value, () => (IAnimator)Activator.CreateInstance(value)!); s_animators[setter] = (value, () => (IAnimator)Activator.CreateInstance(value)!);

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

@ -1,5 +1,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation.Animators; using Avalonia.Animation.Animators;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Reactive; 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)); var typeConv = TypeDescriptor.GetConverter(typeof(T));

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); 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 resultCount = Math.Max(oldValue.Count, newValue.Count);
var stops = new ImmutableGradientStop[resultCount]; var stops = new ImmutableGradientStop[resultCount];

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

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

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

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

2
src/Avalonia.Base/AvaloniaProperty.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Data.Core; using Avalonia.Data.Core;
using Avalonia.PropertyStore; using Avalonia.PropertyStore;
@ -442,6 +443,7 @@ namespace Avalonia
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>True if the value is valid, otherwise false.</returns> /// <returns>True if the value is valid, otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public bool IsValidValue(object? value) public bool IsValidValue(object? value)
{ {
return TypeUtilities.TryConvertImplicit(PropertyType, value, out _); return TypeUtilities.TryConvertImplicit(PropertyType, value, out _);

2
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Avalonia namespace Avalonia
@ -42,6 +43,7 @@ namespace Avalonia
/// </summary> /// </summary>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns>A collection of <see cref="AvaloniaProperty"/> definitions.</returns> /// <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) public IReadOnlyList<AvaloniaProperty> GetRegistered(Type type)
{ {
_ = type ?? throw new ArgumentNullException(nameof(type)); _ = type ?? throw new ArgumentNullException(nameof(type));

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

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -67,6 +68,7 @@ namespace Avalonia
protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed; protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
protected BindingValue<object?> TryConvert(object? value) protected BindingValue<object?> TryConvert(object? value)
{ {
if (value == UnsetValue) if (value == UnsetValue)

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

@ -1,5 +1,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -8,7 +9,8 @@ namespace Avalonia.Collections
/// <summary> /// <summary>
/// Creates an <see cref="AvaloniaList{T}"/> from a string representation. /// Creates an <see cref="AvaloniaList{T}"/> from a string representation.
/// </summary> /// </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) 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
}

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

@ -37,7 +37,7 @@ namespace Avalonia.Controls
/// <param name="items">The initial items.</param> /// <param name="items">The initial items.</param>
public Classes(params string[] items) public Classes(params string[] items)
: base(items) : base(items)
{ {
} }
/// <summary> /// <summary>
@ -320,7 +320,7 @@ namespace Avalonia.Controls
listener.Changed(); listener.Changed();
} }
private void ThrowIfPseudoclass(string name, string operation) private static void ThrowIfPseudoclass(string name, string operation)
{ {
if (name.StartsWith(":")) if (name.StartsWith(":"))
{ {

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
namespace Avalonia.Data.Core.Parsers namespace Avalonia.Data.Core.Parsers
{ {
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
class ExpressionVisitorNodeBuilder : ExpressionVisitor class ExpressionVisitorNodeBuilder : ExpressionVisitor
{ {
private const string MultiDimensionalArrayGetterMethodName = "Get"; private const string MultiDimensionalArrayGetterMethodName = "Get";
@ -81,7 +83,7 @@ namespace Avalonia.Data.Core.Parsers
return node; return node;
} }
private T GetArgumentExpressionValue<T>(Expression expr) private static T GetArgumentExpressionValue<T>(Expression expr)
{ {
try 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}'."); 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; var type = method.DeclaringType;
return type?.GetRuntimeProperties().FirstOrDefault(prop => prop.GetMethod == method); return type?.GetRuntimeProperties().FirstOrDefault(prop => prop.GetMethod == method);

3
src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -10,6 +11,7 @@ namespace Avalonia.Data.Core.Plugins
public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin
{ {
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public bool Match(object obj, string propertyName) public bool Match(object obj, string propertyName)
{ {
if (obj is AvaloniaObject o) if (obj is AvaloniaObject o)
@ -29,6 +31,7 @@ namespace Avalonia.Data.Core.Plugins
/// An <see cref="IPropertyAccessor"/> interface through which future interactions with the /// An <see cref="IPropertyAccessor"/> interface through which future interactions with the
/// property will be made. /// property will be made.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public IPropertyAccessor? Start(WeakReference<object?> reference, string propertyName) public IPropertyAccessor? Start(WeakReference<object?> reference, string propertyName)
{ {
_ = reference ?? throw new ArgumentNullException(nameof(reference)); _ = reference ?? throw new ArgumentNullException(nameof(reference));

6
src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -12,6 +13,7 @@ namespace Avalonia.Data.Core.Plugins
public class DataAnnotationsValidationPlugin : IDataValidationPlugin public class DataAnnotationsValidationPlugin : IDataValidationPlugin
{ {
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
public bool Match(WeakReference<object?> reference, string memberName) public bool Match(WeakReference<object?> reference, string memberName)
{ {
reference.TryGetTarget(out var target); reference.TryGetTarget(out var target);
@ -24,11 +26,13 @@ namespace Avalonia.Data.Core.Plugins
} }
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
public IPropertyAccessor Start(WeakReference<object?> reference, string name, IPropertyAccessor inner) public IPropertyAccessor Start(WeakReference<object?> reference, string name, IPropertyAccessor inner)
{ {
return new Accessor(reference, name, inner); return new Accessor(reference, name, inner);
} }
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
private sealed class Accessor : DataValidationBase private sealed class Accessor : DataValidationBase
{ {
private readonly ValidationContext? _context; private readonly ValidationContext? _context;
@ -63,7 +67,7 @@ namespace Avalonia.Data.Core.Plugins
} }
} }
private Exception CreateException(IList<ValidationResult> errors) private static Exception CreateException(IList<ValidationResult> errors)
{ {
if (errors.Count == 1) if (errors.Count == 1)
{ {

3
src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
namespace Avalonia.Data.Core.Plugins namespace Avalonia.Data.Core.Plugins
@ -9,9 +10,11 @@ namespace Avalonia.Data.Core.Plugins
public class ExceptionValidationPlugin : IDataValidationPlugin public class ExceptionValidationPlugin : IDataValidationPlugin
{ {
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
public bool Match(WeakReference<object?> reference, string memberName) => true; public bool Match(WeakReference<object?> reference, string memberName) => true;
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
public IPropertyAccessor Start(WeakReference<object?> reference, string name, IPropertyAccessor inner) public IPropertyAccessor Start(WeakReference<object?> reference, string name, IPropertyAccessor inner)
{ {
return new Validator(reference, name, inner); return new Validator(reference, name, inner);

3
src/Avalonia.Base/Data/Core/Plugins/IDataValidationPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Avalonia.Data.Core.Plugins namespace Avalonia.Data.Core.Plugins
{ {
@ -13,6 +14,7 @@ namespace Avalonia.Data.Core.Plugins
/// <param name="reference">A weak reference to the object.</param> /// <param name="reference">A weak reference to the object.</param>
/// <param name="memberName">The name of the member to validate.</param> /// <param name="memberName">The name of the member to validate.</param>
/// <returns>True if the plugin can handle the object; otherwise false.</returns> /// <returns>True if the plugin can handle the object; otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
bool Match(WeakReference<object?> reference, string memberName); bool Match(WeakReference<object?> reference, string memberName);
/// <summary> /// <summary>
@ -25,6 +27,7 @@ namespace Avalonia.Data.Core.Plugins
/// An <see cref="IPropertyAccessor"/> interface through which future interactions with the /// An <see cref="IPropertyAccessor"/> interface through which future interactions with the
/// property will be made. /// property will be made.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
IPropertyAccessor Start(WeakReference<object?> reference, IPropertyAccessor Start(WeakReference<object?> reference,
string propertyName, string propertyName,
IPropertyAccessor inner); IPropertyAccessor inner);

3
src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessorPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Avalonia.Data.Core.Plugins namespace Avalonia.Data.Core.Plugins
{ {
@ -14,6 +15,7 @@ namespace Avalonia.Data.Core.Plugins
/// <param name="obj">The object.</param> /// <param name="obj">The object.</param>
/// <param name="propertyName">The property name.</param> /// <param name="propertyName">The property name.</param>
/// <returns>True if the plugin can handle the property on the object; otherwise false.</returns> /// <returns>True if the plugin can handle the property on the object; otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
bool Match(object obj, string propertyName); bool Match(object obj, string propertyName);
/// <summary> /// <summary>
@ -25,6 +27,7 @@ namespace Avalonia.Data.Core.Plugins
/// An <see cref="IPropertyAccessor"/> interface through which future interactions with the /// An <see cref="IPropertyAccessor"/> interface through which future interactions with the
/// property will be made. /// property will be made.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
IPropertyAccessor? Start(WeakReference<object?> reference, IPropertyAccessor? Start(WeakReference<object?> reference,
string propertyName); string propertyName);
} }

3
src/Avalonia.Base/Data/Core/Plugins/IStreamPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Avalonia.Data.Core.Plugins namespace Avalonia.Data.Core.Plugins
{ {
@ -12,6 +13,7 @@ namespace Avalonia.Data.Core.Plugins
/// </summary> /// </summary>
/// <param name="reference">A weak reference to the value.</param> /// <param name="reference">A weak reference to the value.</param>
/// <returns>True if the plugin can handle the value; otherwise false.</returns> /// <returns>True if the plugin can handle the value; otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
bool Match(WeakReference<object?> reference); bool Match(WeakReference<object?> reference);
/// <summary> /// <summary>
@ -21,6 +23,7 @@ namespace Avalonia.Data.Core.Plugins
/// <returns> /// <returns>
/// An observable that produces the output for the value. /// An observable that produces the output for the value.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
IObservable<object?> Start(WeakReference<object?> reference); IObservable<object?> Start(WeakReference<object?> reference);
} }
} }

5
src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -18,6 +19,7 @@ namespace Avalonia.Data.Core.Plugins
); );
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
public bool Match(WeakReference<object?> reference, string memberName) public bool Match(WeakReference<object?> reference, string memberName)
{ {
reference.TryGetTarget(out var target); reference.TryGetTarget(out var target);
@ -26,6 +28,7 @@ namespace Avalonia.Data.Core.Plugins
} }
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
public IPropertyAccessor Start(WeakReference<object?> reference, string name, IPropertyAccessor accessor) public IPropertyAccessor Start(WeakReference<object?> reference, string name, IPropertyAccessor accessor)
{ {
return new Validator(reference, name, accessor); return new Validator(reference, name, accessor);
@ -108,7 +111,7 @@ namespace Avalonia.Data.Core.Plugins
return target; return target;
} }
private Exception GenerateException(IList<object> errors) private static Exception GenerateException(IList<object> errors)
{ {
if (errors.Count == 1) if (errors.Count == 1)
{ {

10
src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -17,6 +17,7 @@ namespace Avalonia.Data.Core.Plugins
new Dictionary<(Type, string), PropertyInfo?>(); new Dictionary<(Type, string), PropertyInfo?>();
/// <inheritdoc/> /// <inheritdoc/>
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public bool Match(object obj, string propertyName) => GetFirstPropertyWithName(obj, propertyName) != null; public bool Match(object obj, string propertyName) => GetFirstPropertyWithName(obj, propertyName) != null;
/// <summary> /// <summary>
@ -28,6 +29,7 @@ namespace Avalonia.Data.Core.Plugins
/// An <see cref="IPropertyAccessor"/> interface through which future interactions with the /// An <see cref="IPropertyAccessor"/> interface through which future interactions with the
/// property will be made. /// property will be made.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public IPropertyAccessor? Start(WeakReference<object?> reference, string propertyName) public IPropertyAccessor? Start(WeakReference<object?> reference, string propertyName)
{ {
_ = reference ?? throw new ArgumentNullException(nameof(reference)); _ = reference ?? throw new ArgumentNullException(nameof(reference));
@ -52,7 +54,8 @@ namespace Avalonia.Data.Core.Plugins
private const BindingFlags PropertyBindingFlags = private const BindingFlags PropertyBindingFlags =
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
private PropertyInfo? GetFirstPropertyWithName(object instance, string propertyName) private PropertyInfo? GetFirstPropertyWithName(object instance, string propertyName)
{ {
if (instance is IReflectableType reflectableType && instance is not Type) if (instance is IReflectableType reflectableType && instance is not Type)
@ -70,7 +73,8 @@ namespace Avalonia.Data.Core.Plugins
return propertyInfo; return propertyInfo;
} }
private PropertyInfo? TryFindAndCacheProperty(Type type, string propertyName) private PropertyInfo? TryFindAndCacheProperty(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] Type type, string propertyName)
{ {
PropertyInfo? found = null; PropertyInfo? found = null;

9
src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
@ -10,8 +11,10 @@ namespace Avalonia.Data.Core.Plugins
private readonly Dictionary<(Type, string), MethodInfo?> _methodLookup = private readonly Dictionary<(Type, string), MethodInfo?> _methodLookup =
new Dictionary<(Type, string), MethodInfo?>(); new Dictionary<(Type, string), MethodInfo?>();
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public bool Match(object obj, string methodName) => GetFirstMethodWithName(obj.GetType(), methodName) != null; public bool Match(object obj, string methodName) => GetFirstMethodWithName(obj.GetType(), methodName) != null;
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public IPropertyAccessor? Start(WeakReference<object?> reference, string methodName) public IPropertyAccessor? Start(WeakReference<object?> reference, string methodName)
{ {
_ = reference ?? throw new ArgumentNullException(nameof(reference)); _ = reference ?? throw new ArgumentNullException(nameof(reference));
@ -34,7 +37,8 @@ namespace Avalonia.Data.Core.Plugins
} }
} }
private MethodInfo? GetFirstMethodWithName(Type type, string methodName) private MethodInfo? GetFirstMethodWithName(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type, string methodName)
{ {
var key = (type, methodName); var key = (type, methodName);
@ -46,7 +50,8 @@ namespace Avalonia.Data.Core.Plugins
return methodInfo; return methodInfo;
} }
private MethodInfo? TryFindAndCacheMethod(Type type, string methodName) private MethodInfo? TryFindAndCacheMethod(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type, string methodName)
{ {
MethodInfo? found = null; MethodInfo? found = null;

5
src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reflection; using System.Reflection;
@ -8,6 +9,7 @@ namespace Avalonia.Data.Core.Plugins
/// <summary> /// <summary>
/// Handles binding to <see cref="IObservable{T}"/>s for the '^' stream binding operator. /// Handles binding to <see cref="IObservable{T}"/>s for the '^' stream binding operator.
/// </summary> /// </summary>
[UnconditionalSuppressMessage("Trimming", "IL3050", Justification = TrimmingMessages.IgnoreNativeAotSupressWarningMessage)]
public class ObservableStreamPlugin : IStreamPlugin public class ObservableStreamPlugin : IStreamPlugin
{ {
static MethodInfo? observableSelect; static MethodInfo? observableSelect;
@ -17,6 +19,7 @@ namespace Avalonia.Data.Core.Plugins
/// </summary> /// </summary>
/// <param name="reference">A weak reference to the value.</param> /// <param name="reference">A weak reference to the value.</param>
/// <returns>True if the plugin can handle the value; otherwise false.</returns> /// <returns>True if the plugin can handle the value; otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public virtual bool Match(WeakReference<object?> reference) public virtual bool Match(WeakReference<object?> reference)
{ {
reference.TryGetTarget(out var target); reference.TryGetTarget(out var target);
@ -33,6 +36,7 @@ namespace Avalonia.Data.Core.Plugins
/// <returns> /// <returns>
/// An observable that produces the output for the value. /// An observable that produces the output for the value.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public virtual IObservable<object?> Start(WeakReference<object?> reference) public virtual IObservable<object?> Start(WeakReference<object?> reference)
{ {
if (!reference.TryGetTarget(out var target) || target is null) if (!reference.TryGetTarget(out var target) || target is null)
@ -65,6 +69,7 @@ namespace Avalonia.Data.Core.Plugins
new object[] { target, box })!; new object[] { target, box })!;
} }
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
private static MethodInfo GetObservableSelect(Type source) private static MethodInfo GetObservableSelect(Type source)
{ {
return GetObservableSelect().MakeGenericMethod(source, typeof(object)); return GetObservableSelect().MakeGenericMethod(source, typeof(object));

9
src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Reflection; using System.Reflection;
@ -9,6 +10,7 @@ namespace Avalonia.Data.Core.Plugins
/// <summary> /// <summary>
/// Handles binding to <see cref="Task"/>s for the '^' stream binding operator. /// Handles binding to <see cref="Task"/>s for the '^' stream binding operator.
/// </summary> /// </summary>
[UnconditionalSuppressMessage("Trimming", "IL3050", Justification = TrimmingMessages.IgnoreNativeAotSupressWarningMessage)]
public class TaskStreamPlugin : IStreamPlugin public class TaskStreamPlugin : IStreamPlugin
{ {
/// <summary> /// <summary>
@ -16,12 +18,13 @@ namespace Avalonia.Data.Core.Plugins
/// </summary> /// </summary>
/// <param name="reference">A weak reference to the value.</param> /// <param name="reference">A weak reference to the value.</param>
/// <returns>True if the plugin can handle the value; otherwise false.</returns> /// <returns>True if the plugin can handle the value; otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public virtual bool Match(WeakReference<object?> reference) public virtual bool Match(WeakReference<object?> reference)
{ {
reference.TryGetTarget(out var target); reference.TryGetTarget(out var target);
return target is Task; return target is Task;
} }
/// <summary> /// <summary>
/// Starts producing output based on the specified value. /// Starts producing output based on the specified value.
@ -30,6 +33,7 @@ namespace Avalonia.Data.Core.Plugins
/// <returns> /// <returns>
/// An observable that produces the output for the value. /// An observable that produces the output for the value.
/// </returns> /// </returns>
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public virtual IObservable<object?> Start(WeakReference<object?> reference) public virtual IObservable<object?> Start(WeakReference<object?> reference)
{ {
reference.TryGetTarget(out var target); reference.TryGetTarget(out var target);
@ -59,7 +63,8 @@ namespace Avalonia.Data.Core.Plugins
return Observable.Empty<object?>(); return Observable.Empty<object?>();
} }
private IObservable<object?> HandleCompleted(Task task) [RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
private static IObservable<object?> HandleCompleted(Task task)
{ {
var resultProperty = task.GetType().GetRuntimeProperty("Result"); var resultProperty = task.GetType().GetRuntimeProperty("Result");

3
src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs

@ -1,9 +1,10 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics.CodeAnalysis;
using Avalonia.Data.Core.Plugins; using Avalonia.Data.Core.Plugins;
namespace Avalonia.Data.Core namespace Avalonia.Data.Core
{ {
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
public class PropertyAccessorNode : SettableNode public class PropertyAccessorNode : SettableNode
{ {
private readonly bool _enableValidation; private readonly bool _enableValidation;

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

@ -1,9 +1,11 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Linq; using System.Reactive.Linq;
using Avalonia.Data.Core.Plugins; using Avalonia.Data.Core.Plugins;
namespace Avalonia.Data.Core namespace Avalonia.Data.Core
{ {
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
public class StreamNode : ExpressionNode public class StreamNode : ExpressionNode
{ {
private IStreamPlugin? _customPlugin = null; private IStreamPlugin? _customPlugin = null;

30
src/Avalonia.Base/Diagnostics/TrimmingMessages.cs

@ -0,0 +1,30 @@
namespace Avalonia;
internal static class TrimmingMessages
{
public const string ImplicitTypeConvertionSupressWarningMessage = "Implicit convertion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible.";
public const string ImplicitTypeConvertionRequiresUnreferencedCodeMessage = "Implicit convertion methods are required for type conversion.";
public const string TypeConvertionSupressWarningMessage = "Convertion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible.";
public const string TypeConvertionRequiresUnreferencedCodeMessage = "Convertion methods are required for type conversion, including op_Implicit, op_Explicit, Parse and TypeConverter.";
public const string ReflectionBindingRequiresUnreferencedCodeMessage = "BindingExpression and ReflectionBinding heavily use reflection. Consider using CompiledBindings instead.";
public const string ReflectionBindingSupressWarningMessage = "BindingExpression and ReflectionBinding internal heavily use reflection.";
public const string CompiledBindingSafeSupressWarningMessage = "CompiledBinding preserves members used in the expression tree.";
public const string ExpressionNodeRequiresUnreferencedCodeMessage = "ExpressionNode might require unreferenced code.";
public const string ExpressionSafeSupressWarningMessage = "Typed Expressions preserves members used in the expression tree.";
public const string SelectorsParseRequiresUnreferencedCodeMessage = "Selectors runtime parser might require unreferenced code. Consider using stronly typed selectors factory with 'new Style(s => s.OfType<Button>())' syntax.";
public const string PropertyAccessorsRequiresUnreferencedCodeMessage = "PropertyAccessors might require unreferenced code.";
public const string DataValidationPluginRequiresUnreferencedCodeMessage = "DataValidationPlugin might require unreferenced code.";
public const string StreamPluginRequiresUnreferencedCodeMessage = "StreamPlugin might require unreferenced code.";
public const string StyleResourceIncludeRequiresUnreferenceCodeMessage = "StyleInclude and ResourceInclude use AvaloniaXamlLoader.Load which dynamically loads referenced assembly with Avalonia resources. Note, StyleInclude and ResourceInclude defined in XAML are resolved compile time and are safe with trimming and AOT.";
public const string AvaloniaXamlLoaderRequiresUnreferenceCodeMessage = "AvaloniaXamlLoader.Load(uri, baseUri) dynamically loads referenced assembly with Avalonia resources.";
public const string XamlTypeResolvedRequiresUnreferenceCodeMessage = "XamlTypeResolver might require unreferenced code.";
public const string IgnoreNativeAotSupressWarningMessage = "This method is not supported by NativeAOT.";
}

18
src/Avalonia.Base/Input/AccessKeyHandler.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.VisualTree; using Avalonia.VisualTree;
@ -23,7 +24,7 @@ namespace Avalonia.Input
/// <summary> /// <summary>
/// The registered access keys. /// The registered access keys.
/// </summary> /// </summary>
private readonly List<Tuple<string, IInputElement>> _registered = new List<Tuple<string, IInputElement>>(); private readonly List<(string AccessKey, IInputElement Element)> _registered = new();
/// <summary> /// <summary>
/// The window to which the handler belongs. /// The window to which the handler belongs.
@ -108,12 +109,12 @@ namespace Avalonia.Input
{ {
var existing = _registered.FirstOrDefault(x => x.Item2 == element); var existing = _registered.FirstOrDefault(x => x.Item2 == element);
if (existing != null) if (existing != default)
{ {
_registered.Remove(existing); _registered.Remove(existing);
} }
_registered.Add(Tuple.Create(accessKey.ToString().ToUpper(), element)); _registered.Add((accessKey.ToString().ToUpperInvariant(), element));
} }
/// <summary> /// <summary>
@ -143,7 +144,7 @@ namespace Avalonia.Input
{ {
// TODO: Use FocusScopes to store the current element and restore it when context menu is closed. // TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
// Save currently focused input element. // Save currently focused input element.
_restoreFocusElement = FocusManager.Instance?.Current; _restoreFocusElement = FocusManager.Instance?.Current;
// When Alt is pressed without a main menu, or with a closed main menu, show // When Alt is pressed without a main menu, or with a closed main menu, show
// access key markers in the window (i.e. "_File"). // access key markers in the window (i.e. "_File").
@ -180,10 +181,11 @@ namespace Avalonia.Input
{ {
// If any other key is pressed with the Alt key held down, or the main menu is open, // If any other key is pressed with the Alt key held down, or the main menu is open,
// find all controls who have registered that access key. // find all controls who have registered that access key.
var text = e.Key.ToString().ToUpper(); var text = e.Key.ToString();
var matches = _registered var matches = _registered
.Where(x => x.Item1 == text && ((Visual)x.Item2).IsEffectivelyVisible) .Where(x => string.Equals(x.AccessKey, text, StringComparison.OrdinalIgnoreCase)
.Select(x => x.Item2); && x.Element.IsEffectivelyVisible)
.Select(x => x.Element);
// If the menu is open, only match controls in the menu's visual tree. // If the menu is open, only match controls in the menu's visual tree.
if (menuIsOpen) if (menuIsOpen)
@ -194,7 +196,7 @@ namespace Avalonia.Input
var match = matches.FirstOrDefault(); var match = matches.FirstOrDefault();
// If there was a match, raise the AccessKeyPressed event on it. // If there was a match, raise the AccessKeyPressed event on it.
if (match != null) if (match is not null)
{ {
match.RaiseEvent(new RoutedEventArgs(AccessKeyPressedEvent)); match.RaiseEvent(new RoutedEventArgs(AccessKeyPressedEvent));
e.Handled = true; e.Handled = true;

4
src/Avalonia.Base/Input/DragDropDevice.cs

@ -11,7 +11,7 @@ namespace Avalonia.Input
private Interactive? _lastTarget = null; private Interactive? _lastTarget = null;
private Interactive? GetTarget(IInputRoot root, Point local) private static Interactive? GetTarget(IInputRoot root, Point local)
{ {
var hit = root.InputHitTest(local) as Visual; var hit = root.InputHitTest(local) as Visual;
var target = hit?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault(); var target = hit?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
@ -20,7 +20,7 @@ namespace Avalonia.Input
return null; return null;
} }
private DragDropEffects RaiseDragEvent(Interactive? target, IInputRoot inputRoot, Point point, RoutedEvent<DragEventArgs> routedEvent, DragDropEffects operation, IDataObject data, KeyModifiers modifiers) private static DragDropEffects RaiseDragEvent(Interactive? target, IInputRoot inputRoot, Point point, RoutedEvent<DragEventArgs> routedEvent, DragDropEffects operation, IDataObject data, KeyModifiers modifiers)
{ {
if (target == null) if (target == null)
return DragDropEffects.None; return DragDropEffects.None;

5
src/Avalonia.Base/Input/KeyGesture.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Text; using System.Text;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -143,7 +144,7 @@ namespace Avalonia.Input
// TODO: Move that to external key parser // TODO: Move that to external key parser
private static Key ParseKey(string key) private static Key ParseKey(string key)
{ {
if (s_keySynonyms.TryGetValue(key.ToLower(), out Key rv)) if (s_keySynonyms.TryGetValue(key.ToLower(CultureInfo.InvariantCulture), out Key rv))
return rv; return rv;
return EnumHelper.Parse<Key>(key, true); return EnumHelper.Parse<Key>(key, true);
@ -166,7 +167,7 @@ namespace Avalonia.Input
return EnumHelper.Parse<KeyModifiers>(modifier.ToString(), true); return EnumHelper.Parse<KeyModifiers>(modifier.ToString(), true);
} }
private Key ResolveNumPadOperationKey(Key key) private static Key ResolveNumPadOperationKey(Key key)
{ {
switch (key) switch (key)
{ {

2
src/Avalonia.Base/Input/KeyboardDevice.cs

@ -25,7 +25,7 @@ namespace Avalonia.Input
public IInputElement? FocusedElement => _focusedElement; public IInputElement? FocusedElement => _focusedElement;
private void ClearFocusWithinAncestors(IInputElement? element) private static void ClearFocusWithinAncestors(IInputElement? element)
{ {
var el = element; var el = element;

9
src/Avalonia.Base/Input/MouseDevice.cs

@ -1,12 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.VisualTree;
namespace Avalonia.Input namespace Avalonia.Input
{ {
@ -34,7 +30,7 @@ namespace Avalonia.Input
ProcessRawEvent(margs); ProcessRawEvent(margs);
} }
int ButtonCount(PointerPointProperties props) static int ButtonCount(PointerPointProperties props)
{ {
var rv = 0; var rv = 0;
if (props.IsLeftButtonPressed) if (props.IsLeftButtonPressed)
@ -106,9 +102,10 @@ namespace Avalonia.Input
private void LeaveWindow() private void LeaveWindow()
{ {
} }
PointerPointProperties CreateProperties(RawPointerEventArgs args) static PointerPointProperties CreateProperties(RawPointerEventArgs args)
{ {
return new PointerPointProperties(args.InputModifiers, args.Type.ToUpdateKind()); return new PointerPointProperties(args.InputModifiers, args.Type.ToUpdateKind());
} }

2
src/Avalonia.Base/Input/PenDevice.cs

@ -99,7 +99,7 @@ namespace Avalonia.Input
return false; return false;
} }
private bool PenMove(Pointer pointer, ulong timestamp, private static bool PenMove(Pointer pointer, ulong timestamp,
IInputRoot root, Point p, PointerPointProperties properties, IInputRoot root, Point p, PointerPointProperties properties,
KeyModifiers inputModifiers, IInputElement? hitTest, KeyModifiers inputModifiers, IInputElement? hitTest,
Lazy<IReadOnlyList<RawPointerPoint>?>? intermediatePoints) Lazy<IReadOnlyList<RawPointerPoint>?>? intermediatePoints)

6
src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs

@ -20,7 +20,8 @@ namespace Avalonia.Input.Platform
WholeWordTextActionModifiers = wholeWordTextActionModifiers; WholeWordTextActionModifiers = wholeWordTextActionModifiers;
Copy = new List<KeyGesture> Copy = new List<KeyGesture>
{ {
new KeyGesture(Key.C, commandModifiers) new KeyGesture(Key.C, commandModifiers),
new KeyGesture(Key.Insert, KeyModifiers.Control)
}; };
Cut = new List<KeyGesture> Cut = new List<KeyGesture>
{ {
@ -28,7 +29,8 @@ namespace Avalonia.Input.Platform
}; };
Paste = new List<KeyGesture> Paste = new List<KeyGesture>
{ {
new KeyGesture(Key.V, commandModifiers) new KeyGesture(Key.V, commandModifiers),
new KeyGesture(Key.Insert, KeyModifiers.Shift)
}; };
Undo = new List<KeyGesture> Undo = new List<KeyGesture>
{ {

4
src/Avalonia.Base/Input/Pointer.cs

@ -19,7 +19,7 @@ namespace Avalonia.Input
public int Id { get; } public int Id { get; }
IInputElement? FindCommonParent(IInputElement? control1, IInputElement? control2) static IInputElement? FindCommonParent(IInputElement? control1, IInputElement? control2)
{ {
if (control1 is not Visual c1 || control2 is not Visual c2) if (control1 is not Visual c1 || control2 is not Visual c2)
return null; return null;
@ -54,7 +54,7 @@ namespace Avalonia.Input
v3.DetachedFromVisualTree += OnCaptureDetached; v3.DetachedFromVisualTree += OnCaptureDetached;
} }
IInputElement? GetNextCapture(Visual parent) static IInputElement? GetNextCapture(Visual parent)
{ {
return parent as IInputElement ?? parent.FindAncestorOfType<IInputElement>(); return parent as IInputElement ?? parent.FindAncestorOfType<IInputElement>();
} }

2
src/Avalonia.Base/Input/TouchDevice.cs

@ -21,7 +21,7 @@ namespace Avalonia.Input
private Rect _lastClickRect; private Rect _lastClickRect;
private ulong _lastClickTime; private ulong _lastClickTime;
RawInputModifiers GetModifiers(RawInputModifiers modifiers, bool isLeftButtonDown) static RawInputModifiers GetModifiers(RawInputModifiers modifiers, bool isLeftButtonDown)
{ {
var rv = modifiers &= RawInputModifiers.KeyboardMask; var rv = modifiers &= RawInputModifiers.KeyboardMask;
if (isLeftButtonDown) if (isLeftButtonDown)

2
src/Avalonia.Base/Layout/AttachedLayout.cs

@ -184,7 +184,7 @@ namespace Avalonia.Layout
/// </summary> /// </summary>
protected void InvalidateArrange() => ArrangeInvalidated?.Invoke(this, EventArgs.Empty); protected void InvalidateArrange() => ArrangeInvalidated?.Invoke(this, EventArgs.Empty);
private VirtualizingLayoutContext GetVirtualizingLayoutContext(LayoutContext context) private static VirtualizingLayoutContext GetVirtualizingLayoutContext(LayoutContext context)
{ {
if (context is VirtualizingLayoutContext virtualizingContext) if (context is VirtualizingLayoutContext virtualizingContext)
{ {

4
src/Avalonia.Base/Layout/StackLayout.cs

@ -335,7 +335,7 @@ namespace Avalonia.Layout
InvalidateLayout(); InvalidateLayout();
} }
private double GetAverageElementSize( private static double GetAverageElementSize(
Size availableSize, Size availableSize,
VirtualizingLayoutContext context, VirtualizingLayoutContext context,
StackLayoutState stackLayoutState) StackLayoutState stackLayoutState)
@ -359,6 +359,6 @@ namespace Avalonia.Layout
private void InvalidateLayout() => InvalidateMeasure(); private void InvalidateLayout() => InvalidateMeasure();
private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((StackLayoutState)context.LayoutState!).FlowAlgorithm; private static FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((StackLayoutState)context.LayoutState!).FlowAlgorithm;
} }
} }

2
src/Avalonia.Base/Layout/UniformGridLayout.cs

@ -557,6 +557,6 @@ namespace Avalonia.Layout
private void InvalidateLayout() => InvalidateMeasure(); private void InvalidateLayout() => InvalidateMeasure();
private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((UniformGridLayoutState)context.LayoutState!).FlowAlgorithm; private static FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((UniformGridLayoutState)context.LayoutState!).FlowAlgorithm;
} }
} }

12
src/Avalonia.Base/Media/PathMarkupParser.cs

@ -527,7 +527,7 @@ namespace Avalonia.Media
return span.Slice(i); return span.Slice(i);
} }
private bool ReadBool(ref ReadOnlySpan<char> span) private static bool ReadBool(ref ReadOnlySpan<char> span)
{ {
span = SkipWhitespace(span); span = SkipWhitespace(span);
@ -551,7 +551,7 @@ namespace Avalonia.Media
} }
} }
private double ReadDouble(ref ReadOnlySpan<char> span) private static double ReadDouble(ref ReadOnlySpan<char> span)
{ {
if (!ReadArgument(ref span, out var doubleValue)) if (!ReadArgument(ref span, out var doubleValue))
{ {
@ -561,7 +561,7 @@ namespace Avalonia.Media
return double.Parse(doubleValue.ToString(), CultureInfo.InvariantCulture); return double.Parse(doubleValue.ToString(), CultureInfo.InvariantCulture);
} }
private Size ReadSize(ref ReadOnlySpan<char> span) private static Size ReadSize(ref ReadOnlySpan<char> span)
{ {
var width = ReadDouble(ref span); var width = ReadDouble(ref span);
span = ReadSeparator(span); span = ReadSeparator(span);
@ -569,7 +569,7 @@ namespace Avalonia.Media
return new Size(width, height); return new Size(width, height);
} }
private Point ReadPoint(ref ReadOnlySpan<char> span) private static Point ReadPoint(ref ReadOnlySpan<char> span)
{ {
var x = ReadDouble(ref span); var x = ReadDouble(ref span);
span = ReadSeparator(span); span = ReadSeparator(span);
@ -577,7 +577,7 @@ namespace Avalonia.Media
return new Point(x, y); return new Point(x, y);
} }
private Point ReadRelativePoint(ref ReadOnlySpan<char> span, Point origin) private static Point ReadRelativePoint(ref ReadOnlySpan<char> span, Point origin)
{ {
var x = ReadDouble(ref span); var x = ReadDouble(ref span);
span = ReadSeparator(span); span = ReadSeparator(span);
@ -585,7 +585,7 @@ namespace Avalonia.Media
return new Point(origin.X + x, origin.Y + y); return new Point(origin.X + x, origin.Y + y);
} }
private bool ReadCommand(ref ReadOnlySpan<char> span, out Command command, out bool relative) private static bool ReadCommand(ref ReadOnlySpan<char> span, out Command command, out bool relative)
{ {
span = SkipWhitespace(span); span = SkipWhitespace(span);
if (span.IsEmpty) if (span.IsEmpty)

4
src/Avalonia.Base/Platform/AssetLoader.cs

@ -187,13 +187,13 @@ namespace Avalonia.Platform
throw new ArgumentException($"Unsupported url type: " + uri.Scheme, nameof(uri)); throw new ArgumentException($"Unsupported url type: " + uri.Scheme, nameof(uri));
} }
private (IAssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri) private static (IAssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri)
{ {
var asm = s_assemblyDescriptorResolver.GetAssembly(uri.Authority); var asm = s_assemblyDescriptorResolver.GetAssembly(uri.Authority);
return (asm, uri.GetUnescapeAbsolutePath()); return (asm, uri.GetUnescapeAbsolutePath());
} }
private IAssemblyDescriptor? GetAssembly(Uri? uri) private static IAssemblyDescriptor? GetAssembly(Uri? uri)
{ {
if (uri != null) if (uri != null)
{ {

2
src/Avalonia.Base/PropertyStore/DirectUntypedBindingObserver.cs

@ -1,9 +1,11 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Threading; using Avalonia.Threading;
namespace Avalonia.PropertyStore namespace Avalonia.PropertyStore
{ {
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
internal class DirectUntypedBindingObserver<T> : IObserver<object?>, internal class DirectUntypedBindingObserver<T> : IObserver<object?>,
IDisposable IDisposable
{ {

2
src/Avalonia.Base/PropertyStore/UntypedValueUtils.cs

@ -7,6 +7,7 @@ namespace Avalonia.PropertyStore
{ {
internal static class UntypedValueUtils internal static class UntypedValueUtils
{ {
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
public static BindingValue<T> ConvertAndValidate<T>( public static BindingValue<T> ConvertAndValidate<T>(
object? value, object? value,
Type targetType, Type targetType,
@ -23,6 +24,7 @@ namespace Avalonia.PropertyStore
return v; return v;
} }
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
public static bool TryConvertAndValidate<T>( public static bool TryConvertAndValidate<T>(
StyledPropertyBase<T> property, StyledPropertyBase<T> property,
object? value, object? value,

12
src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs

@ -87,7 +87,7 @@ namespace Avalonia.Rendering.Composition.Animations
if (elapsed < _delayTime) if (elapsed < _delayTime)
{ {
if (_delayBehavior == AnimationDelayBehavior.SetInitialValueBeforeDelay) if (_delayBehavior == AnimationDelayBehavior.SetInitialValueBeforeDelay)
return ExpressionVariant.Create(GetKeyFrame(ref ctx, _keyFrames[0])); return ExpressionVariant.Create(KeyFrameAnimationInstance<T>.GetKeyFrame(ref ctx, _keyFrames[0]));
return currentValue; return currentValue;
} }
@ -95,7 +95,7 @@ namespace Avalonia.Rendering.Composition.Animations
var iterationNumber = elapsed.Ticks / _duration.Ticks; var iterationNumber = elapsed.Ticks / _duration.Ticks;
if (_iterationBehavior == AnimationIterationBehavior.Count if (_iterationBehavior == AnimationIterationBehavior.Count
&& iterationNumber >= _iterationCount) && iterationNumber >= _iterationCount)
return ExpressionVariant.Create(GetKeyFrame(ref ctx, _keyFrames[_keyFrames.Length - 1])); return ExpressionVariant.Create(KeyFrameAnimationInstance<T>.GetKeyFrame(ref ctx, _keyFrames[_keyFrames.Length - 1]));
var evenIterationNumber = iterationNumber % 2 == 0; var evenIterationNumber = iterationNumber % 2 == 0;
@ -124,7 +124,7 @@ namespace Avalonia.Rendering.Composition.Animations
{ {
// this is the last frame // this is the last frame
if (c == _keyFrames.Length - 1) if (c == _keyFrames.Length - 1)
return ExpressionVariant.Create(GetKeyFrame(ref ctx, kf)); return ExpressionVariant.Create(KeyFrameAnimationInstance<T>.GetKeyFrame(ref ctx, kf));
left = kf; left = kf;
right = _keyFrames[c + 1]; right = _keyFrames[c + 1];
@ -147,13 +147,13 @@ namespace Avalonia.Rendering.Composition.Animations
return currentValue; return currentValue;
return ExpressionVariant.Create(_interpolator.Interpolate( return ExpressionVariant.Create(_interpolator.Interpolate(
GetKeyFrame(ref ctx, left), KeyFrameAnimationInstance<T>.GetKeyFrame(ref ctx, left),
GetKeyFrame(ref ctx, right), KeyFrameAnimationInstance<T>.GetKeyFrame(ref ctx, right),
easedKeyProgress easedKeyProgress
)); ));
} }
T GetKeyFrame(ref ExpressionEvaluationContext ctx, ServerKeyFrame<T> f) static T GetKeyFrame(ref ExpressionEvaluationContext ctx, ServerKeyFrame<T> f)
{ {
if (f.Expression != null) if (f.Expression != null)
return f.Expression.Evaluate(ref ctx).CastOrDefault<T>(); return f.Expression.Evaluate(ref ctx).CastOrDefault<T>();

2
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -124,7 +124,7 @@ public class CompositingRenderer : IRendererWithCompositor
QueueUpdate(); QueueUpdate();
} }
private void SyncChildren(Visual v) private static void SyncChildren(Visual v)
{ {
//TODO: Optimize by moving that logic to Visual itself //TODO: Optimize by moving that logic to Visual itself
if(v.CompositionVisual == null) if(v.CompositionVisual == null)

4
src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs

@ -62,7 +62,7 @@ namespace Avalonia.Rendering.Composition
return point * m; return point * m;
} }
bool TryGetInvertedTransform(CompositionVisual visual, out Matrix matrix) static bool TryGetInvertedTransform(CompositionVisual visual, out Matrix matrix)
{ {
var m = visual.TryGetServerGlobalTransform(); var m = visual.TryGetServerGlobalTransform();
if (m == null) if (m == null)
@ -75,7 +75,7 @@ namespace Avalonia.Rendering.Composition
return m33.TryInvert(out matrix); return m33.TryInvert(out matrix);
} }
bool TryTransformTo(CompositionVisual visual, Point globalPoint, out Point v) static bool TryTransformTo(CompositionVisual visual, Point globalPoint, out Point v)
{ {
v = default; v = default;
if (TryGetInvertedTransform(visual, out var m)) if (TryGetInvertedTransform(visual, out var m))

2
src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs

@ -368,7 +368,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW
: null; : null;
} }
private IDisposable? CreateChildScene(IBrush? brush) private static IDisposable? CreateChildScene(IBrush? brush)
{ {
if (brush is VisualBrush visualBrush) if (brush is VisualBrush visualBrush)
{ {

2
src/Avalonia.Base/Rendering/DeferredRenderer.cs

@ -272,7 +272,7 @@ namespace Avalonia.Rendering
} }
} }
Scene? TryGetChildScene(IRef<IDrawOperation>? op) => (op?.Item as BrushDrawOperation)?.Aux as Scene; static Scene? TryGetChildScene(IRef<IDrawOperation>? op) => (op?.Item as BrushDrawOperation)?.Aux as Scene;
/// <inheritdoc/> /// <inheritdoc/>
Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)

2
src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs

@ -318,7 +318,7 @@ namespace Avalonia.Rendering.SceneGraph
} }
} }
private void UpdateSize(Scene scene) private static void UpdateSize(Scene scene)
{ {
var renderRoot = scene.Root.Visual as IRenderRoot; var renderRoot = scene.Root.Visual as IRenderRoot;
var newSize = renderRoot?.ClientSize ?? scene.Root.Visual.Bounds.Size; var newSize = renderRoot?.ClientSize ?? scene.Root.Visual.Bounds.Size;

2
src/Avalonia.Base/StyledPropertyBase.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.PropertyStore; using Avalonia.PropertyStore;
@ -206,6 +207,7 @@ namespace Avalonia
} }
/// <inheritdoc/> /// <inheritdoc/>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
internal override IDisposable? RouteSetValue( internal override IDisposable? RouteSetValue(
AvaloniaObject target, AvaloniaObject target,
object? value, object? value,

5
src/Avalonia.Base/Styling/PropertyEqualsSelector.cs

@ -1,11 +1,10 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using Avalonia.Styling.Activators; using Avalonia.Styling.Activators;
using Avalonia.Utilities; using Avalonia.Utilities;
#nullable enable
namespace Avalonia.Styling namespace Avalonia.Styling
{ {
/// <summary> /// <summary>
@ -92,6 +91,8 @@ namespace Avalonia.Styling
protected override Selector? MovePrevious() => _previous; protected override Selector? MovePrevious() => _previous;
protected override Selector? MovePreviousOrParent() => _previous; protected override Selector? MovePreviousOrParent() => _previous;
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.TypeConvertionSupressWarningMessage)]
[UnconditionalSuppressMessage("Trimming", "IL2067", Justification = TrimmingMessages.TypeConvertionSupressWarningMessage)]
internal static bool Compare(Type propertyType, object? propertyValue, object? value) internal static bool Compare(Type propertyType, object? propertyValue, object? value)
{ {
if (propertyType == typeof(object) && if (propertyType == typeof(object) &&

2
src/Avalonia.Base/Styling/Setter.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation; using Avalonia.Animation;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Metadata; using Avalonia.Metadata;
@ -64,6 +65,7 @@ namespace Avalonia.Styling
void IValueEntry.Unsubscribe() { } void IValueEntry.Unsubscribe() { }
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
ISetterInstance ISetter.Instance(IStyleInstance instance, StyledElement target) ISetterInstance ISetter.Instance(IStyleInstance instance, StyledElement target)
{ {
if (target is not AvaloniaObject ao) if (target is not AvaloniaObject ao)

3
src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs

@ -4,6 +4,7 @@ using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Xml.Linq; using System.Xml.Linq;
using System.Linq; using System.Linq;
using System.Diagnostics.CodeAnalysis;
namespace Avalonia.Utilities namespace Avalonia.Utilities
{ {
@ -33,6 +34,7 @@ namespace Avalonia.Utilities
return entries; return entries;
} }
[RequiresUnreferencedCode("AvaloniaResources uses Data Contract Serialization, which might require unreferenced code")]
public static void Write(Stream stream, List<AvaloniaResourcesIndexEntry> entries) public static void Write(Stream stream, List<AvaloniaResourcesIndexEntry> entries)
{ {
new BinaryWriter(stream).Write(LastKnownVersion); new BinaryWriter(stream).Write(LastKnownVersion);
@ -43,6 +45,7 @@ namespace Avalonia.Utilities
}); });
} }
[RequiresUnreferencedCode("AvaloniaResources uses Data Contract Serialization, which might require unreferenced code")]
public static byte[] Create(Dictionary<string, byte[]> data) public static byte[] Create(Dictionary<string, byte[]> data)
{ {
var sources = data.ToList(); var sources = data.ToList();

13
src/Avalonia.Base/Utilities/TypeUtilities.cs

@ -1,5 +1,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -125,6 +126,7 @@ namespace Avalonia.Utilities
/// <param name="culture">The culture to use.</param> /// <param name="culture">The culture to use.</param>
/// <param name="result">If successful, contains the convert value.</param> /// <param name="result">If successful, contains the convert value.</param>
/// <returns>True if the cast was successful, otherwise false.</returns> /// <returns>True if the cast was successful, otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
public static bool TryConvert(Type to, object? value, CultureInfo? culture, out object? result) public static bool TryConvert(Type to, object? value, CultureInfo? culture, out object? result)
{ {
if (value == null) if (value == null)
@ -150,7 +152,7 @@ namespace Avalonia.Utilities
if (toUnderl == typeof(string)) if (toUnderl == typeof(string))
{ {
result = Convert.ToString(value, culture); result = Convert.ToString(value, culture)!;
return true; return true;
} }
@ -244,6 +246,7 @@ namespace Avalonia.Utilities
/// <param name="value">The value to convert.</param> /// <param name="value">The value to convert.</param>
/// <param name="result">If successful, contains the converted value.</param> /// <param name="result">If successful, contains the converted value.</param>
/// <returns>True if the convert was successful, otherwise false.</returns> /// <returns>True if the convert was successful, otherwise false.</returns>
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public static bool TryConvertImplicit(Type to, object? value, out object? result) public static bool TryConvertImplicit(Type to, object? value, out object? result)
{ {
if (value == null) if (value == null)
@ -306,6 +309,7 @@ namespace Avalonia.Utilities
/// <param name="type">The type to convert to..</param> /// <param name="type">The type to convert to..</param>
/// <param name="culture">The culture to use.</param> /// <param name="culture">The culture to use.</param>
/// <returns>A value of <paramref name="type"/>.</returns> /// <returns>A value of <paramref name="type"/>.</returns>
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
public static object? ConvertOrDefault(object? value, Type type, CultureInfo culture) public static object? ConvertOrDefault(object? value, Type type, CultureInfo culture)
{ {
return TryConvert(type, value, culture, out var result) ? result : Default(type); return TryConvert(type, value, culture, out var result) ? result : Default(type);
@ -318,11 +322,13 @@ namespace Avalonia.Utilities
/// <param name="value">The value to convert.</param> /// <param name="value">The value to convert.</param>
/// <param name="type">The type to convert to.</param> /// <param name="type">The type to convert to.</param>
/// <returns>A value of <paramref name="type"/>.</returns> /// <returns>A value of <paramref name="type"/>.</returns>
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public static object? ConvertImplicitOrDefault(object? value, Type type) public static object? ConvertImplicitOrDefault(object? value, Type type)
{ {
return TryConvertImplicit(type, value, out var result) ? result : Default(type); return TryConvertImplicit(type, value, out var result) ? result : Default(type);
} }
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public static T ConvertImplicit<T>(object value) public static T ConvertImplicit<T>(object value)
{ {
if (TryConvertImplicit(typeof(T), value, out var result)) if (TryConvertImplicit(typeof(T), value, out var result))
@ -339,6 +345,7 @@ namespace Avalonia.Utilities
/// </summary> /// </summary>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns>The default value.</returns> /// <returns>The default value.</returns>
[UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "We don't care about public ctors for the value types, and always return null for the ref types.")]
public static object? Default(Type type) public static object? Default(Type type)
{ {
if (type.IsValueType) if (type.IsValueType)
@ -391,7 +398,9 @@ namespace Avalonia.Utilities
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
} }
private static MethodInfo? FindTypeConversionOperatorMethod(Type fromType, Type toType, OperatorType operatorType) private static MethodInfo? FindTypeConversionOperatorMethod(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type fromType,
Type toType, OperatorType operatorType)
{ {
const string implicitName = "op_Implicit"; const string implicitName = "op_Implicit";
const string explicitName = "op_Explicit"; const string explicitName = "op_Explicit";

8
src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -20,7 +21,8 @@ namespace Avalonia.Utilities
/// <param name="target">The event source.</param> /// <param name="target">The event source.</param>
/// <param name="eventName">The name of the event.</param> /// <param name="eventName">The name of the event.</param>
/// <param name="subscriber">The subscriber.</param> /// <param name="subscriber">The subscriber.</param>
public static void Subscribe<TTarget, TEventArgs, TSubscriber>(TTarget target, string eventName, EventHandler<TEventArgs> subscriber) public static void Subscribe<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] TTarget, TEventArgs, TSubscriber>(
TTarget target, string eventName, EventHandler<TEventArgs> subscriber)
where TEventArgs : EventArgs where TSubscriber : class where TEventArgs : EventArgs where TSubscriber : class
{ {
_ = target ?? throw new ArgumentNullException(nameof(target)); _ = target ?? throw new ArgumentNullException(nameof(target));
@ -92,7 +94,9 @@ namespace Avalonia.Utilities
private static Dictionary<MethodInfo, CallerDelegate> s_Callers = private static Dictionary<MethodInfo, CallerDelegate> s_Callers =
new Dictionary<MethodInfo, CallerDelegate>(); new Dictionary<MethodInfo, CallerDelegate>();
public Subscription(SubscriptionDic<T, TSubscriber> sdic, Type targetType, object target, string eventName) public Subscription(SubscriptionDic<T, TSubscriber> sdic,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] Type targetType,
object target, string eventName)
{ {
_sdic = sdic; _sdic = sdic;
_target = target; _target = target;

3
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -6,7 +6,7 @@
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder> <BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
<DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>
<CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies>
<NoWarn>NU1605;CS8632</NoWarn> <NoWarn>$(NoWarn);NU1605;CS8632</NoWarn>
</PropertyGroup> </PropertyGroup>
<!--Disable Net Perf. analyzer for submodule to avoid commit issue --> <!--Disable Net Perf. analyzer for submodule to avoid commit issue -->
@ -111,6 +111,7 @@
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link> <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile> </Compile>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" /> <Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />
<Compile Include="..\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
<PackageReference Include="Mono.Cecil" Version="0.11.4" /> <PackageReference Include="Mono.Cecil" Version="0.11.4" />

1
src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs

@ -7,6 +7,7 @@ namespace Avalonia.Build.Tasks
LegacyResmScheme = 3, LegacyResmScheme = 3,
TransformError = 4, TransformError = 4,
EmitError = 4, EmitError = 4,
Loader = 5,
Unknown = 9999 Unknown = 9999
} }

119
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -196,7 +196,8 @@ namespace Avalonia.Build.Tasks
var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers"); var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
var createRootServiceProviderMethod = asm.MainModule.ImportReference( var createRootServiceProviderMethod = asm.MainModule.ImportReference(
typeSystem.GetTypeReference(runtimeHelpers).Resolve().Methods typeSystem.GetTypeReference(runtimeHelpers).Resolve().Methods
.First(x => x.Name == "CreateRootServiceProviderV2")); .First(x => x.Name == "CreateRootServiceProviderV3"));
var serviceProviderType = createRootServiceProviderMethod.ReturnType;
var loaderDispatcherDef = new TypeDefinition(CompiledAvaloniaXamlNamespace, "!XamlLoader", var loaderDispatcherDef = new TypeDefinition(CompiledAvaloniaXamlNamespace, "!XamlLoader",
TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object); TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
@ -212,11 +213,36 @@ namespace Avalonia.Build.Tasks
MethodAttributes.Static | MethodAttributes.Public, MethodAttributes.Static | MethodAttributes.Public,
asm.MainModule.TypeSystem.Object) asm.MainModule.TypeSystem.Object)
{ {
Parameters = {new ParameterDefinition(asm.MainModule.TypeSystem.String)} Parameters =
{
new ParameterDefinition(serviceProviderType),
new ParameterDefinition(asm.MainModule.TypeSystem.String)
},
};
var loaderDispatcherMethodOld = new MethodDefinition("TryLoad",
MethodAttributes.Static | MethodAttributes.Public,
asm.MainModule.TypeSystem.Object)
{
Parameters =
{
new ParameterDefinition(asm.MainModule.TypeSystem.String)
},
Body =
{
Instructions =
{
Instruction.Create(OpCodes.Ldnull),
Instruction.Create(OpCodes.Ldarg_0),
Instruction.Create(OpCodes.Call, loaderDispatcherMethod),
Instruction.Create(OpCodes.Ret)
}
}
}; };
loaderDispatcherDef.Methods.Add(loaderDispatcherMethod); loaderDispatcherDef.Methods.Add(loaderDispatcherMethod);
loaderDispatcherDef.Methods.Add(loaderDispatcherMethodOld);
asm.MainModule.Types.Add(loaderDispatcherDef); asm.MainModule.Types.Add(loaderDispatcherDef);
var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First( var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First(
m => m =>
m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 3 && m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 3 &&
@ -377,30 +403,42 @@ namespace Avalonia.Build.Tasks
classTypeDefinition.Fields.Add(designLoaderField); classTypeDefinition.Fields.Add(designLoaderField);
const string TrampolineName = "!XamlIlPopulateTrampoline"; const string TrampolineName = "!XamlIlPopulateTrampoline";
var trampoline = new MethodDefinition(TrampolineName, var trampolineMethodWithoutSP = new Lazy<MethodDefinition>(() => CreateTrampolineMethod(false));
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void); var trampolineMethodWithSP = new Lazy<MethodDefinition>(() => CreateTrampolineMethod(true));
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition)); MethodDefinition CreateTrampolineMethod(bool hasSystemProviderArg)
classTypeDefinition.Methods.Add(trampoline); {
var trampoline = new MethodDefinition(TrampolineName,
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
if (hasSystemProviderArg)
{
trampoline.Parameters.Add(new ParameterDefinition(serviceProviderType));
}
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
classTypeDefinition.Methods.Add(trampoline);
var regularStart = Instruction.Create(OpCodes.Call, createRootServiceProviderMethod); var regularStart = Instruction.Create(OpCodes.Nop);
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, regularStart)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, regularStart));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); trampoline.Body.Instructions.Add(Instruction.Create(hasSystemProviderArg ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, designLoaderLoad)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, designLoaderLoad));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
trampoline.Body.Instructions.Add(regularStart); trampoline.Body.Instructions.Add(regularStart);
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); trampoline.Body.Instructions.Add(Instruction.Create(hasSystemProviderArg ? OpCodes.Ldarg_0 : OpCodes.Ldnull));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); trampoline.Body.Instructions.Add(Instruction.Create(hasSystemProviderArg ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0));
CopyDebugDocument(trampoline, compiledPopulateMethod); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
CopyDebugDocument(trampoline, compiledPopulateMethod);
return trampoline;
}
var foundXamlLoader = false; var foundXamlLoader = false;
// Find AvaloniaXamlLoader.Load(this) and replace it with !XamlIlPopulateTrampoline(this) // Find AvaloniaXamlLoader.Load(this) or AvaloniaXamlLoader.Load(sp, this) and replace it with !XamlIlPopulateTrampoline(this)
foreach (var method in classTypeDefinition.Methods foreach (var method in classTypeDefinition.Methods.ToArray())
.Where(m => !m.Attributes.HasFlag(MethodAttributes.Static)))
{ {
var i = method.Body.Instructions; var i = method.Body.Instructions;
for (var c = 1; c < i.Count; c++) for (var c = 1; c < i.Count; c++)
@ -422,7 +460,20 @@ namespace Avalonia.Build.Tasks
{ {
if (MatchThisCall(i, c - 1)) if (MatchThisCall(i, c - 1))
{ {
i[c].Operand = trampoline; i[c].Operand = trampolineMethodWithoutSP.Value;
foundXamlLoader = true;
}
}
if (op != null
&& op.Name == "Load"
&& op.Parameters.Count == 2
&& op.Parameters[0].ParameterType.FullName == "System.IServiceProvider"
&& op.Parameters[1].ParameterType.FullName == "System.Object"
&& op.DeclaringType.FullName == "Avalonia.Markup.Xaml.AvaloniaXamlLoader")
{
if (MatchThisCall(i, c - 1))
{
i[c].Operand = trampolineMethodWithSP.Value;
foundXamlLoader = true; foundXamlLoader = true;
} }
} }
@ -439,7 +490,7 @@ namespace Avalonia.Build.Tasks
{ {
var i = ctors[0].Body.Instructions; var i = ctors[0].Body.Instructions;
var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret)); var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret));
i.Insert(retIdx, Instruction.Create(OpCodes.Call, trampoline)); i.Insert(retIdx, Instruction.Create(OpCodes.Call, trampolineMethodWithoutSP.Value));
i.Insert(retIdx, Instruction.Create(OpCodes.Ldarg_0)); i.Insert(retIdx, Instruction.Create(OpCodes.Ldarg_0));
} }
else else
@ -461,20 +512,33 @@ namespace Avalonia.Build.Tasks
null : null :
classTypeDefinition.GetConstructors().FirstOrDefault(c => classTypeDefinition.GetConstructors().FirstOrDefault(c =>
c.IsPublic && !c.IsStatic && !c.HasParameters); c.IsPublic && !c.IsStatic && !c.HasParameters);
var constructorWithSp = compiledBuildMethod != null ?
null :
classTypeDefinition.GetConstructors().FirstOrDefault(c =>
c.IsPublic && !c.IsStatic && c.Parameters.Count == 1 && c.Parameters[0].ParameterType.FullName == serviceProviderType.FullName);
if (compiledBuildMethod != null || parameterlessConstructor != null) if (compiledBuildMethod != null || parameterlessConstructor != null || constructorWithSp != null)
{ {
var i = loaderDispatcherMethod.Body.Instructions; var i = loaderDispatcherMethod.Body.Instructions;
var nop = Instruction.Create(OpCodes.Nop); var nop = Instruction.Create(OpCodes.Nop);
i.Add(Instruction.Create(OpCodes.Ldarg_0)); i.Add(Instruction.Create(OpCodes.Ldarg_1));
i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri)); i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri));
i.Add(Instruction.Create(OpCodes.Ldc_I4, (int)StringComparison.OrdinalIgnoreCase)); i.Add(Instruction.Create(OpCodes.Ldc_I4, (int)StringComparison.OrdinalIgnoreCase));
i.Add(Instruction.Create(OpCodes.Call, stringEquals)); i.Add(Instruction.Create(OpCodes.Call, stringEquals));
i.Add(Instruction.Create(OpCodes.Brfalse, nop)); i.Add(Instruction.Create(OpCodes.Brfalse, nop));
if (parameterlessConstructor != null) if (parameterlessConstructor != null)
{
i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor)); i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor));
}
else if (constructorWithSp != null)
{
i.Add(Instruction.Create(OpCodes.Ldarg_0));
i.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod));
i.Add(Instruction.Create(OpCodes.Newobj, constructorWithSp));
}
else else
{ {
i.Add(Instruction.Create(OpCodes.Ldarg_0));
i.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod)); i.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod));
i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod)); i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod));
} }
@ -482,6 +546,11 @@ namespace Avalonia.Build.Tasks
i.Add(Instruction.Create(OpCodes.Ret)); i.Add(Instruction.Create(OpCodes.Ret));
i.Add(nop); i.Add(nop);
} }
else
{
engine.LogWarning(BuildEngineErrorCode.Loader, "",
$"XAML resource \"{res.Uri}\" won't be reachable via runtime loader, as no public constructor was found");
}
} }
} }

1
src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj

@ -21,6 +21,7 @@
<Import Project="..\..\build\BuildTargets.targets" /> <Import Project="..\..\build\BuildTargets.targets" />
<!--<Import Project="..\..\build\ApiDiff.props" />--> <!--<Import Project="..\..\build\ApiDiff.props" />-->
<Import Project="..\..\build\NullableEnable.props" /> <Import Project="..\..\build\NullableEnable.props" />
<Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\DevAnalyzers.props" /> <Import Project="..\..\build\DevAnalyzers.props" />
<ItemGroup Label="InternalsVisibleTo"> <ItemGroup Label="InternalsVisibleTo">

2
src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs

@ -154,7 +154,7 @@ namespace Avalonia.Controls.Primitives
/// </summary> /// </summary>
/// <param name="hsvColor">The <see cref="HsvColor"/> to round component values for.</param> /// <param name="hsvColor">The <see cref="HsvColor"/> to round component values for.</param>
/// <returns>A new <see cref="HsvColor"/> with rounded component values.</returns> /// <returns>A new <see cref="HsvColor"/> with rounded component values.</returns>
private HsvColor RoundComponentValues(HsvColor hsvColor) private static HsvColor RoundComponentValues(HsvColor hsvColor)
{ {
return new HsvColor( return new HsvColor(
Math.Round(hsvColor.A, 2, MidpointRounding.AwayFromZero), Math.Round(hsvColor.A, 2, MidpointRounding.AwayFromZero),

2
src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs

@ -1146,7 +1146,7 @@ namespace Avalonia.Controls.Primitives
}); });
} }
private void FillPixelForBox( private static void FillPixelForBox(
double x, double x,
double y, double y,
Hsv baseHsv, Hsv baseHsv,

2
src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs

@ -56,7 +56,7 @@ namespace Avalonia.Controls
set => SetAndRaise(CellEditingTemplateProperty, ref _cellEditingCellTemplate, value); set => SetAndRaise(CellEditingTemplateProperty, ref _cellEditingCellTemplate, value);
} }
private void OnCellTemplateChanged(AvaloniaPropertyChangedEventArgs e) private static void OnCellTemplateChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var oldValue = (IDataTemplate)e.OldValue; var oldValue = (IDataTemplate)e.OldValue;
var value = (IDataTemplate)e.NewValue; var value = (IDataTemplate)e.NewValue;

50
src/Avalonia.Controls/AppBuilderBase.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using System.Linq; using System.Linq;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@ -162,13 +163,6 @@ namespace Avalonia.Controls
return Self; return Self;
} }
/// <summary>
/// Specifies a windowing subsystem to use.
/// </summary>
/// <param name="dll">The dll in which to look for subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseWindowingSubsystem(string dll) => UseWindowingSubsystem(GetInitializer(dll), dll.Replace("Avalonia.", string.Empty));
/// <summary> /// <summary>
/// Specifies a rendering subsystem to use. /// Specifies a rendering subsystem to use.
/// </summary> /// </summary>
@ -182,50 +176,8 @@ namespace Avalonia.Controls
return Self; return Self;
} }
/// <summary>
/// Specifies a rendering subsystem to use.
/// </summary>
/// <param name="dll">The dll in which to look for subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseRenderingSubsystem(string dll) => UseRenderingSubsystem(GetInitializer(dll));
static Action GetInitializer(string assemblyName) => () =>
{
var assembly = Assembly.Load(new AssemblyName(assemblyName));
var platformClassName = assemblyName.Replace("Avalonia.", string.Empty) + "Platform";
var platformClassFullName = assemblyName + "." + platformClassName;
var platformClass = assembly.GetType(platformClassFullName);
var init = platformClass!.GetRuntimeMethod("Initialize", Type.EmptyTypes);
init!.Invoke(null, null);
};
public TAppBuilder UseAvaloniaModules() => AfterSetup(builder => SetupAvaloniaModules());
protected virtual bool CheckSetup => true; protected virtual bool CheckSetup => true;
/// <summary>
/// Searches and initiates modules included with <see cref="ExportAvaloniaModuleAttribute"/> attribute.
/// </summary>
private void SetupAvaloniaModules()
{
var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from attribute in assembly.GetCustomAttributes<ExportAvaloniaModuleAttribute>()
where string.IsNullOrEmpty(attribute.ForWindowingSubsystem)
|| attribute.ForWindowingSubsystem == WindowingSubsystemName
where string.IsNullOrEmpty(attribute.ForRenderingSubsystem)
|| attribute.ForRenderingSubsystem == RenderingSubsystemName
group attribute by attribute.Name into exports
select (from export in exports
orderby export.ForWindowingSubsystem.Length descending
orderby export.ForRenderingSubsystem.Length descending
select export).First().ModuleType into moduleType
select (from constructor in moduleType.GetTypeInfo().DeclaredConstructors
where constructor.GetParameters().Length == 0 && !constructor.IsStatic
select constructor).Single() into constructor
select (Action)(() => constructor.Invoke(Array.Empty<object>()));
Delegate.Combine(moduleInitializers.ToArray())!.DynamicInvoke();
}
/// <summary> /// <summary>
/// Configures platform-specific options /// Configures platform-specific options
/// </summary> /// </summary>

2
src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs

@ -71,7 +71,7 @@ namespace Avalonia.Automation.Peers
} }
} }
private ExpandCollapseState ToState(bool value) private static ExpandCollapseState ToState(bool value)
{ {
return value ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed; return value ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed;
} }

1
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -10,6 +10,7 @@
<Import Project="..\..\build\JetBrains.Annotations.props" /> <Import Project="..\..\build\JetBrains.Annotations.props" />
<Import Project="..\..\build\ApiDiff.props" /> <Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" /> <Import Project="..\..\build\NullableEnable.props" />
<Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\DevAnalyzers.props" /> <Import Project="..\..\build\DevAnalyzers.props" />
<ItemGroup Label="InternalsVisibleTo"> <ItemGroup Label="InternalsVisibleTo">

2
src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs

@ -206,7 +206,7 @@ namespace Avalonia.Controls.Primitives
return true; return true;
} }
private void EnsureValidThread() private static void EnsureValidThread()
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
} }

3
src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs

@ -6,7 +6,6 @@
using Avalonia.Threading; using Avalonia.Threading;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Threading;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
@ -353,7 +352,7 @@ namespace Avalonia.Controls.Primitives
return true; return true;
} }
private void EnsureValidThread() private static void EnsureValidThread()
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();
} }

8
src/Avalonia.Controls/Grid.cs

@ -1165,7 +1165,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// For "Auto" definitions MinWidth is used in place of PreferredSize. /// For "Auto" definitions MinWidth is used in place of PreferredSize.
/// </remarks> /// </remarks>
private double GetMeasureSizeForRange( private static double GetMeasureSizeForRange(
IReadOnlyList<DefinitionBase> definitions, IReadOnlyList<DefinitionBase> definitions,
int start, int start,
int count) int count)
@ -1192,7 +1192,7 @@ namespace Avalonia.Controls
/// <param name="start">Starting index of the range.</param> /// <param name="start">Starting index of the range.</param>
/// <param name="count">Number of definitions included in the range.</param> /// <param name="count">Number of definitions included in the range.</param>
/// <returns>Length type for given range.</returns> /// <returns>Length type for given range.</returns>
private LayoutTimeSizeType GetLengthTypeForRange( private static LayoutTimeSizeType GetLengthTypeForRange(
IReadOnlyList<DefinitionBase> definitions, IReadOnlyList<DefinitionBase> definitions,
int start, int start,
int count) int count)
@ -1721,7 +1721,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="definitions">Array of definitions to use for calculations.</param> /// <param name="definitions">Array of definitions to use for calculations.</param>
/// <returns>Desired size.</returns> /// <returns>Desired size.</returns>
private double CalculateDesiredSize( private static double CalculateDesiredSize(
IReadOnlyList<DefinitionBase> definitions) IReadOnlyList<DefinitionBase> definitions)
{ {
double desiredSize = 0; double desiredSize = 0;
@ -2281,7 +2281,7 @@ namespace Avalonia.Controls
/// <param name="start">Start of the range.</param> /// <param name="start">Start of the range.</param>
/// <param name="count">Number of items in the range.</param> /// <param name="count">Number of items in the range.</param>
/// <returns>Final size.</returns> /// <returns>Final size.</returns>
private double GetFinalSizeForRange( private static double GetFinalSizeForRange(
IReadOnlyList<DefinitionBase> definitions, IReadOnlyList<DefinitionBase> definitions,
int start, int start,
int count) int count)

2
src/Avalonia.Controls/GridSplitter.cs

@ -516,7 +516,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Retrieves the ActualWidth or ActualHeight of the definition depending on its type Column or Row. /// Retrieves the ActualWidth or ActualHeight of the definition depending on its type Column or Row.
/// </summary> /// </summary>
private double GetActualLength(DefinitionBase definition) private static double GetActualLength(DefinitionBase definition)
{ {
var column = definition as ColumnDefinition; var column = definition as ColumnDefinition;

11
src/Avalonia.Controls/MenuItemAccessKeyHandler.cs

@ -14,7 +14,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// The registered access keys. /// The registered access keys.
/// </summary> /// </summary>
private readonly List<Tuple<string, IInputElement>> _registered = new List<Tuple<string, IInputElement>>(); private readonly List<(string AccessKey, IInputElement Element)> _registered = new();
/// <summary> /// <summary>
/// The window to which the handler belongs. /// The window to which the handler belongs.
@ -59,12 +59,12 @@ namespace Avalonia.Controls
{ {
var existing = _registered.FirstOrDefault(x => x.Item2 == element); var existing = _registered.FirstOrDefault(x => x.Item2 == element);
if (existing != null) if (existing != default)
{ {
_registered.Remove(existing); _registered.Remove(existing);
} }
_registered.Add(Tuple.Create(accessKey.ToString().ToUpper(), element)); _registered.Add((accessKey.ToString().ToUpperInvariant(), element));
} }
/// <summary> /// <summary>
@ -88,9 +88,10 @@ namespace Avalonia.Controls
{ {
if (!string.IsNullOrWhiteSpace(e.Text)) if (!string.IsNullOrWhiteSpace(e.Text))
{ {
var text = e.Text.ToUpper(); var text = e.Text;
var focus = _registered var focus = _registered
.FirstOrDefault(x => x.Item1 == text && x.Item2.IsEffectivelyVisible)?.Item2; .FirstOrDefault(x => string.Equals(x.AccessKey, text, StringComparison.OrdinalIgnoreCase)
&& x.Element.IsEffectivelyVisible).Element;
focus?.RaiseEvent(new RoutedEventArgs(AccessKeyHandler.AccessKeyPressedEvent)); focus?.RaiseEvent(new RoutedEventArgs(AccessKeyHandler.AccessKeyPressedEvent));

12
src/Avalonia.Controls/NativeMenuBar.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -21,7 +22,16 @@ namespace Avalonia.Controls
item.Click -= OnMenuItemClick; item.Click -= OnMenuItemClick;
}); });
} }
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NativeMenu))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NativeMenuItem))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NativeMenuItemBase))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NativeMenuItemSeparator))]
public NativeMenuBar()
{
}
public static void SetEnableMenuItemClickForwarding(MenuItem menuItem, bool enable) public static void SetEnableMenuItemClickForwarding(MenuItem menuItem, bool enable)
{ {
menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable); menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable);

6
src/Avalonia.Controls/Notifications/WindowNotificationManager.cs

@ -146,7 +146,11 @@ namespace Avalonia.Controls.Notifications
{ {
var adornerLayer = host.FindDescendantOfType<VisualLayerManager>()?.AdornerLayer; var adornerLayer = host.FindDescendantOfType<VisualLayerManager>()?.AdornerLayer;
adornerLayer?.Children.Add(this); if (adornerLayer is not null)
{
adornerLayer.Children.Add(this);
AdornerLayer.SetAdornedElement(this, adornerLayer);
}
} }
private void UpdatePseudoClasses(NotificationPosition position) private void UpdatePseudoClasses(NotificationPosition position)

4
src/Avalonia.Controls/Platform/InProcessDragSource.cs

@ -69,7 +69,7 @@ namespace Avalonia.Platform
return effect; return effect;
} }
private DragDropEffects GetPreferredEffect(DragDropEffects effect, RawInputModifiers modifiers) private static DragDropEffects GetPreferredEffect(DragDropEffects effect, RawInputModifiers modifiers)
{ {
if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None) if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None)
return effect; // No need to check for the modifiers. return effect; // No need to check for the modifiers.
@ -80,7 +80,7 @@ namespace Avalonia.Platform
return DragDropEffects.Move; return DragDropEffects.Move;
} }
private StandardCursorType GetCursorForDropEffect(DragDropEffects effects) private static StandardCursorType GetCursorForDropEffect(DragDropEffects effects)
{ {
if (effects.HasAllFlags(DragDropEffects.Copy)) if (effects.HasAllFlags(DragDropEffects.Copy))
return StandardCursorType.DragCopy; return StandardCursorType.DragCopy;

6
src/Avalonia.Controls/Primitives/Popup.cs

@ -1,6 +1,5 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Automation.Peers; using Avalonia.Automation.Peers;
using Avalonia.Controls.Mixins; using Avalonia.Controls.Mixins;
@ -15,7 +14,6 @@ using Avalonia.Metadata;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Utilities;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
@ -639,7 +637,7 @@ namespace Avalonia.Controls.Primitives
return Disposable.Create((unsubscribe, target, handler), state => state.unsubscribe(state.target, state.handler)); return Disposable.Create((unsubscribe, target, handler), state => state.unsubscribe(state.target, state.handler));
} }
private void WindowManagerAddShadowHintChanged(IPopupHost host, bool hint) private static void WindowManagerAddShadowHintChanged(IPopupHost host, bool hint)
{ {
if(host is PopupRoot pr && pr.PlatformImpl is not null) if(host is PopupRoot pr && pr.PlatformImpl is not null)
{ {
@ -769,7 +767,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
private void PassThroughEvent(PointerPressedEventArgs e) private static void PassThroughEvent(PointerPressedEventArgs e)
{ {
if (e.Source is LightDismissOverlayLayer layer && if (e.Source is LightDismissOverlayLayer layer &&
layer.GetVisualRoot() is InputElement root) layer.GetVisualRoot() is InputElement root)

5
src/Avalonia.Controls/ProgressBar.cs

@ -270,15 +270,16 @@ namespace Avalonia.Controls
double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum); double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
// When the Orientation changed, the indicator's Width or Height should set to double.NaN. // When the Orientation changed, the indicator's Width or Height should set to double.NaN.
// Indicator size calculation should consider the ProgressBar's Padding property setting
if (Orientation == Orientation.Horizontal) if (Orientation == Orientation.Horizontal)
{ {
_indicator.Width = barSize.Width * percent; _indicator.Width = (barSize.Width - _indicator.Margin.Left - _indicator.Margin.Right) * percent;
_indicator.Height = double.NaN; _indicator.Height = double.NaN;
} }
else else
{ {
_indicator.Width = double.NaN; _indicator.Width = double.NaN;
_indicator.Height = barSize.Height * percent; _indicator.Height = (barSize.Height - _indicator.Margin.Top - _indicator.Margin.Bottom) * percent;
} }

2
src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs

@ -87,7 +87,7 @@ namespace Avalonia.Controls
protected virtual string OnSelectTemplateKeyCore(object? dataContext, Control? owner) protected virtual string OnSelectTemplateKeyCore(object? dataContext, Control? owner)
{ {
if (SelectTemplateKey is object) if (SelectTemplateKey is not null)
{ {
_args ??= new SelectTemplateEventArgs(); _args ??= new SelectTemplateEventArgs();
_args.TemplateKey = null; _args.TemplateKey = null;

7
src/Avalonia.Controls/SplitView.cs

@ -1,14 +1,11 @@
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using System; using System;
using System.Reactive.Disposables;
using Avalonia.Controls.Presenters; using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
@ -431,7 +428,7 @@ namespace Avalonia.Controls
} }
} }
private string GetPseudoClass(SplitViewDisplayMode mode) private static string GetPseudoClass(SplitViewDisplayMode mode)
{ {
return mode switch return mode switch
{ {
@ -443,7 +440,7 @@ namespace Avalonia.Controls
}; };
} }
private string GetPseudoClass(SplitViewPanePlacement placement) private static string GetPseudoClass(SplitViewPanePlacement placement)
{ {
return placement switch return placement switch
{ {

2
src/Avalonia.Controls/TextBox.cs

@ -1588,7 +1588,7 @@ namespace Avalonia.Controls
private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text); private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text);
private int CoerceCaretIndex(int value, string? text) private static int CoerceCaretIndex(int value, string? text)
{ {
if (text == null) if (text == null)
{ {

2
src/Avalonia.Controls/TopLevel.cs

@ -427,7 +427,7 @@ namespace Avalonia.Controls
LayoutHelper.InvalidateSelfAndChildrenMeasure(this); LayoutHelper.InvalidateSelfAndChildrenMeasure(this);
} }
private bool TransparencyLevelsMatch (WindowTransparencyLevel requested, WindowTransparencyLevel received) private static bool TransparencyLevelsMatch (WindowTransparencyLevel requested, WindowTransparencyLevel received)
{ {
if(requested == received) if(requested == received)
{ {

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

Loading…
Cancel
Save