Browse Source

Merge branch 'master' into merge-resources

pull/9577/head
Max Katz 4 years ago
committed by GitHub
parent
commit
f52d30d412
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      .editorconfig
  2. 15
      packages/Avalonia/AvaloniaBuildTasks.targets
  3. 9
      samples/ControlCatalog.NetCore/Program.cs
  4. 11
      samples/ControlCatalog.NetCore/Properties/launchSettings.json
  5. 10
      samples/ControlCatalog/ControlCatalog.csproj
  6. 29
      samples/ControlCatalog/Converter/DegToRadConverter.cs
  7. 3
      samples/ControlCatalog/MainView.xaml
  8. 25
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  9. 2
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  10. 107
      samples/ControlCatalog/Pages/CustomDrawing.xaml
  11. 67
      samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
  12. 215
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  13. 2
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  14. 2
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  15. 3
      samples/ControlCatalog/Pages/ScreenPage.cs
  16. 2
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  17. 3
      samples/Directory.Build.props
  18. 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  19. 2
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
  20. 2
      src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
  21. 2
      src/Avalonia.Base/Animation/CrossFade.cs
  22. 2
      src/Avalonia.Base/Animation/KeySpline.cs
  23. 4
      src/Avalonia.Base/Controls/Classes.cs
  24. 2
      src/Avalonia.Base/CornerRadius.cs
  25. 2
      src/Avalonia.Base/Data/Core/ExpressionNode.cs
  26. 4
      src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs
  27. 2
      src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
  28. 2
      src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
  29. 2
      src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
  30. 18
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  31. 4
      src/Avalonia.Base/Input/DragDropDevice.cs
  32. 5
      src/Avalonia.Base/Input/KeyGesture.cs
  33. 2
      src/Avalonia.Base/Input/KeyboardDevice.cs
  34. 9
      src/Avalonia.Base/Input/MouseDevice.cs
  35. 2
      src/Avalonia.Base/Input/PenDevice.cs
  36. 4
      src/Avalonia.Base/Input/Pointer.cs
  37. 2
      src/Avalonia.Base/Input/TouchDevice.cs
  38. 2
      src/Avalonia.Base/Layout/AttachedLayout.cs
  39. 4
      src/Avalonia.Base/Layout/StackLayout.cs
  40. 2
      src/Avalonia.Base/Layout/UniformGridLayout.cs
  41. 5
      src/Avalonia.Base/Media/ArcSegment.cs
  42. 6
      src/Avalonia.Base/Media/BezierSegment .cs
  43. 8
      src/Avalonia.Base/Media/BoxShadow.cs
  44. 2
      src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs
  45. 2
      src/Avalonia.Base/Media/Immutable/ImmutableTransform.cs
  46. 2
      src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
  47. 6
      src/Avalonia.Base/Media/LineSegment.cs
  48. 2
      src/Avalonia.Base/Media/MatrixTransform.cs
  49. 2
      src/Avalonia.Base/Media/PathFigure.cs
  50. 2
      src/Avalonia.Base/Media/PathGeometry.cs
  51. 12
      src/Avalonia.Base/Media/PathMarkupParser.cs
  52. 6
      src/Avalonia.Base/Media/QuadraticBezierSegment .cs
  53. 2
      src/Avalonia.Base/Media/RotateTransform.cs
  54. 2
      src/Avalonia.Base/Media/ScaleTransform.cs
  55. 2
      src/Avalonia.Base/Media/SkewTransform.cs
  56. 2
      src/Avalonia.Base/Media/Transform.cs
  57. 2
      src/Avalonia.Base/Media/TranslateTransform.cs
  58. 4
      src/Avalonia.Base/Platform/AssetLoader.cs
  59. 2
      src/Avalonia.Base/RelativePoint.cs
  60. 12
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
  61. 2
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  62. 4
      src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
  63. 2
      src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
  64. 2
      src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs
  65. 2
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  66. 4
      src/Avalonia.Base/Rendering/DeferredRenderer.cs
  67. 2
      src/Avalonia.Base/Rendering/RendererBase.cs
  68. 2
      src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs
  69. 2
      src/Avalonia.Base/Rendering/SceneGraph/VisualNode.cs
  70. 2
      src/Avalonia.Base/Styling/Activators/IStyleActivator.cs
  71. 2
      src/Avalonia.Base/Thickness.cs
  72. 1
      src/Avalonia.Base/Visual.cs
  73. 2
      src/Avalonia.Base/VisualTree/TransformedBounds.cs
  74. 1
      src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs
  75. 2
      src/Avalonia.Build.Tasks/Extensions.cs
  76. 2
      src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
  77. 119
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  78. 2
      src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
  79. 2
      src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs
  80. 2
      src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs
  81. 2
      src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs
  82. 2
      src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
  83. 3
      src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
  84. 2
      src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs
  85. 8
      src/Avalonia.Controls/Grid.cs
  86. 2
      src/Avalonia.Controls/GridSplitter.cs
  87. 11
      src/Avalonia.Controls/MenuItemAccessKeyHandler.cs
  88. 4
      src/Avalonia.Controls/Platform/InProcessDragSource.cs
  89. 6
      src/Avalonia.Controls/Primitives/Popup.cs
  90. 2
      src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs
  91. 2
      src/Avalonia.Controls/Selection/IndexRange.cs
  92. 4
      src/Avalonia.Controls/Selection/SelectionNodeBase.cs
  93. 20
      src/Avalonia.Controls/Slider.cs
  94. 7
      src/Avalonia.Controls/SplitView.cs
  95. 2
      src/Avalonia.Controls/TextBox.cs
  96. 2
      src/Avalonia.Controls/TopLevel.cs
  97. 1
      src/Avalonia.Controls/UserControl.cs
  98. 2
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/HtmlTransport.cs
  99. 2
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs
  100. 2
      src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs

13
.editorconfig

@ -137,14 +137,27 @@ 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.
# 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
dotnet_diagnostic.CA1826.severity = suggestion
# CA1827: Do not use Count/LongCount when Any can be used
dotnet_diagnostic.CA1827.severity = warning
# CA1828: Do not use CountAsync/LongCountAsync when AnyAsync can be used
dotnet_diagnostic.CA1828.severity = warning
# CA1829: Use Length/Count property instead of Enumerable.Count method
dotnet_diagnostic.CA1829.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning dotnet_diagnostic.CA1847.severity = warning

15
packages/Avalonia/AvaloniaBuildTasks.targets

@ -30,7 +30,9 @@
/> />
<Target Name="AddAvaloniaResources" BeforeTargets="ResolveReferences"> <Target Name="AddAvaloniaResources"
BeforeTargets="ResolveReferences"
Condition="('@(AvaloniaResource->Count())' &gt; 0) or ('@(AvaloniaXaml->Count())' &gt; 0)">
<PropertyGroup> <PropertyGroup>
<AvaloniaResourcesTemporaryFilePath Condition="'$(AvaloniaResourcesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/resources</AvaloniaResourcesTemporaryFilePath> <AvaloniaResourcesTemporaryFilePath Condition="'$(AvaloniaResourcesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/resources</AvaloniaResourcesTemporaryFilePath>
</PropertyGroup> </PropertyGroup>
@ -62,7 +64,9 @@
BeforeTargets="CoreCompile;CoreResGen" BeforeTargets="CoreCompile;CoreResGen"
Inputs="@(AvaloniaResource);@(AvaloniaXaml);@(CustomAdditionalGenerateAvaloniaResourcesInputs);$(MSBuildAllProjects)" Inputs="@(AvaloniaResource);@(AvaloniaXaml);@(CustomAdditionalGenerateAvaloniaResourcesInputs);$(MSBuildAllProjects)"
Outputs="$(AvaloniaResourcesTemporaryFilePath)" Outputs="$(AvaloniaResourcesTemporaryFilePath)"
DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)"> DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)"
Condition="('@(AvaloniaResource->Count())' &gt; 0) or ('@(AvaloniaXaml->Count())' &gt; 0)"
>
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="@(AvaloniaXaml)"/> <AvaloniaResource Include="@(AvaloniaXaml)"/>
</ItemGroup> </ItemGroup>
@ -81,7 +85,12 @@
<Target <Target
Name="CompileAvaloniaXaml" Name="CompileAvaloniaXaml"
AfterTargets="AfterCompile" AfterTargets="AfterCompile"
Condition="Exists('@(IntermediateAssembly)') And $(DesignTimeBuild) != true And $(EnableAvaloniaXamlCompilation) != false" Condition="
(('@(AvaloniaResource->Count())' &gt; 0)
or ('@(AvaloniaXaml->Count())' &gt; 0))
and Exists('@(IntermediateAssembly)')
And $(DesignTimeBuild) != true
And $(EnableAvaloniaXamlCompilation) != false"
> >
<PropertyGroup> <PropertyGroup>
<AvaloniaXamlReferencesTemporaryFilePath Condition="'$(AvaloniaXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/references</AvaloniaXamlReferencesTemporaryFilePath> <AvaloniaXamlReferencesTemporaryFilePath Condition="'$(AvaloniaXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/references</AvaloniaXamlReferencesTemporaryFilePath>

9
samples/ControlCatalog.NetCore/Program.cs

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

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

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

10
samples/ControlCatalog/ControlCatalog.csproj

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

29
samples/ControlCatalog/Converter/DegToRadConverter.cs

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

3
samples/ControlCatalog/MainView.xaml

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

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>();

107
samples/ControlCatalog/Pages/CustomDrawing.xaml

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

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

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

215
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

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

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)));

3
samples/Directory.Build.props

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

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

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;
} }

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(":"))
{ {

2
src/Avalonia.Base/CornerRadius.cs

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

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"),

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

@ -81,7 +81,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 +193,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);

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

@ -63,7 +63,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)
{ {

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

@ -108,7 +108,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)
{ {

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

@ -59,7 +59,7 @@ namespace Avalonia.Data.Core.Plugins
return Observable.Empty<object?>(); return Observable.Empty<object?>();
} }
private IObservable<object?> HandleCompleted(Task task) private static IObservable<object?> HandleCompleted(Task task)
{ {
var resultProperty = task.GetType().GetRuntimeProperty("Result"); var resultProperty = task.GetType().GetRuntimeProperty("Result");

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)

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;
} }
} }

5
src/Avalonia.Base/Media/ArcSegment.cs

@ -1,3 +1,4 @@
using System;
using System.Globalization; using System.Globalization;
namespace Avalonia.Media namespace Avalonia.Media
@ -100,6 +101,6 @@ namespace Avalonia.Media
} }
public override string ToString() public override string ToString()
=> $"A {Size} {RotationAngle.ToString(CultureInfo.InvariantCulture)} {(IsLargeArc ? 1 : 0)} {(int)SweepDirection} {Point}"; => FormattableString.Invariant($"A {Size} {RotationAngle} {(IsLargeArc ? 1 : 0)} {(int)SweepDirection} {Point}");
} }
} }

6
src/Avalonia.Base/Media/BezierSegment .cs

@ -1,3 +1,5 @@
using System;
namespace Avalonia.Media namespace Avalonia.Media
{ {
public sealed class BezierSegment : PathSegment public sealed class BezierSegment : PathSegment
@ -60,6 +62,6 @@ namespace Avalonia.Media
} }
public override string ToString() public override string ToString()
=> $"C {Point1} {Point2} {Point3}"; => FormattableString.Invariant($"C {Point1} {Point2} {Point3}");
} }
} }

8
src/Avalonia.Base/Media/BoxShadow.cs

@ -94,22 +94,22 @@ namespace Avalonia.Media
if (OffsetX != 0.0) if (OffsetX != 0.0)
{ {
sb.AppendFormat(" {0}", OffsetX.ToString()); sb.AppendFormat(" {0}", OffsetX.ToString(CultureInfo.InvariantCulture));
} }
if (OffsetY != 0.0) if (OffsetY != 0.0)
{ {
sb.AppendFormat(" {0}", OffsetY.ToString()); sb.AppendFormat(" {0}", OffsetY.ToString(CultureInfo.InvariantCulture));
} }
if (Blur != 0.0) if (Blur != 0.0)
{ {
sb.AppendFormat(" {0}", Blur.ToString()); sb.AppendFormat(" {0}", Blur.ToString(CultureInfo.InvariantCulture));
} }
if (Spread != 0.0) if (Spread != 0.0)
{ {
sb.AppendFormat(" {0}", Spread.ToString()); sb.AppendFormat(" {0}", Spread.ToString(CultureInfo.InvariantCulture));
} }
sb.AppendFormat(" {0}", Color.ToString()); sb.AppendFormat(" {0}", Color.ToString());

2
src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs

@ -7,7 +7,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media.Imaging namespace Avalonia.Media.Imaging
{ {
/// <summary> /// <summary>
/// A bitmap that holds the rendering of a <see cref="IVisual"/>. /// A bitmap that holds the rendering of a <see cref="Visual"/>.
/// </summary> /// </summary>
public class RenderTargetBitmap : Bitmap, IDisposable, IRenderTarget public class RenderTargetBitmap : Bitmap, IDisposable, IRenderTarget
{ {

2
src/Avalonia.Base/Media/Immutable/ImmutableTransform.cs

@ -3,7 +3,7 @@
namespace Avalonia.Media.Immutable namespace Avalonia.Media.Immutable
{ {
/// <summary> /// <summary>
/// Represents a transform on an <see cref="IVisual"/>. /// Represents a transform on an <see cref="Visual"/>.
/// </summary> /// </summary>
public class ImmutableTransform : ITransform public class ImmutableTransform : ITransform
{ {

2
src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media.Immutable namespace Avalonia.Media.Immutable
{ {
/// <summary> /// <summary>
/// Paints an area with an <see cref="IVisual"/>. /// Paints an area with an <see cref="Visual"/>.
/// </summary> /// </summary>
internal class ImmutableVisualBrush : ImmutableTileBrush, IVisualBrush internal class ImmutableVisualBrush : ImmutableTileBrush, IVisualBrush
{ {

6
src/Avalonia.Base/Media/LineSegment.cs

@ -1,3 +1,5 @@
using System;
namespace Avalonia.Media namespace Avalonia.Media
{ {
public sealed class LineSegment : PathSegment public sealed class LineSegment : PathSegment
@ -26,6 +28,6 @@ namespace Avalonia.Media
} }
public override string ToString() public override string ToString()
=> $"L {Point}"; => FormattableString.Invariant($"L {Point}");
} }
} }

2
src/Avalonia.Base/Media/MatrixTransform.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Transforms an <see cref="IVisual"/> according to a <see cref="Matrix"/>. /// Transforms an <see cref="Visual"/> according to a <see cref="Matrix"/>.
/// </summary> /// </summary>
public class MatrixTransform : Transform public class MatrixTransform : Transform
{ {

2
src/Avalonia.Base/Media/PathFigure.cs

@ -126,7 +126,7 @@ namespace Avalonia.Media
} }
public override string ToString() public override string ToString()
=> $"M {StartPoint} {string.Join(" ", _segments ?? Enumerable.Empty<PathSegment>())}{(IsClosed ? "Z" : "")}"; => FormattableString.Invariant($"M {StartPoint} {string.Join(" ", _segments ?? Enumerable.Empty<PathSegment>())}{(IsClosed ? "Z" : "")}");
internal void ApplyTo(StreamGeometryContext ctx) internal void ApplyTo(StreamGeometryContext ctx)
{ {

2
src/Avalonia.Base/Media/PathGeometry.cs

@ -133,7 +133,7 @@ namespace Avalonia.Media
public override string ToString() public override string ToString()
{ {
var figuresString = _figures is not null ? string.Join(" ", _figures) : string.Empty; var figuresString = _figures is not null ? string.Join(" ", _figures) : string.Empty;
return $"{(FillRule != FillRule.EvenOdd ? "F1 " : "")}{figuresString}"; return FormattableString.Invariant($"{(FillRule != FillRule.EvenOdd ? "F1 " : "")}{figuresString}");
} }
} }
} }

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)

6
src/Avalonia.Base/Media/QuadraticBezierSegment .cs

@ -1,3 +1,5 @@
using System;
namespace Avalonia.Media namespace Avalonia.Media
{ {
public sealed class QuadraticBezierSegment : PathSegment public sealed class QuadraticBezierSegment : PathSegment
@ -44,6 +46,6 @@ namespace Avalonia.Media
} }
public override string ToString() public override string ToString()
=> $"Q {Point1} {Point2}"; => FormattableString.Invariant($"Q {Point1} {Point2}");
} }
} }

2
src/Avalonia.Base/Media/RotateTransform.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Rotates an <see cref="IVisual"/>. /// Rotates an <see cref="Visual"/>.
/// </summary> /// </summary>
public class RotateTransform : Transform public class RotateTransform : Transform
{ {

2
src/Avalonia.Base/Media/ScaleTransform.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Scale an <see cref="IVisual"/>. /// Scale an <see cref="Visual"/>.
/// </summary> /// </summary>
public class ScaleTransform : Transform public class ScaleTransform : Transform
{ {

2
src/Avalonia.Base/Media/SkewTransform.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Skews an <see cref="IVisual"/>. /// Skews an <see cref="Visual"/>.
/// </summary> /// </summary>
public class SkewTransform : Transform public class SkewTransform : Transform
{ {

2
src/Avalonia.Base/Media/Transform.cs

@ -7,7 +7,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Represents a transform on an <see cref="IVisual"/>. /// Represents a transform on an <see cref="Visual"/>.
/// </summary> /// </summary>
public abstract class Transform : Animatable, IMutableTransform public abstract class Transform : Animatable, IMutableTransform
{ {

2
src/Avalonia.Base/Media/TranslateTransform.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Translates (moves) an <see cref="IVisual"/>. /// Translates (moves) an <see cref="Visual"/>.
/// </summary> /// </summary>
public class TranslateTransform : Transform public class TranslateTransform : Transform
{ {

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/RelativePoint.cs

@ -199,7 +199,7 @@ namespace Avalonia
{ {
return _unit == RelativeUnit.Absolute ? return _unit == RelativeUnit.Absolute ?
_point.ToString() : _point.ToString() :
string.Format(CultureInfo.InvariantCulture, "{0}%, {1}%", _point.X * 100, _point.Y * 100); string.Format(CultureInfo.InvariantCulture, "{0}%, {1}%", _point.X * 100, _point.Y * 100);
} }
} }
} }

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/Composition/Server/FpsCounter.cs

@ -52,7 +52,7 @@ internal class FpsCounter
_lastFpsUpdate = now; _lastFpsUpdate = now;
} }
var fpsLine = $"Frame #{_totalFrames:00000000} FPS: {_fps:000} " + aux; var fpsLine = FormattableString.Invariant($"Frame #{_totalFrames:00000000} FPS: {_fps:000} ") + aux;
double width = 0; double width = 0;
double height = 0; double height = 0;
foreach (var ch in fpsLine) foreach (var ch in fpsLine)

2
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@ -156,7 +156,7 @@ namespace Avalonia.Rendering.Composition.Server
(Compositor.BatchObjectPool.CurrentUsage + Compositor.BatchObjectPool.CurrentPool) * (Compositor.BatchObjectPool.CurrentUsage + Compositor.BatchObjectPool.CurrentPool) *
Compositor.BatchObjectPool.ArraySize * Compositor.BatchObjectPool.ArraySize *
IntPtr.Size), false); IntPtr.Size), false);
_fpsCounter.RenderFps(targetContext, $"M:{managedMem} / N:{nativeMem} R:{RenderedVisuals:0000}"); _fpsCounter.RenderFps(targetContext, FormattableString.Invariant($"M:{managedMem} / N:{nativeMem} R:{RenderedVisuals:0000}"));
} }
RenderedVisuals = 0; RenderedVisuals = 0;

4
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)
@ -725,7 +725,7 @@ namespace Avalonia.Rendering
foreach (var layer in Layers) foreach (var layer in Layers)
{ {
var fileName = Path.Combine(DebugFramesPath ?? string.Empty, $"frame-{id}-layer-{index++}.png"); var fileName = Path.Combine(DebugFramesPath ?? string.Empty, FormattableString.Invariant($"frame-{id}-layer-{index++}.png"));
layer.Bitmap.Item.Save(fileName); layer.Bitmap.Item.Save(fileName);
} }
} }

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

@ -36,7 +36,7 @@ namespace Avalonia.Rendering
_lastFpsUpdate = now; _lastFpsUpdate = now;
} }
var text = layerCount.HasValue ? $"Layers: {layerCount} FPS: {_fps:000}" : $"FPS: {_fps:000}"; var text = layerCount.HasValue ? FormattableString.Invariant($"Layers: {layerCount} FPS: {_fps:000}") : FormattableString.Invariant($"FPS: {_fps:000}");
var formattedText = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Typeface.Default, s_fontSize, Brushes.White); var formattedText = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Typeface.Default, s_fontSize, Brushes.White);

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/Rendering/SceneGraph/VisualNode.cs

@ -10,7 +10,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
/// <summary> /// <summary>
/// A node in the low-level scene graph representing an <see cref="IVisual"/>. /// A node in the low-level scene graph representing an <see cref="Visual"/>.
/// </summary> /// </summary>
internal class VisualNode : IVisualNode internal class VisualNode : IVisualNode
{ {

2
src/Avalonia.Base/Styling/Activators/IStyleActivator.cs

@ -39,7 +39,7 @@ namespace Avalonia.Styling.Activators
/// </summary> /// </summary>
/// <param name="sink">The listener.</param> /// <param name="sink">The listener.</param>
/// <remarks> /// <remarks>
/// This method should not call <see cref="IStyleActivatorSink.OnNext(bool, int)"/>. /// This method should not call <see cref="IStyleActivatorSink.OnNext(bool)"/>.
/// </remarks> /// </remarks>
void Subscribe(IStyleActivatorSink sink); void Subscribe(IStyleActivatorSink sink);

2
src/Avalonia.Base/Thickness.cs

@ -277,7 +277,7 @@ namespace Avalonia
/// <returns>The string representation of the thickness.</returns> /// <returns>The string representation of the thickness.</returns>
public override string ToString() public override string ToString()
{ {
return $"{_left},{_top},{_right},{_bottom}"; return FormattableString.Invariant($"{_left},{_top},{_right},{_bottom}");
} }
/// <summary> /// <summary>

1
src/Avalonia.Base/Visual.cs

@ -417,6 +417,7 @@ namespace Avalonia
OnAttachedToVisualTree(e); OnAttachedToVisualTree(e);
AttachedToVisualTree?.Invoke(this, e); AttachedToVisualTree?.Invoke(this, e);
InvalidateVisual(); InvalidateVisual();
_visualRoot.Renderer?.RecalculateChildren(_visualParent!);
if (ZIndex != 0 && VisualParent is Visual parent) if (ZIndex != 0 && VisualParent is Visual parent)
parent.HasNonUniformZIndexChildren = true; parent.HasNonUniformZIndexChildren = true;

2
src/Avalonia.Base/VisualTree/TransformedBounds.cs

@ -77,6 +77,6 @@ namespace Avalonia.VisualTree
return !left.Equals(right); return !left.Equals(right);
} }
public override string ToString() => $"Bounds: {Bounds} Clip: {Clip} Transform {Transform}"; public override string ToString() => FormattableString.Invariant($"Bounds: {Bounds} Clip: {Clip} Transform {Transform}");
} }
} }

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
} }

2
src/Avalonia.Build.Tasks/Extensions.cs

@ -5,7 +5,7 @@ namespace Avalonia.Build.Tasks
{ {
static class Extensions static class Extensions
{ {
static string FormatErrorCode(BuildEngineErrorCode code) => $"AVLN:{(int)code:0000}"; static string FormatErrorCode(BuildEngineErrorCode code) => FormattableString.Invariant($"AVLN:{(int)code:0000}");
public static void LogError(this IBuildEngine engine, BuildEngineErrorCode code, string file, Exception ex, public static void LogError(this IBuildEngine engine, BuildEngineErrorCode code, string file, Exception ex,
int lineNumber = 0, int linePosition = 0) int lineNumber = 0, int linePosition = 0)

2
src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs

@ -67,7 +67,7 @@ namespace Avalonia.Build.Tasks
{ {
var src = new Source(r.ItemSpec, Root); var src = new Source(r.ItemSpec, Root);
BuildEngine.LogMessage($"avares -> name:{src.Path}, path: {src.SystemPath}, size:{src.Size}, ItemSpec:{r.ItemSpec}", _reportImportance); BuildEngine.LogMessage(FormattableString.Invariant($"avares -> name:{src.Path}, path: {src.SystemPath}, size:{src.Size}, ItemSpec:{r.ItemSpec}"), _reportImportance);
return src; return src;
}).ToList(); }).ToList();

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");
}
} }
} }

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;

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;
} }

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();
} }

2
src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs

@ -259,7 +259,7 @@ namespace Avalonia.Controls.Primitives
SelectedValue = (int)newSel * Increment + MinimumValue; SelectedValue = (int)newSel * Increment + MinimumValue;
_suppressUpdateOffset = false; _suppressUpdateOffset = false;
System.Diagnostics.Debug.WriteLine($"Offset: {_offset} ItemHeight: {ItemHeight}"); System.Diagnostics.Debug.WriteLine(FormattableString.Invariant($"Offset: {_offset} ItemHeight: {ItemHeight}"));
} }
} }

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));

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)

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;

2
src/Avalonia.Controls/Selection/IndexRange.cs

@ -86,7 +86,7 @@ namespace Avalonia.Controls.Selection
return hashCode; return hashCode;
} }
public override string ToString() => $"[{Begin}..{End}]"; public override string ToString() => FormattableString.Invariant($"[{Begin}..{End}]");
public static bool operator ==(IndexRange left, IndexRange right) => left.Equals(right); public static bool operator ==(IndexRange left, IndexRange right) => left.Equals(right);
public static bool operator !=(IndexRange left, IndexRange right) => !(left == right); public static bool operator !=(IndexRange left, IndexRange right) => !(left == right);

4
src/Avalonia.Controls/Selection/SelectionNodeBase.cs

@ -290,12 +290,12 @@ namespace Avalonia.Controls.Selection
// so bail. // so bail.
// //
// See unit test Handles_Selection_Made_In_CollectionChanged for more details. // See unit test Handles_Selection_Made_In_CollectionChanged for more details.
if (ItemsView is object && if (ItemsView is not null &&
RangesEnabled && RangesEnabled &&
Ranges.Count > 0 && Ranges.Count > 0 &&
e.Action == NotifyCollectionChangedAction.Add) e.Action == NotifyCollectionChangedAction.Add)
{ {
var lastIndex = Ranges.Last().End; var lastIndex = Ranges[Ranges.Count - 1].End;
if (e.NewStartingIndex <= lastIndex) if (e.NewStartingIndex <= lastIndex)
{ {

20
src/Avalonia.Controls/Slider.cs

@ -190,7 +190,7 @@ namespace Avalonia.Controls
_increaseButtonSubscription?.Dispose(); _increaseButtonSubscription?.Dispose();
_increaseButtonReleaseDispose?.Dispose(); _increaseButtonReleaseDispose?.Dispose();
_pointerMovedDispose?.Dispose(); _pointerMovedDispose?.Dispose();
_decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton"); _decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
_track = e.NameScope.Find<Track>("PART_Track"); _track = e.NameScope.Find<Track>("PART_Track");
_increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton"); _increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
@ -258,7 +258,7 @@ namespace Avalonia.Controls
e.Handled = handled; e.Handled = handled;
} }
private void MoveToNextTick(double direction) private void MoveToNextTick(double direction)
{ {
if (direction == 0.0) return; if (direction == 0.0) return;
@ -317,6 +317,12 @@ namespace Avalonia.Controls
private void TrackMoved(object? sender, PointerEventArgs e) private void TrackMoved(object? sender, PointerEventArgs e)
{ {
if (!IsEnabled)
{
_isDragging = false;
return;
}
if (_isDragging) if (_isDragging)
{ {
MoveToPoint(e.GetCurrentPoint(_track)); MoveToPoint(e.GetCurrentPoint(_track));
@ -343,15 +349,15 @@ namespace Avalonia.Controls
return; return;
var orient = Orientation == Orientation.Horizontal; var orient = Orientation == Orientation.Horizontal;
var thumbLength = (orient var thumbLength = (orient
? _track.Thumb.Bounds.Width ? _track.Thumb.Bounds.Width
: _track.Thumb.Bounds.Height) + double.Epsilon; : _track.Thumb.Bounds.Height) + double.Epsilon;
var trackLength = (orient var trackLength = (orient
? _track.Bounds.Width ? _track.Bounds.Width
: _track.Bounds.Height) - thumbLength; : _track.Bounds.Height) - thumbLength;
var trackPos = orient ? posOnTrack.Position.X : posOnTrack.Position.Y; var trackPos = orient ? posOnTrack.Position.X : posOnTrack.Position.Y;
var logicalPos = MathUtilities.Clamp((trackPos - thumbLength * 0.5) / trackLength, 0.0d, 1.0d); var logicalPos = MathUtilities.Clamp((trackPos - thumbLength * 0.5) / trackLength, 0.0d, 1.0d);
var invert = orient ? var invert = orient ?
IsDirectionReversed ? 1 : 0 : IsDirectionReversed ? 1 : 0 :
IsDirectionReversed ? 0 : 1; IsDirectionReversed ? 0 : 1;
var calcVal = Math.Abs(invert - logicalPos); var calcVal = Math.Abs(invert - logicalPos);

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)
{ {

1
src/Avalonia.Controls/UserControl.cs

@ -1,4 +1,3 @@
using System;
using Avalonia.Styling; using Avalonia.Styling;
namespace Avalonia.Controls namespace Avalonia.Controls

2
src/Avalonia.DesignerSupport/Remote/HtmlTransport/HtmlTransport.cs

@ -162,7 +162,7 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
if (sendNow != null && socket != null) if (sendNow != null && socket != null)
{ {
await socket.SendMessage( await socket.SendMessage(
$"frame:{sendNow.SequenceId}:{sendNow.Width}:{sendNow.Height}:{sendNow.Stride}:{sendNow.DpiX}:{sendNow.DpiY}"); FormattableString.Invariant($"frame:{sendNow.SequenceId}:{sendNow.Width}:{sendNow.Height}:{sendNow.Stride}:{sendNow.DpiX}:{sendNow.DpiY}"));
await socket.SendMessage(false, sendNow.Data); await socket.SendMessage(false, sendNow.Data);
} }

2
src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs

@ -146,7 +146,7 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
public async Task RespondAsync(int code, byte[] data, string contentType) public async Task RespondAsync(int code, byte[] data, string contentType)
{ {
var headers = Encoding.UTF8.GetBytes($"HTTP/1.1 {code} {(HttpStatusCode)code}\r\nConnection: close\r\nContent-Type: {contentType}\r\nContent-Length: {data.Length}\r\n\r\n"); var headers = Encoding.UTF8.GetBytes(FormattableString.Invariant($"HTTP/1.1 {code} {(HttpStatusCode)code}\r\nConnection: close\r\nContent-Type: {contentType}\r\nContent-Length: {data.Length}\r\n\r\n"));
await _stream.WriteAsync(headers, 0, headers.Length); await _stream.WriteAsync(headers, 0, headers.Length);
await _stream.WriteAsync(data, 0, data.Length); await _stream.WriteAsync(data, 0, data.Length);
_stream.Dispose(); _stream.Dispose();

2
src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs

@ -47,7 +47,7 @@ namespace Avalonia.Diagnostics.Screenshots
/// </summary> /// </summary>
public string Title { get; } = "Save Screenshot to ..."; public string Title { get; } = "Save Screenshot to ...";
Window GetWindow(Control control) static Window GetWindow(Control control)
{ {
var window = control.VisualRoot as Window; var window = control.VisualRoot as Window;
var app = Application.Current; var app = Application.Current;

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

Loading…
Cancel
Save