From 01c6bf4bb79c006d8998d3994b1c04bc9bb08ed7 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 9 Sep 2022 12:48:43 +0200 Subject: [PATCH 001/137] Add DisplayMemberBinding to ItemsControl --- .../Generators/IItemContainerGenerator.cs | 6 ++++++ .../Generators/ItemContainerGenerator.cs | 13 ++++++++++++- .../Generators/ItemContainerGenerator`1.cs | 12 ++++++++++-- .../Generators/TreeItemContainerGenerator.cs | 10 +++++++++- src/Avalonia.Controls/ItemsControl.cs | 19 +++++++++++++++++++ .../Presenters/ItemsPresenterBase.cs | 17 +++++++++++++++++ 6 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs index f9772cb399..79c77f2519 100644 --- a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.Styling; namespace Avalonia.Controls.Generators @@ -24,6 +25,11 @@ namespace Avalonia.Controls.Generators /// Gets or sets the data template used to display the items in the control. /// IDataTemplate? ItemTemplate { get; set; } + + /// + /// Gets or sets the binding to use to bind to the member of an item used for displaying + /// + IBinding? DisplayMemberBinding { get; set; } /// /// Gets the ContainerType, or null if its an untyped ContainerGenerator. diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs index 8b36b07cec..42f0124295 100644 --- a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs @@ -45,6 +45,9 @@ namespace Avalonia.Controls.Generators /// Gets or sets the data template used to display the items in the control. /// public IDataTemplate? ItemTemplate { get; set; } + + /// + public IBinding? DisplayMemberBinding { get; set; } /// /// Gets the owner control. @@ -189,7 +192,15 @@ namespace Avalonia.Controls.Generators if (result == null) { result = new ContentPresenter(); - result.SetValue(ContentPresenter.ContentProperty, item, BindingPriority.Style); + if (DisplayMemberBinding is not null) + { + result.SetValue(StyledElement.DataContextProperty, item, BindingPriority.Style); + result.Bind(ContentPresenter.ContentProperty, DisplayMemberBinding, BindingPriority.Style); + } + else + { + result.SetValue(ContentPresenter.ContentProperty, item, BindingPriority.Style); + } if (ItemTemplate != null) { diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs index 3ff1b0702d..5e965a9d04 100644 --- a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs +++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs @@ -53,8 +53,16 @@ namespace Avalonia.Controls.Generators container.SetValue(ContentTemplateProperty, ItemTemplate, BindingPriority.Style); } - container.SetValue(ContentProperty, item, BindingPriority.Style); - + if (DisplayMemberBinding is not null) + { + container.SetValue(StyledElement.DataContextProperty, item, BindingPriority.Style); + container.Bind(ContentProperty, DisplayMemberBinding, BindingPriority.Style); + } + else + { + container.SetValue(ContentProperty, item, BindingPriority.Style); + } + if (!(item is IControl)) { container.DataContext = item; diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs index 4e3deb5552..9f9845b14f 100644 --- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs @@ -76,7 +76,15 @@ namespace Avalonia.Controls.Generators result.SetValue(Control.ThemeProperty, ItemContainerTheme, BindingPriority.Style); } - result.SetValue(ContentProperty, template.Build(item), BindingPriority.Style); + if (DisplayMemberBinding is not null) + { + result.SetValue(StyledElement.DataContextProperty, item, BindingPriority.Style); + result.Bind(ContentProperty, DisplayMemberBinding, BindingPriority.Style); + } + else + { + result.SetValue(ContentProperty, item, BindingPriority.Style); + } var itemsSelector = template.ItemsSelector(item); diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 345e7fcac8..e9ce7912a7 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -11,6 +11,7 @@ using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Controls.Utils; +using Avalonia.Data; using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Metadata; @@ -61,6 +62,23 @@ namespace Avalonia.Controls public static readonly StyledProperty ItemTemplateProperty = AvaloniaProperty.Register(nameof(ItemTemplate)); + + /// + /// Defines the property + /// + public static readonly StyledProperty DisplayMemberBindingProperty = + AvaloniaProperty.Register(nameof(DisplayMemberBinding)); + + /// + /// Gets or sets the to use for binding to the display member of each item. + /// + [AssignBinding] + public IBinding? DisplayMemberBinding + { + get { return GetValue(DisplayMemberBindingProperty); } + set { SetValue(DisplayMemberBindingProperty, value); } + } + private IEnumerable? _items = new AvaloniaList(); private int _itemCount; private IItemContainerGenerator? _itemContainerGenerator; @@ -97,6 +115,7 @@ namespace Avalonia.Controls _itemContainerGenerator.ItemContainerTheme = ItemContainerTheme; _itemContainerGenerator.ItemTemplate = ItemTemplate; + _itemContainerGenerator.DisplayMemberBinding = DisplayMemberBinding; _itemContainerGenerator.Materialized += (_, e) => OnContainersMaterialized(e); _itemContainerGenerator.Dematerialized += (_, e) => OnContainersDematerialized(e); _itemContainerGenerator.Recycled += (_, e) => OnContainersRecycled(e); diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs index 2821fa8cf0..836433cdf8 100644 --- a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs +++ b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs @@ -5,6 +5,7 @@ using Avalonia.Collections; using Avalonia.Controls.Generators; using Avalonia.Controls.Templates; using Avalonia.Controls.Utils; +using Avalonia.Data; using Avalonia.LogicalTree; using Avalonia.Styling; @@ -33,6 +34,12 @@ namespace Avalonia.Controls.Presenters public static readonly StyledProperty ItemTemplateProperty = ItemsControl.ItemTemplateProperty.AddOwner(); + /// + /// Defines the property + /// + public static readonly StyledProperty DisplayMemberBindingProperty = + ItemsControl.DisplayMemberBindingProperty.AddOwner(); + private IEnumerable? _items; private IDisposable? _itemsSubscription; private bool _createdPanel; @@ -120,6 +127,15 @@ namespace Avalonia.Controls.Presenters set { SetValue(ItemTemplateProperty, value); } } + /// + /// Gets or sets the to use for binding to the display member of each item. + /// + public IBinding? DisplayMemberBinding + { + get { return GetValue(DisplayMemberBindingProperty); } + set { SetValue(DisplayMemberBindingProperty, value); } + } + /// /// Gets the panel used to display the items. /// @@ -177,6 +193,7 @@ namespace Avalonia.Controls.Presenters { result = new ItemContainerGenerator(this); result.ItemTemplate = ItemTemplate; + result.DisplayMemberBinding = DisplayMemberBinding; } result.Materialized += ContainerActionHandler; From 30e46518693d4bb2e14ddede6b2c00448cd0fc31 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 19 Sep 2022 13:48:26 +0200 Subject: [PATCH 002/137] Add TabItem HeaderDisplayMemberBinding --- .../Generators/TabItemContainerGenerator.cs | 7 +++++++ src/Avalonia.Controls/TabControl.cs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs index c6b0bda9af..4021b8436a 100644 --- a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.LogicalTree; using Avalonia.Reactive; using Avalonia.VisualTree; @@ -33,6 +34,12 @@ namespace Avalonia.Controls.Generators TabControl.ItemTemplateProperty)); } + if (Owner.HeaderDisplayMemberBinding is not null) + { + tabItem.Bind(HeaderedContentControl.HeaderProperty, Owner.HeaderDisplayMemberBinding, + BindingPriority.Style); + } + if (tabItem.Header == null) { if (item is IHeadered headered) diff --git a/src/Avalonia.Controls/TabControl.cs b/src/Avalonia.Controls/TabControl.cs index 70fecc7ce1..63738716c0 100644 --- a/src/Avalonia.Controls/TabControl.cs +++ b/src/Avalonia.Controls/TabControl.cs @@ -12,6 +12,7 @@ using Avalonia.LogicalTree; using Avalonia.VisualTree; using Avalonia.Automation; using Avalonia.Controls.Metadata; +using Avalonia.Data; namespace Avalonia.Controls { @@ -57,6 +58,12 @@ namespace Avalonia.Controls public static readonly StyledProperty SelectedContentTemplateProperty = AvaloniaProperty.Register(nameof(SelectedContentTemplate)); + /// + /// Defines the property + /// + public static readonly StyledProperty HeaderDisplayMemberBindingProperty = + AvaloniaProperty.Register(nameof(HeaderDisplayMemberBinding)); + /// /// The default value for the property. /// @@ -134,6 +141,16 @@ namespace Avalonia.Controls get { return GetValue(SelectedContentTemplateProperty); } internal set { SetValue(SelectedContentTemplateProperty, value); } } + + /// + /// Gets or sets the to use for binding to the display member of each tab-items header. + /// + [AssignBinding] + public IBinding? HeaderDisplayMemberBinding + { + get { return GetValue(HeaderDisplayMemberBindingProperty); } + set { SetValue(HeaderDisplayMemberBindingProperty, value); } + } internal ItemsPresenter? ItemsPresenterPart { get; private set; } From dcebd4f5ab8a496b7f2a91490806f676241e6fd7 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 19 Sep 2022 13:49:22 +0200 Subject: [PATCH 003/137] Update TabControl-Demo to use the new added HeaderDisplayMemberBinding --- samples/ControlCatalog/Pages/TabControlPage.xaml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/samples/ControlCatalog/Pages/TabControlPage.xaml b/samples/ControlCatalog/Pages/TabControlPage.xaml index cba6fcd0ad..90afb5ceca 100644 --- a/samples/ControlCatalog/Pages/TabControlPage.xaml +++ b/samples/ControlCatalog/Pages/TabControlPage.xaml @@ -51,15 +51,9 @@ - - - - - - - + From ab4bb208f56eee4a06dd052eece7afa642e5753f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 22 Sep 2022 14:31:02 +0200 Subject: [PATCH 004/137] Add Unit Test --- .../ItemsControlTests.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs index f08653a4f8..944f974cb0 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs @@ -4,6 +4,7 @@ using System.Linq; using Avalonia.Collections; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Styling; @@ -736,6 +737,25 @@ namespace Avalonia.Controls.UnitTests root.Child = null; root.Child = target; } + + [Fact] + public void Should_Use_DisplayMemberBinding() + { + var target = new ItemsControl + { + Template = GetTemplate(), + DisplayMemberBinding = new Binding("Length") + }; + + target.Items = new[] { "Foo" }; + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + var container = (ContentPresenter)target.Presenter.Panel.Children[0]; + container.UpdateChild(); + + Assert.Equal(container.Child!.GetValue(TextBlock.TextProperty), "3"); + } private class Item { From 42e27d89508a5a523f24c1eb1f2f272154b6a374 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 7 Oct 2022 15:40:23 +0200 Subject: [PATCH 005/137] Fix Tests --- src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs index 9f9845b14f..2d8cb05e03 100644 --- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs @@ -83,7 +83,7 @@ namespace Avalonia.Controls.Generators } else { - result.SetValue(ContentProperty, item, BindingPriority.Style); + result.SetValue(ContentProperty, template.Build(item), BindingPriority.Style); } var itemsSelector = template.ItemsSelector(item); From 2a2add7d4dbb54c271296f17a545d28d3f829cf6 Mon Sep 17 00:00:00 2001 From: Tim <47110241+timunie@users.noreply.github.com> Date: Mon, 10 Oct 2022 14:59:39 +0200 Subject: [PATCH 006/137] Update ListBoxPage: - Added ItemModel - Enable CompiledBindings - Use DisplayMemberBinding --- samples/ControlCatalog/Pages/ListBoxPage.xaml | 4 +++ .../ViewModels/ListBoxPageViewModel.cs | 36 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml index 433592345a..067d4d9890 100644 --- a/samples/ControlCatalog/Pages/ListBoxPage.xaml +++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml @@ -1,5 +1,8 @@ @@ -30,6 +33,7 @@ diff --git a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs index 59489ebcc0..f89d9d1e20 100644 --- a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reactive; using Avalonia.Controls; using Avalonia.Controls.Selection; +using ControlCatalog.Pages; using MiniMvvm; namespace ControlCatalog.ViewModels @@ -20,9 +21,9 @@ namespace ControlCatalog.ViewModels public ListBoxPageViewModel() { - Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem())); + Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem())); - Selection = new SelectionModel(); + Selection = new SelectionModel(); Selection.Select(1); _selectionMode = this.WhenAnyValue( @@ -58,8 +59,8 @@ namespace ControlCatalog.ViewModels }); } - public ObservableCollection Items { get; } - public SelectionModel Selection { get; } + public ObservableCollection Items { get; } + public SelectionModel Selection { get; } public IObservable SelectionMode => _selectionMode; public bool Multiple @@ -96,6 +97,31 @@ namespace ControlCatalog.ViewModels public MiniCommand RemoveItemCommand { get; } public MiniCommand SelectRandomItemCommand { get; } - private string GenerateItem() => $"Item {_counter++.ToString()}"; + private ItemModel GenerateItem() => new ItemModel(_counter ++); + } + + /// + /// An Item model for the + /// + public class ItemModel + { + /// + /// Creates a new ItemModel with the given ID + /// + /// The ID to display + public ItemModel(int id) + { + ID = id; + } + + /// + /// The ID of this Item + /// + public int ID { get; } + + public override string ToString() + { + return $"Item {ID}"; + } } } From f47f71c08da60c2294eb5467f42b47d6ac6563a8 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 14 Oct 2022 03:41:06 -0400 Subject: [PATCH 007/137] Remove AlternatingRowBackground from the API --- .../ControlCatalog/Pages/DataGridPage.xaml | 3 +-- src/Avalonia.Controls.DataGrid/DataGrid.cs | 25 +++---------------- .../Themes/Fluent.xaml | 7 +----- .../Themes/Simple.xaml | 5 ---- 4 files changed, 6 insertions(+), 34 deletions(-) diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml index 27272a9ff7..bc8252a3a4 100644 --- a/samples/ControlCatalog/Pages/DataGridPage.xaml +++ b/samples/ControlCatalog/Pages/DataGridPage.xaml @@ -45,8 +45,7 @@ + RowBackground="#1000"> diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index c6cc9bf278..c23bca1810 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -246,23 +246,6 @@ namespace Avalonia.Controls set { SetValue(ColumnWidthProperty, value); } } - public static readonly StyledProperty AlternatingRowBackgroundProperty = - AvaloniaProperty.Register(nameof(AlternatingRowBackground)); - - /// - /// Gets or sets the that is used to paint the background of odd-numbered rows. - /// - /// - /// The brush that is used to paint the background of odd-numbered rows. The default is a - /// with a - /// value of white (ARGB value #00FFFFFF). - /// - public IBrush AlternatingRowBackground - { - get { return GetValue(AlternatingRowBackgroundProperty); } - set { SetValue(AlternatingRowBackgroundProperty, value); } - } - public static readonly StyledProperty FrozenColumnCountProperty = AvaloniaProperty.Register( nameof(FrozenColumnCount), @@ -2058,7 +2041,7 @@ namespace Avalonia.Controls forceHorizontalScroll: true); } } - + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); @@ -2167,7 +2150,7 @@ namespace Avalonia.Controls return desiredSize; } - + /// protected override void OnDataContextBeginUpdate() { @@ -2183,7 +2166,7 @@ namespace Avalonia.Controls NotifyDataContextPropertyForAllRowCells(GetAllRows(), false); } - + /// /// Raises the BeginningEdit event. /// @@ -4575,7 +4558,7 @@ namespace Avalonia.Controls dataGridCell.Content = element; } - + } private void PreparingCellForEditPrivate(Control editingElement) diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml index b4bae02b9b..3019e3d158 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml @@ -232,7 +232,7 @@ - + @@ -337,10 +337,6 @@ - - - - - - - A control for displaying and interacting with a data source. @@ -58,6 +42,24 @@ MinWidth="200" IsVisible="{Binding #ShowGDP.IsChecked}"/> + + + + + + + + + + + + + + @@ -70,6 +72,20 @@ + + + + + + + + diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index c23bca1810..a9f2e889b9 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -26,6 +26,7 @@ using Avalonia.Controls.Utils; using Avalonia.Layout; using Avalonia.Controls.Metadata; using Avalonia.Input.GestureRecognizers; +using Avalonia.Styling; namespace Avalonia.Controls { @@ -237,6 +238,66 @@ namespace Avalonia.Controls public static readonly StyledProperty ColumnWidthProperty = AvaloniaProperty.Register(nameof(ColumnWidth), defaultValue: DataGridLength.Auto); + /// + /// Identifies the dependency property. + /// + public static readonly StyledProperty RowThemeProperty = + AvaloniaProperty.Register(nameof(RowTheme)); + + /// + /// Gets or sets the theme applied to all rows. + /// + public ControlTheme RowTheme + { + get { return GetValue(RowThemeProperty); } + set { SetValue(RowThemeProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly StyledProperty CellThemeProperty = + AvaloniaProperty.Register(nameof(CellTheme)); + + /// + /// Gets or sets the theme applied to all cells. + /// + public ControlTheme CellTheme + { + get { return GetValue(CellThemeProperty); } + set { SetValue(CellThemeProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly StyledProperty ColumnHeaderThemeProperty = + AvaloniaProperty.Register(nameof(ColumnHeaderTheme)); + + /// + /// Gets or sets the theme applied to all column headers. + /// + public ControlTheme ColumnHeaderTheme + { + get { return GetValue(ColumnHeaderThemeProperty); } + set { SetValue(ColumnHeaderThemeProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly StyledProperty RowGroupThemeProperty = + AvaloniaProperty.Register(nameof(RowGroupTheme)); + + /// + /// Gets or sets the theme applied to all row groups. + /// + public ControlTheme RowGroupTheme + { + get { return GetValue(RowGroupThemeProperty); } + set { SetValue(RowGroupThemeProperty, value); } + } + /// /// Gets or sets the standard width or automatic sizing mode of columns in the control. /// @@ -3225,7 +3286,6 @@ namespace Avalonia.Controls } } - //TODO Styles private void AddNewCellPrivate(DataGridRow row, DataGridColumn column) { DataGridCell newCell = new DataGridCell(); @@ -3238,8 +3298,11 @@ namespace Avalonia.Controls { newCell.OwningColumn = column; newCell.IsVisible = column.IsVisible; + if (row.OwningGrid.CellTheme is {} cellTheme) + { + newCell.SetValue(ThemeProperty, cellTheme, BindingPriority.TemplatedParent); + } } - //newCell.EnsureStyle(null); row.Cells.Insert(column.Index, newCell); } @@ -4520,7 +4583,6 @@ namespace Avalonia.Controls FlushCurrentCellChanged(); } - //TODO Styles private void PopulateCellContent(bool isCellEdited, DataGridColumn dataGridColumn, DataGridRow dataGridRow, diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs index fbdb979e24..191c3fc5b1 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs @@ -231,7 +231,7 @@ namespace Avalonia.Controls } /// - /// Gets or sets a value that indicates whether the user can change the column display position by + /// Gets or sets a value that indicates whether the user can change the column display position by /// dragging the column header. /// /// @@ -260,15 +260,15 @@ namespace Avalonia.Controls /// public bool CanUserResize { - get + get { return CanUserResizeInternal ?? OwningGrid?.CanUserResizeColumns ?? DataGrid.DATAGRID_defaultCanUserResizeColumns; } - set - { + set + { CanUserResizeInternal = value; OwningGrid?.OnColumnCanUserResizeChanged(this); } @@ -321,16 +321,16 @@ namespace Avalonia.Controls /// /// /// When setting this property, the specified value is less than -1 or equal to . - /// + /// /// -or- - /// + /// /// When setting this property on a column in a , the specified value is less than zero or greater than or equal to the number of columns in the . /// /// /// When setting this property, the is already making adjustments. For example, this exception is thrown when you attempt to set in a event handler. - /// + /// /// -or- - /// + /// /// When setting this property, the specified value would result in a frozen column being displayed in the range of unfrozen columns, or an unfrozen column being displayed in the range of frozen columns. /// public int DisplayIndex @@ -401,7 +401,7 @@ namespace Avalonia.Controls } } } - + /// /// Backing field for CellTheme property. /// @@ -412,7 +412,7 @@ namespace Avalonia.Controls (o, v) => o.CellTheme = v); /// - /// Gets or sets the cell theme. + /// Gets or sets the cell theme. /// public ControlTheme CellTheme { @@ -430,14 +430,14 @@ namespace Avalonia.Controls (o, v) => o.Header = v); /// - /// Gets or sets the content + /// Gets or sets the content /// public object Header { get { return _header; } set { SetAndRaise(HeaderProperty, ref _header, value); } } - + /// /// Backing field for Header property /// @@ -455,7 +455,7 @@ namespace Avalonia.Controls get { return _headerTemplate; } set { SetAndRaise(HeaderTemplateProperty, ref _headerTemplate, value); } } - + public bool IsAutoGenerated { get; @@ -750,7 +750,7 @@ namespace Avalonia.Controls protected abstract IControl GenerateEditingElement(DataGridCell cell, object dataItem, out ICellEditBinding binding); /// - /// When overridden in a derived class, gets a read-only element that is bound to the column's + /// When overridden in a derived class, gets a read-only element that is bound to the column's /// property value. /// /// @@ -765,7 +765,7 @@ namespace Avalonia.Controls protected abstract IControl GenerateElement(DataGridCell cell, object dataItem); /// - /// Called by a specific column type when one of its properties changed, + /// Called by a specific column type when one of its properties changed, /// and its current cells need to be updated. /// /// Indicates which property changed and caused this call @@ -882,9 +882,8 @@ namespace Avalonia.Controls { LayoutRoundedWidth = ActualWidth; } - } + } - //TODO Styles internal virtual DataGridColumnHeader CreateHeader() { var result = new DataGridColumnHeader @@ -893,8 +892,10 @@ namespace Avalonia.Controls }; result[!ContentControl.ContentProperty] = this[!HeaderProperty]; result[!ContentControl.ContentTemplateProperty] = this[!HeaderTemplateProperty]; - - //result.EnsureStyle(null); + if (OwningGrid.ColumnHeaderTheme is {} columnTheme) + { + result.SetValue(StyledElement.ThemeProperty, columnTheme, BindingPriority.TemplatedParent); + } return result; } diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs index d3bd968d62..740e3516f6 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs @@ -76,7 +76,7 @@ namespace Avalonia.Controls } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// //TODO Implement public DataGridColumnHeader() @@ -267,7 +267,7 @@ namespace Avalonia.Controls else { newSort = sort; - } + } // changing direction should not affect sort order, so we replace this column's // sort description instead of just adding it to the end of the collection @@ -603,7 +603,7 @@ namespace Avalonia.Controls } /// - /// Returns true if the mouse is + /// Returns true if the mouse is /// - to the left of the element, or within the left half of the element /// and /// - within the vertical range of the element, or ignoreVertical == true @@ -663,16 +663,19 @@ namespace Avalonia.Controls IsMouseOver = false; } - //TODO Styles DragIndicator private void OnMouseMove_BeginReorder(Point mousePosition) { - DataGridColumnHeader dragIndicator = new DataGridColumnHeader + var dragIndicator = new DataGridColumnHeader { OwningColumn = OwningColumn, IsEnabled = false, Content = Content, ContentTemplate = ContentTemplate }; + if (OwningGrid.ColumnHeaderTheme is {} columnHeaderTheme) + { + dragIndicator.SetValue(ThemeProperty, columnHeaderTheme, BindingPriority.TemplatedParent); + } dragIndicator.PseudoClasses.Add(":dragIndicator"); @@ -720,7 +723,7 @@ namespace Avalonia.Controls { return; } - + //handle entry into reorder mode if (_dragMode == DragMode.MouseDown && _dragColumn == null && _lastMousePositionHeaders != null && (distanceFromRight > DATAGRIDCOLUMNHEADER_resizeRegionWidth && distanceFromLeft > DATAGRIDCOLUMNHEADER_resizeRegionWidth)) { diff --git a/src/Avalonia.Controls.DataGrid/DataGridRow.cs b/src/Avalonia.Controls.DataGrid/DataGridRow.cs index 1559763a1b..cd22934ac0 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridRow.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridRow.cs @@ -89,7 +89,7 @@ namespace Avalonia.Controls o => o.IsValid); /// - /// Gets a value that indicates whether the data in a row is valid. + /// Gets a value that indicates whether the data in a row is valid. /// public bool IsValid { @@ -130,7 +130,7 @@ namespace Avalonia.Controls } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public DataGridRow() { @@ -240,7 +240,6 @@ namespace Avalonia.Controls private set; } - //TODO Styles internal DataGridCell FillerCell { get @@ -252,7 +251,10 @@ namespace Avalonia.Controls IsVisible = false, OwningRow = this }; - //_fillerCell.EnsureStyle(null); + if (OwningGrid.CellTheme is {} cellTheme) + { + _fillerCell.SetValue(ThemeProperty, cellTheme, BindingPriority.TemplatedParent); + } if (_cellsElement != null) { _cellsElement.Children.Add(_fillerCell); @@ -506,7 +508,7 @@ namespace Avalonia.Controls } /// - /// Measures the children of a to + /// Measures the children of a to /// prepare for arranging them during the pass. /// /// @@ -709,8 +711,6 @@ namespace Avalonia.Controls } } - // Set the proper style for the Header by walking up the Style hierarchy - //TODO Styles internal void EnsureHeaderStyleAndVisibility(Styling.Style previousStyle) { if (_headerElement != null && OwningGrid != null) @@ -785,7 +785,7 @@ namespace Avalonia.Controls OwningGrid?.OnRowDetailsChanged(); } - // Returns the actual template that should be sued for Details: either explicity set on this row + // Returns the actual template that should be sued for Details: either explicity set on this row // or inherited from the DataGrid private IDataTemplate ActualDetailsTemplate { @@ -890,7 +890,7 @@ namespace Avalonia.Controls //TODO Cleanup double? _previousDetailsHeight = null; - //TODO Animation + //TODO Animation private void DetailsContent_HeightChanged(double newValue) { if (_previousDetailsHeight.HasValue) @@ -907,7 +907,7 @@ namespace Avalonia.Controls _detailsElement.ContentHeight = newValue; - // Calling this when details are not visible invalidates during layout when we have no work + // Calling this when details are not visible invalidates during layout when we have no work // to do. In certain scenarios, this could cause a layout cycle OnRowDetailsChanged(); } @@ -1060,7 +1060,7 @@ namespace Avalonia.Controls } } } - + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { @@ -1084,7 +1084,4 @@ namespace Avalonia.Controls } } - - //TODO Styles - } diff --git a/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs index 69e6766bfd..c746b19cc7 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs @@ -53,7 +53,7 @@ namespace Avalonia.Controls AvaloniaProperty.Register(nameof(PropertyName)); /// - /// Gets or sets the name of the property that this row is bound to. + /// Gets or sets the name of the property that this row is bound to. /// public string PropertyName { @@ -85,8 +85,8 @@ namespace Avalonia.Controls } /// - /// Gets or sets a value that indicates the amount that the - /// children of the are indented. + /// Gets or sets a value that indicates the amount that the + /// children of the are indented. /// public double SublevelIndent { @@ -327,9 +327,9 @@ namespace Avalonia.Controls { double xClip = Math.Round(frozenLeftEdge - childLeftEdge); var rg = new RectangleGeometry(); - rg.Rect = - new Rect(xClip, 0, - Math.Max(0, child.Bounds.Width - xClip), + rg.Rect = + new Rect(xClip, 0, + Math.Max(0, child.Bounds.Width - xClip), child.Bounds.Height); child.Clip = rg; } @@ -348,8 +348,6 @@ namespace Avalonia.Controls } } - //TODO Styles - //internal void EnsureHeaderStyleAndVisibility(Style previousStyle) internal void EnsureHeaderVisibility() { if (_headerElement != null && OwningGrid != null) diff --git a/src/Avalonia.Controls.DataGrid/DataGridRows.cs b/src/Avalonia.Controls.DataGrid/DataGridRows.cs index f3afe2c42d..17a7eab2e0 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridRows.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridRows.cs @@ -14,6 +14,9 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Linq; +using Avalonia.Data; +using Avalonia.Styling; +using JetBrains.Annotations; namespace Avalonia.Controls { @@ -117,7 +120,7 @@ namespace Avalonia.Controls detailsCount += GetDetailsCountInclusive(DisplayData.LastScrollingSlot + 1, SlotCount - 1); } - // + // double totalDetailsHeight = detailsCount * RowDetailsHeightEstimate; return totalRowsHeight + totalDetailsHeight; @@ -163,7 +166,7 @@ namespace Avalonia.Controls } /// - /// Clears the entire selection except the indicated row. Displayed rows are deselected explicitly to + /// Clears the entire selection except the indicated row. Displayed rows are deselected explicitly to /// visualize potential transition effects. The row indicated is selected if it is not already. /// internal void ClearRowSelection(int slotException, bool setAnchorSlot) @@ -270,10 +273,10 @@ namespace Avalonia.Controls bool isRow = rowIndex != -1; if (isCollapsed) { - InsertElement(slot, - element: null, + InsertElement(slot, + element: null, updateVerticalScrollBarOnly: true, - isCollapsed: true, + isCollapsed: true, isRow: isRow); } else if (SlotIsDisplayed(slot)) @@ -285,18 +288,18 @@ namespace Avalonia.Controls } else { - InsertElement(slot, GenerateRowGroupHeader(slot, groupInfo), + InsertElement(slot, GenerateRowGroupHeader(slot, groupInfo), updateVerticalScrollBarOnly: false, - isCollapsed: false, + isCollapsed: false, isRow: isRow); } } else { - InsertElement(slot, + InsertElement(slot, element: null, updateVerticalScrollBarOnly: _vScrollBar == null || _vScrollBar.IsVisible, - isCollapsed: false, + isCollapsed: false, isRow: isRow); } } @@ -417,7 +420,7 @@ namespace Avalonia.Controls if (scrolledHorizontally && DisplayData.FirstScrollingSlot <= slot && DisplayData.LastScrollingSlot >= slot) { // If the slot is displayed and we scrolled horizontally, column virtualization could cause the rows to grow. - // As a result we need to force measure on the rows we're displaying and recalculate our First and Last slots + // As a result we need to force measure on the rows we're displaying and recalculate our First and Last slots // so they're accurate foreach (DataGridRow row in DisplayData.GetScrollingRows()) { @@ -455,7 +458,7 @@ namespace Avalonia.Controls deltaY -= GetSlotElementsHeight(slot, firstFullSlot); if (DisplayData.FirstScrollingSlot - slot > 1) { - // + // ResetDisplayedRows(); } @@ -519,7 +522,7 @@ namespace Avalonia.Controls _verticalOffset = NegVerticalOffset; } - // + // Debug.Assert(MathUtilities.LessThanOrClose(NegVerticalOffset, _verticalOffset)); SetVerticalOffset(_verticalOffset); @@ -1025,6 +1028,10 @@ namespace Avalonia.Controls dataGridRow.Slot = slot; dataGridRow.OwningGrid = this; dataGridRow.DataContext = dataContext; + if (RowTheme is {} rowTheme) + { + dataGridRow.SetValue(ThemeProperty, rowTheme, BindingPriority.TemplatedParent); + } CompleteCellsCollection(dataGridRow); OnLoadingRow(new DataGridRowEventArgs(dataGridRow)); @@ -1104,7 +1111,7 @@ namespace Avalonia.Controls /// /// Checks if the row for the provided dataContext has been generated and is present - /// in either the loaded rows, pre-fetched rows, or editing row. + /// in either the loaded rows, pre-fetched rows, or editing row. /// The displayed rows are *not* searched. Returns null if the row does not belong to those 3 categories. /// private DataGridRow GetGeneratedRow(object dataContext) @@ -1152,8 +1159,8 @@ namespace Avalonia.Controls } else { - // If we're grouping, the GroupLevel needs to be fixed later by methods calling this - // which end up inserting rows. We don't do it here because elements could be inserted + // If we're grouping, the GroupLevel needs to be fixed later by methods calling this + // which end up inserting rows. We don't do it here because elements could be inserted // from top to bottom or bottom to up so it's better to do in one pass slotElement = GenerateRow(RowIndexFromSlot(slot), slot); } @@ -1161,7 +1168,6 @@ namespace Avalonia.Controls return slotElement; } - //TODO Styles private void InsertDisplayedElement(int slot, Control element, bool wasNewlyAdded, bool updateSlotInformation) { // We can only support creating new rows that are adjacent to the currently visible rows @@ -1479,7 +1485,6 @@ namespace Avalonia.Controls } } - //TODO Styles // Makes sure the row shows the proper visuals for selection, currency, details, etc. private void LoadRowVisualsForDisplay(DataGridRow row) { @@ -1694,7 +1699,7 @@ namespace Avalonia.Controls { // Figure out what row we've scrolled down to and update the value for NegVerticalOffset NegVerticalOffset = 0; - // + // if (height > 2 * CellsHeight && (RowDetailsVisibilityMode != DataGridRowDetailsVisibilityMode.VisibleWhenSelected || RowDetailsTemplate == null)) { @@ -1755,7 +1760,7 @@ namespace Avalonia.Controls // Figure out what row we've scrolled up to and update the value for NegVerticalOffset deltaY = -NegVerticalOffset; NegVerticalOffset = 0; - // + // if (height < -2 * CellsHeight && (RowDetailsVisibilityMode != DataGridRowDetailsVisibilityMode.VisibleWhenSelected || RowDetailsTemplate == null)) @@ -1813,7 +1818,7 @@ namespace Avalonia.Controls if (MathUtilities.GreaterThanOrClose(0, newVerticalOffset) && newFirstScrollingSlot != 0) { // We've scrolled to the top of the ScrollBar, automatically place the user at the very top - // of the DataGrid. If this produces very odd behavior, evaluate the RowHeight estimate. + // of the DataGrid. If this produces very odd behavior, evaluate the RowHeight estimate. // strategy. For most data, this should be unnoticeable. ResetDisplayedRows(); NegVerticalOffset = 0; @@ -1994,7 +1999,6 @@ namespace Avalonia.Controls VisibleSlotCount = 0; } - //TODO Styles private void UnloadRow(DataGridRow dataGridRow) { Debug.Assert(dataGridRow != null); @@ -2010,16 +2014,13 @@ namespace Avalonia.Controls OnUnloadingRow(new DataGridRowEventArgs(dataGridRow)); bool recycleRow = CurrentSlot != dataGridRow.Index; - // Don't recycle if the row has a custom Style set - //recycleRow &= (dataGridRow.Style == null || dataGridRow.Style == RowStyle); - if (recycleRow) { DisplayData.AddRecyclableRow(dataGridRow); } else { - // + // _rowsPresenter.Children.Remove(dataGridRow); dataGridRow.DetachFromDataGrid(false); } @@ -2240,10 +2241,10 @@ namespace Avalonia.Controls group.Items.CollectionChanged += CollectionViewGroup_CollectionChanged; } var newGroupInfo = new DataGridRowGroupInfo(group, true, parentGroupInfo.Level + 1, insertSlot, insertSlot); - InsertElementAt(insertSlot, - rowIndex: -1, - item: null, - groupInfo: newGroupInfo, + InsertElementAt(insertSlot, + rowIndex: -1, + item: null, + groupInfo: newGroupInfo, isCollapsed: isCollapsed); RowGroupHeadersTable.AddValue(insertSlot, newGroupInfo); } @@ -2256,9 +2257,9 @@ namespace Avalonia.Controls { AutoGenerateColumnsPrivate(); } - InsertElementAt(insertSlot, rowIndex, + InsertElementAt(insertSlot, rowIndex, item: e.NewItems[0], - groupInfo: null, + groupInfo: null, isCollapsed: isCollapsed); } @@ -2448,13 +2449,12 @@ namespace Avalonia.Controls VisibleSlotCount = SlotCount; } - //TODO Styles private void RefreshRowGroupHeaders() { if (DataConnection.CollectionView != null && DataConnection.CollectionView.CanGroup && DataConnection.CollectionView.Groups != null - && DataConnection.CollectionView.IsGrouping + && DataConnection.CollectionView.IsGrouping && DataConnection.CollectionView.GroupingDepth > 0) { // Initialize our array for the height of the RowGroupHeaders by Level. @@ -2476,7 +2476,7 @@ namespace Avalonia.Controls double indent; for (int i = 0; i < groupLevelCount; i++) { - indent = DATAGRID_defaultRowGroupSublevelIndent; + indent = DATAGRID_defaultRowGroupSublevelIndent; RowGroupSublevelIndents[i] = indent; if (i > 0) { @@ -2742,6 +2742,10 @@ namespace Avalonia.Controls groupHeader.RowGroupInfo = rowGroupInfo; groupHeader.DataContext = rowGroupInfo.CollectionViewGroup; groupHeader.Level = rowGroupInfo.Level; + if (RowGroupTheme is {} rowGroupTheme) + { + groupHeader.SetValue(ThemeProperty, rowGroupTheme, BindingPriority.TemplatedParent); + } // Set the RowGroupHeader's PropertyName. Unfortunately, CollectionViewGroup doesn't have this // so we have to set it manually From cc93b6cb861e96075620e1067184ee2657ab47b2 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 15:37:53 +0200 Subject: [PATCH 009/137] feat: Enable rule CA1822 --- .editorconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.editorconfig b/.editorconfig index 337760636b..bcc1b4e011 100644 --- a/.editorconfig +++ b/.editorconfig @@ -141,6 +141,8 @@ dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomme dotnet_diagnostic.CA1802.severity = warning # CA1825: Avoid zero-length array allocations dotnet_diagnostic.CA1825.severity = warning +# CA1822: Mark members as static +dotnet_diagnostic.CA1822.severity = warning # Wrapping preferences csharp_wrap_before_ternary_opsigns = false From 8724514a73e901d61e5fc622e4e21cadbe3d54d3 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:04:53 +0200 Subject: [PATCH 010/137] feat(ControlCatalog): Address rule CA1822 --- .../Pages/AutoCompleteBoxPage.xaml.cs | 8 +++---- .../Pages/CompositionPage.axaml.cs | 4 ++-- .../ControlCatalog/Pages/ImagePage.xaml.cs | 4 ++-- .../ControlCatalog/Pages/OpenGlPage.xaml.cs | 22 +++++++++---------- samples/ControlCatalog/Pages/ScreenPage.cs | 12 +++++----- .../Pages/TabControlPage.xaml.cs | 16 +++++++------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs index bc18327f12..15021b89c6 100644 --- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs +++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs @@ -32,7 +32,7 @@ namespace ControlCatalog.Pages } } - private StateData[] BuildAllStates() + private static StateData[] BuildAllStates() { return new StateData[] { @@ -90,7 +90,7 @@ namespace ControlCatalog.Pages } public StateData[] States { get; private set; } - private LinkedList[] BuildAllSentences() + private static LinkedList[] BuildAllSentences() { return new string[] { @@ -108,8 +108,8 @@ namespace ControlCatalog.Pages { this.InitializeComponent(); - States = BuildAllStates(); - Sentences = BuildAllSentences(); + States = AutoCompleteBoxPage.BuildAllStates(); + Sentences = AutoCompleteBoxPage.BuildAllSentences(); foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox")) { diff --git a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs index 61e0ed5acb..877c183a22 100644 --- a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs +++ b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs @@ -22,10 +22,10 @@ public partial class CompositionPage : UserControl protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); - this.Get("Items").Items = CreateColorItems(); + this.Get("Items").Items = CompositionPage.CreateColorItems(); } - private List CreateColorItems() + private static List CreateColorItems() { var list = new List(); diff --git a/samples/ControlCatalog/Pages/ImagePage.xaml.cs b/samples/ControlCatalog/Pages/ImagePage.xaml.cs index 45043aa5af..a520ee9b46 100644 --- a/samples/ControlCatalog/Pages/ImagePage.xaml.cs +++ b/samples/ControlCatalog/Pages/ImagePage.xaml.cs @@ -52,13 +52,13 @@ namespace ControlCatalog.Pages var comboxBox = (ComboBox)sender; if (_croppedImage.Source is CroppedBitmap croppedBitmap) { - croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex); + croppedBitmap.SourceRect = ImagePage.GetCropRect(comboxBox.SelectedIndex); } } } - private PixelRect GetCropRect(int index) + private static PixelRect GetCropRect(int index) { var bitmapWidth = 640; var bitmapHeight = 426; diff --git a/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs b/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs index a126fbefe5..2f636f88cf 100644 --- a/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs +++ b/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs @@ -247,7 +247,7 @@ namespace ControlCatalog.Pages } - private void CheckError(GlInterface gl) + private static void CheckError(GlInterface gl) { int err; while ((err = gl.GetError()) != GL_NO_ERROR) @@ -256,7 +256,7 @@ namespace ControlCatalog.Pages protected unsafe override void OnOpenGlInit(GlInterface GL, int fb) { - CheckError(GL); + OpenGlPageControl.CheckError(GL); Info = $"Renderer: {GL.GetString(GL_RENDERER)} Version: {GL.GetString(GL_VERSION)}"; @@ -277,13 +277,13 @@ namespace ControlCatalog.Pages GL.BindAttribLocationString(_shaderProgram, positionLocation, "aPos"); GL.BindAttribLocationString(_shaderProgram, normalLocation, "aNormal"); Console.WriteLine(GL.LinkProgramAndGetError(_shaderProgram)); - CheckError(GL); + OpenGlPageControl.CheckError(GL); // Create the vertex buffer object (VBO) for the vertex data. _vertexBufferObject = GL.GenBuffer(); // Bind the VBO and copy the vertex data into it. GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject); - CheckError(GL); + OpenGlPageControl.CheckError(GL); var vertexSize = Marshal.SizeOf(); fixed (void* pdata = _points) GL.BufferData(GL_ARRAY_BUFFER, new IntPtr(_points.Length * vertexSize), @@ -291,21 +291,21 @@ namespace ControlCatalog.Pages _indexBufferObject = GL.GenBuffer(); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject); - CheckError(GL); + OpenGlPageControl.CheckError(GL); fixed (void* pdata = _indices) GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata), GL_STATIC_DRAW); - CheckError(GL); + OpenGlPageControl.CheckError(GL); _vertexArrayObject = GL.GenVertexArray(); GL.BindVertexArray(_vertexArrayObject); - CheckError(GL); + OpenGlPageControl.CheckError(GL); GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT, 0, vertexSize, IntPtr.Zero); GL.VertexAttribPointer(normalLocation, 3, GL_FLOAT, 0, vertexSize, new IntPtr(12)); GL.EnableVertexAttribArray(positionLocation); GL.EnableVertexAttribArray(normalLocation); - CheckError(GL); + OpenGlPageControl.CheckError(GL); } @@ -339,7 +339,7 @@ namespace ControlCatalog.Pages GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject); GL.BindVertexArray(_vertexArrayObject); GL.UseProgram(_shaderProgram); - CheckError(GL); + OpenGlPageControl.CheckError(GL); var projection = Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.PI / 4), (float)(Bounds.Width / Bounds.Height), 0.01f, 1000); @@ -361,10 +361,10 @@ namespace ControlCatalog.Pages GL.Uniform1f(minYLoc, _minY); GL.Uniform1f(timeLoc, (float)St.Elapsed.TotalSeconds); GL.Uniform1f(discoLoc, _disco); - CheckError(GL); + OpenGlPageControl.CheckError(GL); GL.DrawElements(GL_TRIANGLES, _indices.Length, GL_UNSIGNED_SHORT, IntPtr.Zero); - CheckError(GL); + OpenGlPageControl.CheckError(GL); if (_disco > 0.01) Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); } diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index 823f59e030..841b347d78 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -55,21 +55,21 @@ namespace ControlCatalog.Pages context.DrawRectangle(p, workingAreaRect); - var formattedText = CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}"); + var formattedText = ScreenPage.CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height)); formattedText = - CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); + ScreenPage.CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20)); - formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%"); + formattedText = ScreenPage.CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); - formattedText = CreateFormattedText($"Primary: {screen.Primary}"); + formattedText = ScreenPage.CreateFormattedText($"Primary: {screen.Primary}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); formattedText = - CreateFormattedText( + ScreenPage.CreateFormattedText( $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 80)); } @@ -77,7 +77,7 @@ namespace ControlCatalog.Pages context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10)); } - private FormattedText CreateFormattedText(string textToFormat) + private static FormattedText CreateFormattedText(string textToFormat) { return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Typeface.Default, 12, Brushes.Green); diff --git a/samples/ControlCatalog/Pages/TabControlPage.xaml.cs b/samples/ControlCatalog/Pages/TabControlPage.xaml.cs index bd0214c72e..2cc4587dce 100644 --- a/samples/ControlCatalog/Pages/TabControlPage.xaml.cs +++ b/samples/ControlCatalog/Pages/TabControlPage.xaml.cs @@ -14,6 +14,12 @@ namespace ControlCatalog.Pages public class TabControlPage : UserControl { + private static IBitmap LoadBitmap(string uri) + { + var assets = AvaloniaLocator.Current!.GetService()!; + return new Bitmap(assets.Open(new Uri(uri))); + } + public TabControlPage() { InitializeComponent(); @@ -26,13 +32,13 @@ namespace ControlCatalog.Pages { Header = "Arch", Text = "This is the first templated tab page.", - Image = LoadBitmap("avares://ControlCatalog/Assets/delicate-arch-896885_640.jpg"), + Image = TabControlPage.LoadBitmap("avares://ControlCatalog/Assets/delicate-arch-896885_640.jpg"), }, new TabItemViewModel { Header = "Leaf", Text = "This is the second templated tab page.", - Image = LoadBitmap("avares://ControlCatalog/Assets/maple-leaf-888807_640.jpg"), + Image = TabControlPage.LoadBitmap("avares://ControlCatalog/Assets/maple-leaf-888807_640.jpg"), }, new TabItemViewModel { @@ -50,12 +56,6 @@ namespace ControlCatalog.Pages AvaloniaXamlLoader.Load(this); } - private IBitmap LoadBitmap(string uri) - { - var assets = AvaloniaLocator.Current!.GetService()!; - return new Bitmap(assets.Open(new Uri(uri))); - } - private class PageViewModel : ViewModelBase { private Dock _tabPlacement; From 28c033982b17b3f9d9730eca946377207d352458 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:05:43 +0200 Subject: [PATCH 011/137] feat(Android): Address rule CA1822 --- .../Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs | 2 +- .../Avalonia.Android/Platform/Storage/AndroidStorageItem.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index 4cae700c0a..9de9841266 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -30,7 +30,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers return DispatchKeyEventInternal(e, out callBase); } - string UnicodeTextInput(KeyEvent keyEvent) + static string UnicodeTextInput(KeyEvent keyEvent) { return keyEvent.Action == KeyEventActions.Multiple && keyEvent.RepeatCount == 0 diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs index a9b2e16d43..078f70db60 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs @@ -178,7 +178,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF return false; } - private Stream? GetVirtualFileStream(Context context, AndroidUri uri, bool isOutput) + private static Stream? GetVirtualFileStream(Context context, AndroidUri uri, bool isOutput) { var mimeTypes = context.ContentResolver?.GetStreamTypes(uri, FilePickerFileTypes.All.MimeTypes![0]); if (mimeTypes?.Length >= 1) From 93998f2a03d214248ca5384b51ca815527d4565c Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:07:00 +0200 Subject: [PATCH 012/137] feat(Base): Address rule CA1822 --- .../Animators/GradientBrushAnimator.cs | 8 ++++---- src/Avalonia.Base/Animation/KeySpline.cs | 8 ++++---- src/Avalonia.Base/Controls/Classes.cs | 18 +++++++++--------- src/Avalonia.Base/Data/Core/ExpressionNode.cs | 4 ++-- .../Parsers/ExpressionVisitorNodeBuilder.cs | 6 +++--- .../Plugins/DataAnnotationsValidationPlugin.cs | 4 ++-- .../Data/Core/Plugins/IndeiValidationPlugin.cs | 4 ++-- .../Data/Core/Plugins/TaskStreamPlugin.cs | 6 +++--- src/Avalonia.Base/Input/DragDropDevice.cs | 16 ++++++++-------- src/Avalonia.Base/Input/KeyGesture.cs | 4 ++-- src/Avalonia.Base/Input/MouseDevice.cs | 6 +++--- src/Avalonia.Base/Input/PenDevice.cs | 4 ++-- src/Avalonia.Base/Input/Pointer.cs | 4 ++-- src/Avalonia.Base/Input/TouchDevice.cs | 8 ++++---- src/Avalonia.Base/Layout/AttachedLayout.cs | 10 +++++----- src/Avalonia.Base/Layout/StackLayout.cs | 8 ++++---- src/Avalonia.Base/Layout/UniformGridLayout.cs | 8 ++++---- src/Avalonia.Base/Platform/AssetLoader.cs | 8 ++++---- .../Animations/KeyFrameAnimationInstance.cs | 12 ++++++------ .../Composition/CompositingRenderer.cs | 6 +++--- .../Rendering/Composition/CompositionTarget.cs | 6 +++--- .../Drawing/CompositionDrawingContext.cs | 14 +++++++------- .../Rendering/DeferredRenderer.cs | 6 +++--- .../Rendering/SceneGraph/SceneBuilder.cs | 6 +++--- 24 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs index 4727ea1bfb..f469ea5652 100644 --- a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs @@ -28,7 +28,7 @@ namespace Avalonia.Animation.Animators { case IRadialGradientBrush oldRadial when newValue is IRadialGradientBrush newRadial: return new ImmutableRadialGradientBrush( - InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), + GradientBrushAnimator.InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), @@ -39,7 +39,7 @@ namespace Avalonia.Animation.Animators case IConicGradientBrush oldConic when newValue is IConicGradientBrush newConic: return new ImmutableConicGradientBrush( - InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), + GradientBrushAnimator.InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), @@ -49,7 +49,7 @@ namespace Avalonia.Animation.Animators case ILinearGradientBrush oldLinear when newValue is ILinearGradientBrush newLinear: return new ImmutableLinearGradientBrush( - InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), + GradientBrushAnimator.InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), @@ -72,7 +72,7 @@ namespace Avalonia.Animation.Animators return control.Bind((AvaloniaProperty)Property, instance, BindingPriority.Animation); } - private IReadOnlyList InterpolateStops(double progress, IReadOnlyList oldValue, IReadOnlyList newValue) + private static IReadOnlyList InterpolateStops(double progress, IReadOnlyList oldValue, IReadOnlyList newValue) { var resultCount = Math.Max(oldValue.Count, newValue.Count); var stops = new ImmutableGradientStop[resultCount]; diff --git a/src/Avalonia.Base/Animation/KeySpline.cs b/src/Avalonia.Base/Animation/KeySpline.cs index a6e9769186..b33cd6b881 100644 --- a/src/Avalonia.Base/Animation/KeySpline.cs +++ b/src/Avalonia.Base/Animation/KeySpline.cs @@ -98,7 +98,7 @@ namespace Avalonia.Animation get => _controlPointX1; set { - if (IsValidXValue(value)) + if (KeySpline.IsValidXValue(value)) { _controlPointX1 = value; _isDirty = true; @@ -131,7 +131,7 @@ namespace Avalonia.Animation get => _controlPointX2; set { - if (IsValidXValue(value)) + if (KeySpline.IsValidXValue(value)) { _controlPointX2 = value; _isDirty = true; @@ -188,7 +188,7 @@ namespace Avalonia.Animation /// acceptable range; false otherwise. public bool IsValid() { - return IsValidXValue(_controlPointX1) && IsValidXValue(_controlPointX2); + return KeySpline.IsValidXValue(_controlPointX1) && KeySpline.IsValidXValue(_controlPointX2); } /// @@ -196,7 +196,7 @@ namespace Avalonia.Animation /// /// /// - private bool IsValidXValue(double value) + private static bool IsValidXValue(double value) { return value >= 0.0 && value <= 1.0; } diff --git a/src/Avalonia.Base/Controls/Classes.cs b/src/Avalonia.Base/Controls/Classes.cs index c3d3fbca46..100c2b2a8f 100644 --- a/src/Avalonia.Base/Controls/Classes.cs +++ b/src/Avalonia.Base/Controls/Classes.cs @@ -63,7 +63,7 @@ namespace Avalonia.Controls /// public override void Add(string name) { - ThrowIfPseudoclass(name, "added"); + Classes.ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -87,7 +87,7 @@ namespace Avalonia.Controls foreach (var name in names) { - ThrowIfPseudoclass(name, "added"); + Classes.ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -127,7 +127,7 @@ namespace Avalonia.Controls /// public override void Insert(int index, string name) { - ThrowIfPseudoclass(name, "added"); + Classes.ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -152,7 +152,7 @@ namespace Avalonia.Controls foreach (var name in names) { - ThrowIfPseudoclass(name, "added"); + Classes.ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -180,7 +180,7 @@ namespace Avalonia.Controls /// public override bool Remove(string name) { - ThrowIfPseudoclass(name, "removed"); + Classes.ThrowIfPseudoclass(name, "removed"); if (base.Remove(name)) { @@ -206,7 +206,7 @@ namespace Avalonia.Controls foreach (var name in names) { - ThrowIfPseudoclass(name, "removed"); + Classes.ThrowIfPseudoclass(name, "removed"); toRemove ??= new List(); @@ -232,7 +232,7 @@ namespace Avalonia.Controls public override void RemoveAt(int index) { var name = this[index]; - ThrowIfPseudoclass(name, "removed"); + Classes.ThrowIfPseudoclass(name, "removed"); base.RemoveAt(index); NotifyChanged(); } @@ -258,7 +258,7 @@ namespace Avalonia.Controls foreach (var name in source) { - ThrowIfPseudoclass(name, "added"); + Classes.ThrowIfPseudoclass(name, "added"); } foreach (var name in this) @@ -320,7 +320,7 @@ namespace Avalonia.Controls listener.Changed(); } - private void ThrowIfPseudoclass(string name, string operation) + private static void ThrowIfPseudoclass(string name, string operation) { if (name.StartsWith(":")) { diff --git a/src/Avalonia.Base/Data/Core/ExpressionNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNode.cs index 4f755ff140..d1bc60541c 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNode.cs @@ -138,7 +138,7 @@ namespace Avalonia.Data.Core if (target == null) { - ValueChanged(TargetNullNotification()); + ValueChanged(ExpressionNode.TargetNullNotification()); _listening = false; } else if (target != AvaloniaProperty.UnsetValue) @@ -159,7 +159,7 @@ namespace Avalonia.Data.Core _listening = false; } - private BindingNotification TargetNullNotification() + private static BindingNotification TargetNullNotification() { return new BindingNotification( new MarkupBindingChainException("Null value"), diff --git a/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs b/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs index 1e82214d76..9b9ddf2183 100644 --- a/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs +++ b/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs @@ -70,7 +70,7 @@ namespace Avalonia.Data.Core.Parsers if (node.Indexer == AvaloniaObjectIndexer) { - var property = GetArgumentExpressionValue(node.Arguments[0]); + var property = ExpressionVisitorNodeBuilder.GetArgumentExpressionValue(node.Arguments[0]); Nodes.Add(new AvaloniaPropertyAccessorNode(property, _enableDataValidation)); } else @@ -81,7 +81,7 @@ namespace Avalonia.Data.Core.Parsers return node; } - private T GetArgumentExpressionValue(Expression expr) + private static T GetArgumentExpressionValue(Expression expr) { try { @@ -162,7 +162,7 @@ namespace Avalonia.Data.Core.Parsers if (node.Method == CreateDelegateMethod) { var visited = Visit(node.Arguments[1]); - Nodes.Add(new PropertyAccessorNode(GetArgumentExpressionValue(node.Object!).Name, _enableDataValidation)); + Nodes.Add(new PropertyAccessorNode(ExpressionVisitorNodeBuilder.GetArgumentExpressionValue(node.Object!).Name, _enableDataValidation)); return node; } else if (node.Method.Name == StreamBindingExtensions.StreamBindingName || node.Method.Name.StartsWith(StreamBindingExtensions.StreamBindingName + '`')) diff --git a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs index 361d68dc81..54d5b5ac28 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs @@ -57,13 +57,13 @@ namespace Avalonia.Data.Core.Plugins else { base.InnerValueChanged(new BindingNotification( - CreateException(errors), + Accessor.CreateException(errors), BindingErrorType.DataValidationError, value)); } } - private Exception CreateException(IList errors) + private static Exception CreateException(IList errors) { if (errors.Count == 1) { diff --git a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs index 1e7a0d5c8f..e45170ff7e 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs @@ -92,7 +92,7 @@ namespace Avalonia.Data.Core.Plugins if (errors?.Count > 0) { return new BindingNotification( - GenerateException(errors), + Validator.GenerateException(errors), BindingErrorType.DataValidationError, value); } @@ -108,7 +108,7 @@ namespace Avalonia.Data.Core.Plugins return target; } - private Exception GenerateException(IList errors) + private static Exception GenerateException(IList errors) { if (errors.Count == 1) { diff --git a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs index 377ea9f275..b25d592597 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs @@ -44,11 +44,11 @@ namespace Avalonia.Data.Core.Plugins { case TaskStatus.RanToCompletion: case TaskStatus.Faulted: - return HandleCompleted(task); + return TaskStreamPlugin.HandleCompleted(task); default: var subject = new Subject(); task.ContinueWith( - x => HandleCompleted(task).Subscribe(subject), + x => TaskStreamPlugin.HandleCompleted(task).Subscribe(subject), TaskScheduler.FromCurrentSynchronizationContext()) .ConfigureAwait(false); return subject; @@ -59,7 +59,7 @@ namespace Avalonia.Data.Core.Plugins return Observable.Empty(); } - private IObservable HandleCompleted(Task task) + private static IObservable HandleCompleted(Task task) { var resultProperty = task.GetType().GetRuntimeProperty("Result"); diff --git a/src/Avalonia.Base/Input/DragDropDevice.cs b/src/Avalonia.Base/Input/DragDropDevice.cs index 30a08eda17..16ff428d69 100644 --- a/src/Avalonia.Base/Input/DragDropDevice.cs +++ b/src/Avalonia.Base/Input/DragDropDevice.cs @@ -11,7 +11,7 @@ namespace Avalonia.Input private Interactive? _lastTarget = null; - private Interactive? GetTarget(IInputRoot root, Point local) + private static Interactive? GetTarget(IInputRoot root, Point local) { var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType()?.FirstOrDefault(); if (target != null && DragDrop.GetAllowDrop(target)) @@ -19,7 +19,7 @@ namespace Avalonia.Input return null; } - private DragDropEffects RaiseDragEvent(Interactive? target, IInputRoot inputRoot, Point point, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data, KeyModifiers modifiers) + private static DragDropEffects RaiseDragEvent(Interactive? target, IInputRoot inputRoot, Point point, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data, KeyModifiers modifiers) { if (target == null) return DragDropEffects.None; @@ -40,22 +40,22 @@ namespace Avalonia.Input private DragDropEffects DragEnter(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, KeyModifiers modifiers) { - _lastTarget = GetTarget(inputRoot, point); - return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); + _lastTarget = DragDropDevice.GetTarget(inputRoot, point); + return DragDropDevice.RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } private DragDropEffects DragOver(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, KeyModifiers modifiers) { - var target = GetTarget(inputRoot, point); + var target = DragDropDevice.GetTarget(inputRoot, point); if (target == _lastTarget) - return RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data, modifiers); + return DragDropDevice.RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data, modifiers); try { if (_lastTarget != null) _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); - return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); + return DragDropDevice.RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } finally { @@ -81,7 +81,7 @@ namespace Avalonia.Input { try { - return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data, modifiers); + return DragDropDevice.RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data, modifiers); } finally { diff --git a/src/Avalonia.Base/Input/KeyGesture.cs b/src/Avalonia.Base/Input/KeyGesture.cs index 1a6372d346..7f4f69590a 100644 --- a/src/Avalonia.Base/Input/KeyGesture.cs +++ b/src/Avalonia.Base/Input/KeyGesture.cs @@ -138,7 +138,7 @@ namespace Avalonia.Input public bool Matches(KeyEventArgs keyEvent) => keyEvent != null && keyEvent.KeyModifiers == KeyModifiers && - ResolveNumPadOperationKey(keyEvent.Key) == ResolveNumPadOperationKey(Key); + KeyGesture.ResolveNumPadOperationKey(keyEvent.Key) == KeyGesture.ResolveNumPadOperationKey(Key); // TODO: Move that to external key parser private static Key ParseKey(string key) @@ -166,7 +166,7 @@ namespace Avalonia.Input return EnumHelper.Parse(modifier.ToString(), true); } - private Key ResolveNumPadOperationKey(Key key) + private static Key ResolveNumPadOperationKey(Key key) { switch (key) { diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index 055c9cf1fd..6fb34efdb5 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -34,7 +34,7 @@ namespace Avalonia.Input ProcessRawEvent(margs); } - int ButtonCount(PointerPointProperties props) + static int ButtonCount(PointerPointProperties props) { var rv = 0; if (props.IsLeftButtonPressed) @@ -71,7 +71,7 @@ namespace Avalonia.Input case RawPointerEventType.MiddleButtonDown: case RawPointerEventType.XButton1Down: case RawPointerEventType.XButton2Down: - if (ButtonCount(props) > 1) + if (MouseDevice.ButtonCount(props) > 1) e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult); else e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult); @@ -81,7 +81,7 @@ namespace Avalonia.Input case RawPointerEventType.MiddleButtonUp: case RawPointerEventType.XButton1Up: case RawPointerEventType.XButton2Up: - if (ButtonCount(props) != 0) + if (MouseDevice.ButtonCount(props) != 0) e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult); else e.Handled = MouseUp(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult); diff --git a/src/Avalonia.Base/Input/PenDevice.cs b/src/Avalonia.Base/Input/PenDevice.cs index f5f0e90a45..876be42be8 100644 --- a/src/Avalonia.Base/Input/PenDevice.cs +++ b/src/Avalonia.Base/Input/PenDevice.cs @@ -56,7 +56,7 @@ namespace Avalonia.Input e.Handled = PenUp(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult); break; case RawPointerEventType.Move: - e.Handled = PenMove(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult, e.IntermediatePoints); + e.Handled = PenDevice.PenMove(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult, e.IntermediatePoints); break; } @@ -98,7 +98,7 @@ namespace Avalonia.Input return false; } - private bool PenMove(Pointer pointer, ulong timestamp, + private static bool PenMove(Pointer pointer, ulong timestamp, IInputRoot root, Point p, PointerPointProperties properties, KeyModifiers inputModifiers, IInputElement? hitTest, Lazy?>? intermediatePoints) diff --git a/src/Avalonia.Base/Input/Pointer.cs b/src/Avalonia.Base/Input/Pointer.cs index 3012f07f6a..be93d9d6b8 100644 --- a/src/Avalonia.Base/Input/Pointer.cs +++ b/src/Avalonia.Base/Input/Pointer.cs @@ -19,7 +19,7 @@ namespace Avalonia.Input public int Id { get; } - IInputElement? FindCommonParent(IInputElement? control1, IInputElement? control2) + static IInputElement? FindCommonParent(IInputElement? control1, IInputElement? control2) { if (control1 == null || control2 == null) return null; @@ -41,7 +41,7 @@ namespace Avalonia.Input PlatformCapture(control); if (oldCapture != null) { - var commonParent = FindCommonParent(control, oldCapture); + var commonParent = Pointer.FindCommonParent(control, oldCapture); foreach (var notifyTarget in oldCapture.GetSelfAndVisualAncestors().OfType()) { if (notifyTarget == commonParent) diff --git a/src/Avalonia.Base/Input/TouchDevice.cs b/src/Avalonia.Base/Input/TouchDevice.cs index 1d5b1d6bbf..b709b7d0cd 100644 --- a/src/Avalonia.Base/Input/TouchDevice.cs +++ b/src/Avalonia.Base/Input/TouchDevice.cs @@ -20,7 +20,7 @@ namespace Avalonia.Input private Rect _lastClickRect; private ulong _lastClickTime; - RawInputModifiers GetModifiers(RawInputModifiers modifiers, bool isLeftButtonDown) + static RawInputModifiers GetModifiers(RawInputModifiers modifiers, bool isLeftButtonDown) { var rv = modifiers &= RawInputModifiers.KeyboardMask; if (isLeftButtonDown) @@ -73,7 +73,7 @@ namespace Avalonia.Input target.RaiseEvent(new PointerPressedEventArgs(target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind), + new PointerPointProperties(TouchDevice.GetModifiers(args.InputModifiers, true), updateKind), keyModifier, _clickCount)); } @@ -84,7 +84,7 @@ namespace Avalonia.Input { target.RaiseEvent(new PointerReleasedEventArgs(target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(GetModifiers(args.InputModifiers, false), updateKind), + new PointerPointProperties(TouchDevice.GetModifiers(args.InputModifiers, false), updateKind), keyModifier, MouseButton.Left)); } } @@ -100,7 +100,7 @@ namespace Avalonia.Input { target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind), + new PointerPointProperties(TouchDevice.GetModifiers(args.InputModifiers, true), updateKind), keyModifier, args.IntermediatePoints)); } } diff --git a/src/Avalonia.Base/Layout/AttachedLayout.cs b/src/Avalonia.Base/Layout/AttachedLayout.cs index ece8bbe805..594fc04842 100644 --- a/src/Avalonia.Base/Layout/AttachedLayout.cs +++ b/src/Avalonia.Base/Layout/AttachedLayout.cs @@ -67,7 +67,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = GetVirtualizingLayoutContext(context); + var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); virtualizingLayout.InitializeForContextCore(virtualizingContext); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -92,7 +92,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = GetVirtualizingLayoutContext(context); + var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); virtualizingLayout.UninitializeForContextCore(virtualizingContext); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -126,7 +126,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = GetVirtualizingLayoutContext(context); + var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); return virtualizingLayout.MeasureOverride(virtualizingContext, availableSize); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -157,7 +157,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = GetVirtualizingLayoutContext(context); + var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); return virtualizingLayout.ArrangeOverride(virtualizingContext, finalSize); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -184,7 +184,7 @@ namespace Avalonia.Layout /// protected void InvalidateArrange() => ArrangeInvalidated?.Invoke(this, EventArgs.Empty); - private VirtualizingLayoutContext GetVirtualizingLayoutContext(LayoutContext context) + private static VirtualizingLayoutContext GetVirtualizingLayoutContext(LayoutContext context) { if (context is VirtualizingLayoutContext virtualizingContext) { diff --git a/src/Avalonia.Base/Layout/StackLayout.cs b/src/Avalonia.Base/Layout/StackLayout.cs index e3c2ab3817..7983b37843 100644 --- a/src/Avalonia.Base/Layout/StackLayout.cs +++ b/src/Avalonia.Base/Layout/StackLayout.cs @@ -90,7 +90,7 @@ namespace Avalonia.Layout // Constants int itemsCount = context.ItemCount; var stackState = (StackLayoutState)context.LayoutState!; - double averageElementSize = GetAverageElementSize(availableSize, context, stackState) + Spacing; + double averageElementSize = StackLayout.GetAverageElementSize(availableSize, context, stackState) + Spacing; _orientation.SetMinorSize(ref extent, stackState.MaxArrangeBounds); _orientation.SetMajorSize(ref extent, Math.Max(0.0f, itemsCount * averageElementSize - Spacing)); @@ -178,7 +178,7 @@ namespace Avalonia.Layout { index = targetIndex; var state = (StackLayoutState)context.LayoutState!; - double averageElementSize = GetAverageElementSize(availableSize, context, state) + Spacing; + double averageElementSize = StackLayout.GetAverageElementSize(availableSize, context, state) + Spacing; offset = index * averageElementSize + _orientation.MajorStart(state.FlowAlgorithm.LastExtent); } @@ -237,7 +237,7 @@ namespace Avalonia.Layout var state = (StackLayoutState)context.LayoutState!; var lastExtent = state.FlowAlgorithm.LastExtent; - double averageElementSize = GetAverageElementSize(availableSize, context, state) + Spacing; + double averageElementSize = StackLayout.GetAverageElementSize(availableSize, context, state) + Spacing; double realizationWindowOffsetInExtent = _orientation.MajorStart(realizationRect) - _orientation.MajorStart(lastExtent); double majorSize = _orientation.MajorSize(lastExtent) == 0 ? Math.Max(0.0, averageElementSize * itemsCount - Spacing) : _orientation.MajorSize(lastExtent); if (itemsCount > 0 && @@ -335,7 +335,7 @@ namespace Avalonia.Layout InvalidateLayout(); } - private double GetAverageElementSize( + private static double GetAverageElementSize( Size availableSize, VirtualizingLayoutContext context, StackLayoutState stackLayoutState) diff --git a/src/Avalonia.Base/Layout/UniformGridLayout.cs b/src/Avalonia.Base/Layout/UniformGridLayout.cs index a7880a1545..acb333bcfa 100644 --- a/src/Avalonia.Base/Layout/UniformGridLayout.cs +++ b/src/Avalonia.Base/Layout/UniformGridLayout.cs @@ -432,7 +432,7 @@ namespace Avalonia.Layout var gridState = (UniformGridLayoutState)context.LayoutState!; gridState.EnsureElementSize(availableSize, context, _minItemWidth, _minItemHeight, _itemsStretch, Orientation, MinRowSpacing, MinColumnSpacing, _maximumRowsOrColumns); - var desiredSize = GetFlowAlgorithm(context).Measure( + var desiredSize = UniformGridLayout.GetFlowAlgorithm(context).Measure( availableSize, context, true, @@ -452,7 +452,7 @@ namespace Avalonia.Layout protected internal override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { - var value = GetFlowAlgorithm(context).Arrange( + var value = UniformGridLayout.GetFlowAlgorithm(context).Arrange( finalSize, context, true, @@ -463,7 +463,7 @@ namespace Avalonia.Layout protected internal override void OnItemsChangedCore(VirtualizingLayoutContext context, object? source, NotifyCollectionChangedEventArgs args) { - GetFlowAlgorithm(context).OnItemsSourceChanged(source, args, context); + UniformGridLayout.GetFlowAlgorithm(context).OnItemsSourceChanged(source, args, context); // Always invalidate layout to keep the view accurate. InvalidateLayout(); @@ -557,6 +557,6 @@ namespace Avalonia.Layout private void InvalidateLayout() => InvalidateMeasure(); - private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((UniformGridLayoutState)context.LayoutState!).FlowAlgorithm; + private static FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((UniformGridLayoutState)context.LayoutState!).FlowAlgorithm; } } diff --git a/src/Avalonia.Base/Platform/AssetLoader.cs b/src/Avalonia.Base/Platform/AssetLoader.cs index a74da2a178..77ae9f4c32 100644 --- a/src/Avalonia.Base/Platform/AssetLoader.cs +++ b/src/Avalonia.Base/Platform/AssetLoader.cs @@ -126,7 +126,7 @@ namespace Avalonia.Platform uri = uri.EnsureAbsolute(baseUri); if (uri.IsAvares()) { - var (asm, path) = GetResAsmAndPath(uri); + var (asm, path) = AssetLoader.GetResAsmAndPath(uri); if (asm == null) { throw new ArgumentException( @@ -171,7 +171,7 @@ namespace Avalonia.Platform if (uri.IsAvares()) { - var (asm, path) = GetResAsmAndPath(uri); + var (asm, path) = AssetLoader.GetResAsmAndPath(uri); if (asm.AvaloniaResources == null) return null; asm.AvaloniaResources.TryGetValue(path, out var desc); @@ -181,7 +181,7 @@ namespace Avalonia.Platform 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); return (asm, uri.GetUnescapeAbsolutePath()); @@ -194,7 +194,7 @@ namespace Avalonia.Platform if (!uri.IsAbsoluteUri) return null; if (uri.IsAvares()) - return GetResAsmAndPath(uri).asm; + return AssetLoader.GetResAsmAndPath(uri).asm; if (uri.IsResm()) { diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs index e20a4a9ad8..2b395f54af 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs @@ -87,7 +87,7 @@ namespace Avalonia.Rendering.Composition.Animations if (elapsed < _delayTime) { if (_delayBehavior == AnimationDelayBehavior.SetInitialValueBeforeDelay) - return ExpressionVariant.Create(GetKeyFrame(ref ctx, _keyFrames[0])); + return ExpressionVariant.Create(KeyFrameAnimationInstance.GetKeyFrame(ref ctx, _keyFrames[0])); return currentValue; } @@ -95,7 +95,7 @@ namespace Avalonia.Rendering.Composition.Animations var iterationNumber = elapsed.Ticks / _duration.Ticks; if (_iterationBehavior == AnimationIterationBehavior.Count && iterationNumber >= _iterationCount) - return ExpressionVariant.Create(GetKeyFrame(ref ctx, _keyFrames[_keyFrames.Length - 1])); + return ExpressionVariant.Create(KeyFrameAnimationInstance.GetKeyFrame(ref ctx, _keyFrames[_keyFrames.Length - 1])); var evenIterationNumber = iterationNumber % 2 == 0; @@ -124,7 +124,7 @@ namespace Avalonia.Rendering.Composition.Animations { // this is the last frame if (c == _keyFrames.Length - 1) - return ExpressionVariant.Create(GetKeyFrame(ref ctx, kf)); + return ExpressionVariant.Create(KeyFrameAnimationInstance.GetKeyFrame(ref ctx, kf)); left = kf; right = _keyFrames[c + 1]; @@ -139,13 +139,13 @@ namespace Avalonia.Rendering.Composition.Animations return currentValue; return ExpressionVariant.Create(_interpolator.Interpolate( - GetKeyFrame(ref ctx, left), - GetKeyFrame(ref ctx, right), + KeyFrameAnimationInstance.GetKeyFrame(ref ctx, left), + KeyFrameAnimationInstance.GetKeyFrame(ref ctx, right), easedKeyProgress )); } - T GetKeyFrame(ref ExpressionEvaluationContext ctx, ServerKeyFrame f) + static T GetKeyFrame(ref ExpressionEvaluationContext ctx, ServerKeyFrame f) { if (f.Expression != null) return f.Expression.Evaluate(ref ctx).CastOrDefault(); diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index 98a6a3600e..3c9a9feac0 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -124,7 +124,7 @@ public class CompositingRenderer : IRendererWithCompositor QueueUpdate(); } - private void SyncChildren(Visual v) + private static void SyncChildren(Visual v) { //TODO: Optimize by moving that logic to Visual itself if(v.CompositionVisual == null) @@ -233,11 +233,11 @@ public class CompositingRenderer : IRendererWithCompositor visual.Render(_recordingContext); comp.DrawList = _recorder.EndUpdate(); - SyncChildren(visual); + CompositingRenderer.SyncChildren(visual); } foreach(var v in _recalculateChildren) if (!_dirty.Contains(v)) - SyncChildren(v); + CompositingRenderer.SyncChildren(v); _dirty.Clear(); _recalculateChildren.Clear(); CompositionTarget.Size = _root.ClientSize; diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs index d8a608651b..52215e8011 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs @@ -53,7 +53,7 @@ namespace Avalonia.Rendering.Composition var m = Matrix.Identity; while (v != null) { - if (!TryGetInvertedTransform(v, out var cm)) + if (!CompositionTarget.TryGetInvertedTransform(v, out var cm)) return null; m = m * cm; v = v.Parent; @@ -62,7 +62,7 @@ namespace Avalonia.Rendering.Composition return point * m; } - bool TryGetInvertedTransform(CompositionVisual visual, out Matrix matrix) + static bool TryGetInvertedTransform(CompositionVisual visual, out Matrix matrix) { var m = visual.TryGetServerGlobalTransform(); if (m == null) @@ -78,7 +78,7 @@ namespace Avalonia.Rendering.Composition bool TryTransformTo(CompositionVisual visual, Point globalPoint, out Point v) { v = default; - if (TryGetInvertedTransform(visual, out var m)) + if (CompositionTarget.TryGetInvertedTransform(visual, out var m)) { v = globalPoint * m; return true; diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs index 30b57883fc..c02eb5687f 100644 --- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs +++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs @@ -55,7 +55,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW if (next == null || !next.Item.Equals(Transform, brush, pen, geometry)) { - Add(new GeometryNode(Transform, brush, pen, geometry, CreateChildScene(brush))); + Add(new GeometryNode(Transform, brush, pen, geometry, CompositionDrawingContext.CreateChildScene(brush))); } else { @@ -94,7 +94,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW if (next == null || !next.Item.Equals(Transform, pen, p1, p2)) { - Add(new LineNode(Transform, pen, p1, p2, CreateChildScene(pen.Brush))); + Add(new LineNode(Transform, pen, p1, p2, CompositionDrawingContext.CreateChildScene(pen.Brush))); } else { @@ -110,7 +110,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW if (next == null || !next.Item.Equals(Transform, brush, pen, rect, boxShadows)) { - Add(new RectangleNode(Transform, brush, pen, rect, boxShadows, CreateChildScene(brush))); + Add(new RectangleNode(Transform, brush, pen, rect, boxShadows, CompositionDrawingContext.CreateChildScene(brush))); } else { @@ -139,7 +139,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW if (next == null || !next.Item.Equals(Transform, brush, pen, rect)) { - Add(new EllipseNode(Transform, brush, pen, rect, CreateChildScene(brush))); + Add(new EllipseNode(Transform, brush, pen, rect, CompositionDrawingContext.CreateChildScene(brush))); } else { @@ -165,7 +165,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW if (next == null || !next.Item.Equals(Transform, foreground, glyphRun)) { - Add(new GlyphRunNode(Transform, foreground, glyphRun, CreateChildScene(foreground))); + Add(new GlyphRunNode(Transform, foreground, glyphRun, CompositionDrawingContext.CreateChildScene(foreground))); } else @@ -324,7 +324,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW if (next == null || !next.Item.Equals(mask, bounds)) { - Add(new OpacityMaskNode(mask, bounds, CreateChildScene(mask))); + Add(new OpacityMaskNode(mask, bounds, CompositionDrawingContext.CreateChildScene(mask))); } else { @@ -368,7 +368,7 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW : null; } - private IDisposable? CreateChildScene(IBrush? brush) + private static IDisposable? CreateChildScene(IBrush? brush) { if (brush is VisualBrush visualBrush) { diff --git a/src/Avalonia.Base/Rendering/DeferredRenderer.cs b/src/Avalonia.Base/Rendering/DeferredRenderer.cs index 4236763e3b..1eefa5a177 100644 --- a/src/Avalonia.Base/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Base/Rendering/DeferredRenderer.cs @@ -272,18 +272,18 @@ namespace Avalonia.Rendering } } - Scene? TryGetChildScene(IRef? op) => (op?.Item as BrushDrawOperation)?.Aux as Scene; + static Scene? TryGetChildScene(IRef? op) => (op?.Item as BrushDrawOperation)?.Aux as Scene; /// Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) { - return TryGetChildScene(_currentDraw)?.Size ?? Size.Empty; + return DeferredRenderer.TryGetChildScene(_currentDraw)?.Size ?? Size.Empty; } /// void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush) { - var childScene = TryGetChildScene(_currentDraw); + var childScene = DeferredRenderer.TryGetChildScene(_currentDraw); if (childScene != null) { diff --git a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs index 0ceb44ed75..a34cce8796 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs @@ -18,7 +18,7 @@ namespace Avalonia.Rendering.SceneGraph _ = scene ?? throw new ArgumentNullException(nameof(scene)); Dispatcher.UIThread.VerifyAccess(); - UpdateSize(scene); + SceneBuilder.UpdateSize(scene); scene.Layers.GetOrAdd(scene.Root.Visual); using (var impl = new DeferredDrawingContextImpl(this, scene.Layers)) @@ -46,7 +46,7 @@ namespace Avalonia.Rendering.SceneGraph if (visual == scene.Root.Visual) { - UpdateSize(scene); + SceneBuilder.UpdateSize(scene); } if (visual.VisualRoot == scene.Root.Visual) @@ -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 newSize = renderRoot?.ClientSize ?? scene.Root.Visual.Bounds.Size; From ee84a8c7fd242a76353aad24d83d483d344f6b83 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:08:25 +0200 Subject: [PATCH 013/137] feat(Controls): Address rule CA1822 --- .../Automation/Peers/ComboBoxAutomationPeer.cs | 8 ++++---- .../Calendar/CalendarBlackoutDatesCollection.cs | 10 +++++----- .../Calendar/SelectedDatesCollection.cs | 10 +++++----- src/Avalonia.Controls/ComboBox.cs | 8 ++++---- .../DateTimePickers/DateTimePickerPanel.cs | 6 +++--- src/Avalonia.Controls/Grid.cs | 6 +++--- src/Avalonia.Controls/GridSplitter.cs | 16 ++++++++-------- .../Platform/InProcessDragSource.cs | 4 ++-- .../Presenters/ScrollContentPresenter.cs | 8 ++++---- src/Avalonia.Controls/Primitives/AdornerLayer.cs | 4 ++-- src/Avalonia.Controls/Primitives/Popup.cs | 4 ++-- src/Avalonia.Controls/Repeater/RecyclePool.cs | 10 +++++----- .../Repeater/RecyclingElementFactory.cs | 4 ++-- src/Avalonia.Controls/SplitView.cs | 6 +++--- src/Avalonia.Controls/TextBox.cs | 10 +++++----- src/Avalonia.Controls/TopLevel.cs | 4 ++-- src/Avalonia.Controls/TreeView.cs | 6 +++--- src/Avalonia.Controls/UserControl.cs | 1 - 18 files changed, 62 insertions(+), 63 deletions(-) diff --git a/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs index 5ff291d972..d6295fdbd9 100644 --- a/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs @@ -18,7 +18,7 @@ namespace Avalonia.Automation.Peers public new ComboBox Owner => (ComboBox)base.Owner; - public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsDropDownOpen); + public ExpandCollapseState ExpandCollapseState => ComboBoxAutomationPeer.ToState(Owner.IsDropDownOpen); public bool ShowsMenu => true; public void Collapse() => Owner.IsDropDownOpen = false; public void Expand() => Owner.IsDropDownOpen = true; @@ -66,12 +66,12 @@ namespace Avalonia.Automation.Peers { RaisePropertyChangedEvent( ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, - ToState((bool)e.OldValue!), - ToState((bool)e.NewValue!)); + ComboBoxAutomationPeer.ToState((bool)e.OldValue!), + ComboBoxAutomationPeer.ToState((bool)e.NewValue!)); } } - private ExpandCollapseState ToState(bool value) + private static ExpandCollapseState ToState(bool value) { return value ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed; } diff --git a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs index a92feec509..61463795ee 100644 --- a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs +++ b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs @@ -122,7 +122,7 @@ namespace Avalonia.Controls.Primitives /// protected override void ClearItems() { - EnsureValidThread(); + CalendarBlackoutDatesCollection.EnsureValidThread(); base.ClearItems(); _owner.UpdateMonths(); @@ -140,7 +140,7 @@ namespace Avalonia.Controls.Primitives /// protected override void InsertItem(int index, CalendarDateRange item) { - EnsureValidThread(); + CalendarBlackoutDatesCollection.EnsureValidThread(); if (!IsValid(item)) { @@ -162,7 +162,7 @@ namespace Avalonia.Controls.Primitives /// protected override void RemoveItem(int index) { - EnsureValidThread(); + CalendarBlackoutDatesCollection.EnsureValidThread(); base.RemoveItem(index); _owner.UpdateMonths(); @@ -182,7 +182,7 @@ namespace Avalonia.Controls.Primitives /// protected override void SetItem(int index, CalendarDateRange item) { - EnsureValidThread(); + CalendarBlackoutDatesCollection.EnsureValidThread(); if (!IsValid(item)) { @@ -206,7 +206,7 @@ namespace Avalonia.Controls.Primitives return true; } - private void EnsureValidThread() + private static void EnsureValidThread() { Dispatcher.UIThread.VerifyAccess(); } diff --git a/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs b/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs index 211b5edb0d..8327442fcf 100644 --- a/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs +++ b/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs @@ -133,7 +133,7 @@ namespace Avalonia.Controls.Primitives /// protected override void ClearItems() { - EnsureValidThread(); + SelectedDatesCollection.EnsureValidThread(); Collection addedItems = new Collection(); Collection removedItems = new Collection(); @@ -170,7 +170,7 @@ namespace Avalonia.Controls.Primitives /// protected override void InsertItem(int index, DateTime item) { - EnsureValidThread(); + SelectedDatesCollection.EnsureValidThread(); if (!Contains(item)) { @@ -233,7 +233,7 @@ namespace Avalonia.Controls.Primitives /// protected override void RemoveItem(int index) { - EnsureValidThread(); + SelectedDatesCollection.EnsureValidThread(); if (index >= Count) { @@ -284,7 +284,7 @@ namespace Avalonia.Controls.Primitives /// protected override void SetItem(int index, DateTime item) { - EnsureValidThread(); + SelectedDatesCollection.EnsureValidThread(); if (!Contains(item)) { @@ -353,7 +353,7 @@ namespace Avalonia.Controls.Primitives return true; } - private void EnsureValidThread() + private static void EnsureValidThread() { Dispatcher.UIThread.VerifyAccess(); } diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 54196bdf1a..21918b27a8 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -236,7 +236,7 @@ namespace Avalonia.Controls else if (IsDropDownOpen && SelectedIndex < 0 && ItemCount > 0 && (e.Key == Key.Up || e.Key == Key.Down) && IsFocused == true) { - var firstChild = Presenter?.Panel?.Children.FirstOrDefault(c => CanFocus(c)); + var firstChild = Presenter?.Panel?.Children.FirstOrDefault(c => ComboBox.CanFocus(c)); if (firstChild != null) { FocusManager.Instance?.Focus(firstChild, NavigationMethod.Directional); @@ -341,7 +341,7 @@ namespace Avalonia.Controls { _subscriptionsOnOpen.Clear(); - if (CanFocus(this)) + if (ComboBox.CanFocus(this)) { Focus(); } @@ -403,14 +403,14 @@ namespace Avalonia.Controls container = ItemContainerGenerator.ContainerFromIndex(selectedIndex); } - if (container != null && CanFocus(container)) + if (container != null && ComboBox.CanFocus(container)) { container.Focus(); } } } - private bool CanFocus(IControl control) => control.Focusable && control.IsEffectivelyEnabled && control.IsVisible; + private static bool CanFocus(IControl control) => control.Focusable && control.IsEffectivelyEnabled && control.IsVisible; private void UpdateSelectionBoxItem(object? item) { diff --git a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs index 3fdfbee54d..eb4a7391b0 100644 --- a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs +++ b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs @@ -545,8 +545,8 @@ namespace Avalonia.Controls.Primitives private void OnItemTapped(object? sender, TappedEventArgs e) { - if (e.Source is IVisual source && - GetItemFromSource(source) is ListBoxItem listBoxItem && + if (e.Source is IVisual source && + DateTimePickerPanel.GetItemFromSource(source) is ListBoxItem listBoxItem && listBoxItem.Tag is int tag) { SelectedValue = tag; @@ -555,7 +555,7 @@ namespace Avalonia.Controls.Primitives } //Helper to get ListBoxItem from pointerevent source - private ListBoxItem? GetItemFromSource(IVisual src) + private static ListBoxItem? GetItemFromSource(IVisual src) { var item = src; while (item != null && !(item is ListBoxItem)) diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index 8d246d35f4..4dc88fec6a 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -1117,7 +1117,7 @@ namespace Avalonia.Controls else { // otherwise... - cellMeasureWidth = GetMeasureSizeForRange( + cellMeasureWidth = Grid.GetMeasureSizeForRange( DefinitionsU, PrivateCells[cell].ColumnIndex, PrivateCells[cell].ColumnSpan); @@ -1137,7 +1137,7 @@ namespace Avalonia.Controls } else { - cellMeasureHeight = GetMeasureSizeForRange( + cellMeasureHeight = Grid.GetMeasureSizeForRange( DefinitionsV, PrivateCells[cell].RowIndex, PrivateCells[cell].RowSpan); @@ -1165,7 +1165,7 @@ namespace Avalonia.Controls /// /// For "Auto" definitions MinWidth is used in place of PreferredSize. /// - private double GetMeasureSizeForRange( + private static double GetMeasureSizeForRange( IReadOnlyList definitions, int start, int count) diff --git a/src/Avalonia.Controls/GridSplitter.cs b/src/Avalonia.Controls/GridSplitter.cs index 85dad894fd..1a4736fa92 100644 --- a/src/Avalonia.Controls/GridSplitter.cs +++ b/src/Avalonia.Controls/GridSplitter.cs @@ -288,13 +288,13 @@ namespace Avalonia.Controls _resizeData.Definition1 = GetGridDefinition(_resizeData.Grid, index1, _resizeData.ResizeDirection); _resizeData.OriginalDefinition1Length = _resizeData.Definition1.UserSizeValueCache; // Save Size if user cancels. - _resizeData.OriginalDefinition1ActualLength = GetActualLength(_resizeData.Definition1); + _resizeData.OriginalDefinition1ActualLength = GridSplitter.GetActualLength(_resizeData.Definition1); _resizeData.Definition2Index = index2; _resizeData.Definition2 = GetGridDefinition(_resizeData.Grid, index2, _resizeData.ResizeDirection); _resizeData.OriginalDefinition2Length = _resizeData.Definition2.UserSizeValueCache; // Save Size if user cancels. - _resizeData.OriginalDefinition2ActualLength = GetActualLength(_resizeData.Definition2); + _resizeData.OriginalDefinition2ActualLength = GridSplitter.GetActualLength(_resizeData.Definition2); // Determine how to resize the columns. bool isStar1 = IsStar(_resizeData.Definition1); @@ -516,7 +516,7 @@ namespace Avalonia.Controls /// /// Retrieves the ActualWidth or ActualHeight of the definition depending on its type Column or Row. /// - private double GetActualLength(DefinitionBase definition) + private static double GetActualLength(DefinitionBase definition) { var column = definition as ColumnDefinition; @@ -537,11 +537,11 @@ namespace Avalonia.Controls /// private void GetDeltaConstraints(out double minDelta, out double maxDelta) { - double definition1Len = GetActualLength(_resizeData!.Definition1!); + double definition1Len = GridSplitter.GetActualLength(_resizeData!.Definition1!); double definition1Min = _resizeData.Definition1!.UserMinSizeValueCache; double definition1Max = _resizeData.Definition1.UserMaxSizeValueCache; - double definition2Len = GetActualLength(_resizeData.Definition2!); + double definition2Len = GridSplitter.GetActualLength(_resizeData.Definition2!); double definition2Min = _resizeData.Definition2!.UserMinSizeValueCache; double definition2Max = _resizeData.Definition2.UserMaxSizeValueCache; @@ -590,7 +590,7 @@ namespace Avalonia.Controls } else if (IsStar(definition)) { - SetDefinitionLength(definition, new GridLength(GetActualLength(definition), GridUnitType.Star)); + SetDefinitionLength(definition, new GridLength(GridSplitter.GetActualLength(definition), GridUnitType.Star)); } } } @@ -629,8 +629,8 @@ namespace Avalonia.Controls if (definition1 != null && definition2 != null) { - double actualLength1 = GetActualLength(definition1); - double actualLength2 = GetActualLength(definition2); + double actualLength1 = GridSplitter.GetActualLength(definition1); + double actualLength2 = GridSplitter.GetActualLength(definition2); double pixelLength = 1 / _resizeData.Scaling; double epsilon = pixelLength + LayoutHelper.LayoutEpsilon; diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index 209d5f03dc..e107d2c217 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -64,12 +64,12 @@ namespace Avalonia.Platform var tl = root.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); tl?.PlatformImpl?.Input?.Invoke(rawEvent); - var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers); + var effect = InProcessDragSource.GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers); UpdateCursor(root, 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) return effect; // No need to check for the modifiers. diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs index c526b7ac49..e5bf924120 100644 --- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs @@ -295,7 +295,7 @@ namespace Avalonia.Controls.Presenters // arrange then that change wasn't just due to scrolling (as scrolling doesn't adjust // relative positions within Child). if (_anchorElement != null && - TranslateBounds(_anchorElement, Child!, out var updatedBounds) && + ScrollContentPresenter.TranslateBounds(_anchorElement, Child!, out var updatedBounds) && updatedBounds.Position != _anchorElementBounds.Position) { var offset = updatedBounds.Position - _anchorElementBounds.Position; @@ -588,7 +588,7 @@ namespace Avalonia.Controls.Presenters private bool GetViewportBounds(IControl element, out Rect bounds) { - if (TranslateBounds(element, Child!, out var childBounds)) + if (ScrollContentPresenter.TranslateBounds(element, Child!, out var childBounds)) { // We want the bounds relative to the new Offset, regardless of whether the child // control has actually been arranged to this offset yet, so translate first to the @@ -605,7 +605,7 @@ namespace Avalonia.Controls.Presenters private Rect TranslateBounds(IControl control, IControl to) { - if (TranslateBounds(control, to, out var bounds)) + if (ScrollContentPresenter.TranslateBounds(control, to, out var bounds)) { return bounds; } @@ -613,7 +613,7 @@ namespace Avalonia.Controls.Presenters throw new InvalidOperationException("The control's bounds could not be translated to the requested control."); } - private bool TranslateBounds(IControl control, IControl to, out Rect bounds) + private static bool TranslateBounds(IControl control, IControl to, out Rect bounds) { if (!control.IsVisible) { diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index d557424fbb..12a17b8c9f 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -211,7 +211,7 @@ namespace Avalonia.Controls.Primitives { child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform); child.RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Absolute); - UpdateClip(child, info.Bounds.Value, isClipEnabled); + AdornerLayer.UpdateClip(child, info.Bounds.Value, isClipEnabled); child.Arrange(info.Bounds.Value.Bounds); } else @@ -232,7 +232,7 @@ namespace Avalonia.Controls.Primitives layer?.UpdateAdornedElement(adorner, adorned); } - private void UpdateClip(IControl control, TransformedBounds bounds, bool isEnabled) + private static void UpdateClip(IControl control, TransformedBounds bounds, bool isEnabled) { if (!isEnabled) { diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index ccb81ba276..581a65f6b9 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -475,7 +475,7 @@ namespace Avalonia.Controls.Primitives _openState = new PopupOpenState(placementTarget, topLevel, popupHost, cleanupPopup); - WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint); + Popup.WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint); popupHost.Show(); @@ -639,7 +639,7 @@ namespace Avalonia.Controls.Primitives 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) { diff --git a/src/Avalonia.Controls/Repeater/RecyclePool.cs b/src/Avalonia.Controls/Repeater/RecyclePool.cs index cf2b40836e..9d6ad37721 100644 --- a/src/Avalonia.Controls/Repeater/RecyclePool.cs +++ b/src/Avalonia.Controls/Repeater/RecyclePool.cs @@ -32,7 +32,7 @@ namespace Avalonia.Controls public void PutElement(IControl element, string key, IControl? owner) { - var ownerAsPanel = EnsureOwnerIsPanelOrNull(owner); + var ownerAsPanel = RecyclePool.EnsureOwnerIsPanelOrNull(owner); var elementInfo = new ElementInfo(element, ownerAsPanel); if (!_elements.TryGetValue(key, out var pool)) @@ -56,7 +56,7 @@ namespace Avalonia.Controls var elementInfo = elements.FirstOrDefault(x => x.Owner == owner) ?? elements.LastOrDefault(); elements.Remove(elementInfo!); - var ownerAsPanel = EnsureOwnerIsPanelOrNull(owner); + var ownerAsPanel = RecyclePool.EnsureOwnerIsPanelOrNull(owner); if (elementInfo!.Owner != null && elementInfo.Owner != ownerAsPanel) { // Element is still under its parent. remove it from its parent. @@ -80,10 +80,10 @@ namespace Avalonia.Controls return null; } - internal string GetReuseKey(IControl element) => ((Control)element).GetValue(ReuseKeyProperty); - internal void SetReuseKey(IControl element, string value) => ((Control)element).SetValue(ReuseKeyProperty, value); + internal static string GetReuseKey(IControl element) => ((Control)element).GetValue(ReuseKeyProperty); + internal static void SetReuseKey(IControl element, string value) => ((Control)element).SetValue(ReuseKeyProperty, value); - private IPanel? EnsureOwnerIsPanelOrNull(IControl? owner) + private static IPanel? EnsureOwnerIsPanelOrNull(IControl? owner) { if (owner is IPanel panel) { diff --git a/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs b/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs index c1baa66433..1258c58324 100644 --- a/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs +++ b/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs @@ -72,7 +72,7 @@ namespace Avalonia.Controls element = dataTemplate.Build(args.Data)!; // Associate ReuseKey with element - RecyclePool.SetReuseKey(element, templateKey); + Avalonia.Controls.RecyclePool.SetReuseKey(element, templateKey); } return element; @@ -81,7 +81,7 @@ namespace Avalonia.Controls protected override void RecycleElementCore(ElementFactoryRecycleArgs args) { var element = args.Element!; - var key = RecyclePool.GetReuseKey(element); + var key = Avalonia.Controls.RecyclePool.GetReuseKey(element); RecyclePool.PutElement(element, key, args.Parent); } diff --git a/src/Avalonia.Controls/SplitView.cs b/src/Avalonia.Controls/SplitView.cs index c344dd795d..2d735a2cbb 100644 --- a/src/Avalonia.Controls/SplitView.cs +++ b/src/Avalonia.Controls/SplitView.cs @@ -431,7 +431,7 @@ namespace Avalonia.Controls } } - private string GetPseudoClass(SplitViewDisplayMode mode) + private static string GetPseudoClass(SplitViewDisplayMode mode) { return mode switch { @@ -463,8 +463,8 @@ namespace Avalonia.Controls private void OnDisplayModeChanged(AvaloniaPropertyChangedEventArgs e) { - var oldState = GetPseudoClass(e.GetOldValue()); - var newState = GetPseudoClass(e.GetNewValue()); + var oldState = SplitView.GetPseudoClass(e.GetOldValue()); + var newState = SplitView.GetPseudoClass(e.GetNewValue()); PseudoClasses.Remove($":{oldState}"); PseudoClasses.Add($":{newState}"); diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index da4e90fb66..0ac57c9233 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -397,9 +397,9 @@ namespace Avalonia.Controls var selectionStart = SelectionStart; var selectionEnd = SelectionEnd; - CaretIndex = CoerceCaretIndex(caretIndex, value); - SelectionStart = CoerceCaretIndex(selectionStart, value); - SelectionEnd = CoerceCaretIndex(selectionEnd, value); + CaretIndex = TextBox.CoerceCaretIndex(caretIndex, value); + SelectionStart = TextBox.CoerceCaretIndex(selectionStart, value); + SelectionEnd = TextBox.CoerceCaretIndex(selectionEnd, value); var textChanged = SetAndRaise(TextProperty, ref _text, value); @@ -1380,9 +1380,9 @@ namespace Avalonia.Controls } } - private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text); + private int CoerceCaretIndex(int value) => TextBox.CoerceCaretIndex(value, Text); - private int CoerceCaretIndex(int value, string? text) + private static int CoerceCaretIndex(int value, string? text) { if (text == null) { diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 47fc9d7988..9fad9824df 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -429,7 +429,7 @@ namespace Avalonia.Controls LayoutHelper.InvalidateSelfAndChildrenMeasure(this); } - private bool TransparencyLevelsMatch (WindowTransparencyLevel requested, WindowTransparencyLevel received) + private static bool TransparencyLevelsMatch (WindowTransparencyLevel requested, WindowTransparencyLevel received) { if(requested == received) { @@ -449,7 +449,7 @@ namespace Avalonia.Controls { if(transparencyLevel == WindowTransparencyLevel.None || TransparencyLevelHint == WindowTransparencyLevel.None || - !TransparencyLevelsMatch(TransparencyLevelHint, transparencyLevel)) + !TopLevel.TransparencyLevelsMatch(TransparencyLevelHint, transparencyLevel)) { _transparencyFallbackBorder.Background = TransparencyBackgroundFallback; } diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index d78f9c82ef..be30792cc8 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -284,7 +284,7 @@ namespace Avalonia.Controls foreach (IControl container in ItemContainerGenerator.Index!.Containers) { - MarkContainerSelected(container, false); + TreeView.MarkContainerSelected(container, false); } if (SelectedItems.Count > 0) @@ -339,7 +339,7 @@ namespace Avalonia.Controls { var container = ItemContainerGenerator.Index!.ContainerFromItem(item)!; - MarkContainerSelected(container, selected); + TreeView.MarkContainerSelected(container, selected); } private void SelectedItemsAdded(IList items) @@ -826,7 +826,7 @@ namespace Avalonia.Controls /// /// The container. /// Whether the control is selected - private void MarkContainerSelected(IControl container, bool selected) + private static void MarkContainerSelected(IControl container, bool selected) { if (container == null) { diff --git a/src/Avalonia.Controls/UserControl.cs b/src/Avalonia.Controls/UserControl.cs index 7b9cc2da1c..e9339d5f4b 100644 --- a/src/Avalonia.Controls/UserControl.cs +++ b/src/Avalonia.Controls/UserControl.cs @@ -1,4 +1,3 @@ -using System; using Avalonia.Styling; namespace Avalonia.Controls From 4620e5cf99ff0a82832d117b23ca97ffb66c764d Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:09:16 +0200 Subject: [PATCH 014/137] feat(ColorPicker): Address rule CA1822 --- .../ColorPalettes/MaterialColorPalette.cs | 8 ++++---- .../ColorSlider/ColorSlider.cs | 6 +++--- .../ColorSpectrum/ColorSpectrum.cs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs b/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs index 5cf5662ede..555965a9a7 100644 --- a/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs +++ b/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs @@ -35,7 +35,7 @@ namespace Avalonia.Controls /// This is pulled out separately to lazy load for performance. /// If no material color palette is ever used, no colors will be created. /// - private void InitColorChart() + private static void InitColorChart() { lock (_colorChartMutex) { @@ -322,7 +322,7 @@ namespace Avalonia.Controls { if (_colorChart == null) { - InitColorChart(); + MaterialColorPalette.InitColorChart(); } return _colorChartColorCount; @@ -336,7 +336,7 @@ namespace Avalonia.Controls { if (_colorChart == null) { - InitColorChart(); + MaterialColorPalette.InitColorChart(); } return _colorChartShadeCount; @@ -348,7 +348,7 @@ namespace Avalonia.Controls { if (_colorChart == null) { - InitColorChart(); + MaterialColorPalette.InitColorChart(); } return _colorChart![ diff --git a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs index b662d20223..fab2b35969 100644 --- a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs +++ b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs @@ -121,7 +121,7 @@ namespace Avalonia.Controls.Primitives /// /// The to round component values for. /// A new with rounded component values. - private HsvColor RoundComponentValues(HsvColor hsvColor) + private static HsvColor RoundComponentValues(HsvColor hsvColor) { return new HsvColor( Math.Round(hsvColor.A, 2, MidpointRounding.AwayFromZero), @@ -147,7 +147,7 @@ namespace Avalonia.Controls.Primitives if (IsRoundingEnabled) { - hsvColor = RoundComponentValues(hsvColor); + hsvColor = ColorSlider.RoundComponentValues(hsvColor); } // Note: Components converted into a usable range for the user @@ -272,7 +272,7 @@ namespace Avalonia.Controls.Primitives if (IsRoundingEnabled) { - hsvColor = RoundComponentValues(hsvColor); + hsvColor = ColorSlider.RoundComponentValues(hsvColor); } return (rgbColor, hsvColor); diff --git a/src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs b/src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs index bd44161a42..1ff1445d8e 100644 --- a/src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs +++ b/src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs @@ -1027,7 +1027,7 @@ namespace Avalonia.Controls.Primitives { for (int y = pixelDimension - 1; y >= 0; --y) { - FillPixelForBox( + ColorSpectrum.FillPixelForBox( x, y, hsv, pixelDimension, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue, bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData, newHsvValues); @@ -1099,7 +1099,7 @@ namespace Avalonia.Controls.Primitives }); } - private void FillPixelForBox( + private static void FillPixelForBox( double x, double y, Hsv baseHsv, From b8b180f64c781d782e7f9a044210a5a0a2192fd9 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:09:38 +0200 Subject: [PATCH 015/137] feat(DataGrid): Address rule CA1822 --- src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs index 0e754d5815..023ae99266 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs @@ -56,7 +56,7 @@ namespace Avalonia.Controls set => SetAndRaise(CellEditingTemplateProperty, ref _cellEditingCellTemplate, value); } - private void OnCellTemplateChanged(AvaloniaPropertyChangedEventArgs e) + private static void OnCellTemplateChanged(AvaloniaPropertyChangedEventArgs e) { var oldValue = (IDataTemplate)e.OldValue; var value = (IDataTemplate)e.NewValue; From bf1f6f04399b2b4290e025d714741a435ea04b25 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:09:57 +0200 Subject: [PATCH 016/137] feat(Diagnostic): Address rule CA1822 --- .../Diagnostics/Screenshots/FilePickerHandler.cs | 4 ++-- .../Diagnostics/ViewModels/ControlDetailsViewModel.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs b/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs index 4153d2d38c..325c55783c 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs @@ -47,7 +47,7 @@ namespace Avalonia.Diagnostics.Screenshots /// public string Title { get; } = "Save Screenshot to ..."; - Window GetWindow(IControl control) + static Window GetWindow(IControl control) { var window = control.VisualRoot as Window; var app = Application.Current; @@ -61,7 +61,7 @@ namespace Avalonia.Diagnostics.Screenshots protected async override Task GetStream(IControl control) { Stream? output = default; - var result = await GetWindow(control).StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + var result = await FilePickerHandler.GetWindow(control).StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions { SuggestedStartLocation = new BclStorageFolder(new DirectoryInfo(ScreenshotsRoot)), Title = Title, diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs index 631da80d8b..869b2fd600 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs @@ -83,7 +83,7 @@ namespace Avalonia.Diagnostics.ViewModels { var setterValue = regularSetter.Value; - var resourceInfo = GetResourceInfo(setterValue); + var resourceInfo = ControlDetailsViewModel.GetResourceInfo(setterValue); SetterViewModel setterVm; @@ -122,7 +122,7 @@ namespace Avalonia.Diagnostics.ViewModels public bool CanNavigateToParentProperty => _selectedEntitiesStack.Count >= 1; - private (object resourceKey, bool isDynamic)? GetResourceInfo(object? value) + private static (object resourceKey, bool isDynamic)? GetResourceInfo(object? value) { if (value is StaticResourceExtension staticResource) { From e014c941447f4f2a2243a697cf62b4fa1e248202 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:10:13 +0200 Subject: [PATCH 017/137] feat(Dialogs): Address rule CA1822 --- src/Avalonia.Dialogs/ManagedStorageProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Dialogs/ManagedStorageProvider.cs b/src/Avalonia.Dialogs/ManagedStorageProvider.cs index 37d2781692..06c2c29dab 100644 --- a/src/Avalonia.Dialogs/ManagedStorageProvider.cs +++ b/src/Avalonia.Dialogs/ManagedStorageProvider.cs @@ -28,7 +28,7 @@ public class ManagedStorageProvider : BclStorageProvider where T : Window, ne public override async Task> OpenFilePickerAsync(FilePickerOpenOptions options) { var model = new ManagedFileChooserViewModel(options, _managedOptions); - var results = await Show(model, _parent); + var results = await ManagedStorageProvider.Show(model, _parent); return results.Select(f => new BclStorageFile(new FileInfo(f))).ToArray(); } @@ -36,7 +36,7 @@ public class ManagedStorageProvider : BclStorageProvider where T : Window, ne public override async Task SaveFilePickerAsync(FilePickerSaveOptions options) { var model = new ManagedFileChooserViewModel(options, _managedOptions); - var results = await Show(model, _parent); + var results = await ManagedStorageProvider.Show(model, _parent); return results.FirstOrDefault() is { } result ? new BclStorageFile(new FileInfo(result)) @@ -46,12 +46,12 @@ public class ManagedStorageProvider : BclStorageProvider where T : Window, ne public override async Task> OpenFolderPickerAsync(FolderPickerOpenOptions options) { var model = new ManagedFileChooserViewModel(options, _managedOptions); - var results = await Show(model, _parent); + var results = await ManagedStorageProvider.Show(model, _parent); return results.Select(f => new BclStorageFolder(new DirectoryInfo(f))).ToArray(); } - private async Task Show(ManagedFileChooserViewModel model, Window parent) + private static async Task Show(ManagedFileChooserViewModel model, Window parent) { var dialog = new T { From aa17cdf1dc5395e0184a2967450ba86e0f2ba7f5 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:10:42 +0200 Subject: [PATCH 018/137] feat(FreedDesktop): Address rule CA1822 --- src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs b/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs index 39ddd9d769..2d6a2569fb 100644 --- a/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs +++ b/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs @@ -34,7 +34,7 @@ namespace Avalonia.FreeDesktop Poll(0); } - private string GetSymlinkTarget(string x) => Path.GetFullPath(Path.Combine(DevByLabelDir, NativeMethods.ReadLink(x))); + private static string GetSymlinkTarget(string x) => Path.GetFullPath(Path.Combine(DevByLabelDir, NativeMethods.ReadLink(x))); private string UnescapeString(string input, string regexText, int escapeBase) => new Regex(regexText).Replace(input, m => Convert.ToChar(Convert.ToByte(m.Groups[1].Value, escapeBase)).ToString()); @@ -61,7 +61,7 @@ namespace Avalonia.FreeDesktop new DirectoryInfo(DevByLabelDir).GetFiles() : Enumerable.Empty(); var labelDevPathPairs = labelDirEnum - .Select(x => (GetSymlinkTarget(x.FullName), UnescapeDeviceLabel(x.Name))); + .Select(x => (LinuxMountedVolumeInfoListener.GetSymlinkTarget(x.FullName), UnescapeDeviceLabel(x.Name))); var q1 = from mount in fProcMounts join device in fProcPartitions on mount.Item1 equals device.Item2 From 3a9404171f4d8c8c4a0598403a9db04d776ba2a1 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:11:00 +0200 Subject: [PATCH 019/137] feat(Native): Address rule CA1822 --- src/Avalonia.Native/AvaloniaNativeDragSource.cs | 6 +++--- src/Avalonia.Native/AvaloniaNativeMenuExporter.cs | 4 ++-- src/Avalonia.Native/IAvnMenu.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Native/AvaloniaNativeDragSource.cs b/src/Avalonia.Native/AvaloniaNativeDragSource.cs index f91a299b3b..f93d558d25 100644 --- a/src/Avalonia.Native/AvaloniaNativeDragSource.cs +++ b/src/Avalonia.Native/AvaloniaNativeDragSource.cs @@ -19,8 +19,8 @@ namespace Avalonia.Native { _factory = factory; } - - TopLevel FindRoot(IInteractive interactive) + + static TopLevel FindRoot(IInteractive interactive) { while (interactive != null && !(interactive is IVisual)) interactive = interactive.InteractiveParent; @@ -48,7 +48,7 @@ namespace Avalonia.Native public Task DoDragDrop(PointerEventArgs triggerEvent, IDataObject data, DragDropEffects allowedEffects) { // Sanity check - var tl = FindRoot(triggerEvent.Source); + var tl = AvaloniaNativeDragSource.FindRoot(triggerEvent.Source); var view = tl?.PlatformImpl as WindowBaseImpl; if (view == null) throw new ArgumentException(); diff --git a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs index d8753efe25..ddabfe8f5d 100644 --- a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs +++ b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs @@ -65,7 +65,7 @@ namespace Avalonia.Native } } - private NativeMenu CreateDefaultAppMenu() + private static NativeMenu CreateDefaultAppMenu() { var result = new NativeMenu(); @@ -167,7 +167,7 @@ namespace Avalonia.Native if (appMenu == null) { - appMenu = CreateDefaultAppMenu(); + appMenu = AvaloniaNativeMenuExporter.CreateDefaultAppMenu(); NativeMenu.SetMenu(Application.Current, appMenu); } diff --git a/src/Avalonia.Native/IAvnMenu.cs b/src/Avalonia.Native/IAvnMenu.cs index e413023f6d..f75621865c 100644 --- a/src/Avalonia.Native/IAvnMenu.cs +++ b/src/Avalonia.Native/IAvnMenu.cs @@ -111,7 +111,7 @@ namespace Avalonia.Native.Interop.Impl private __MicroComIAvnMenuItemProxy CreateNewAt(IAvaloniaNativeFactory factory, int index, NativeMenuItemBase item) { - var result = CreateNew(factory, item); + var result = __MicroComIAvnMenuProxy.CreateNew(factory, item); result.Initialize(item); @@ -123,7 +123,7 @@ namespace Avalonia.Native.Interop.Impl return result; } - private __MicroComIAvnMenuItemProxy CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item) + private static __MicroComIAvnMenuItemProxy CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item) { var nativeItem = (__MicroComIAvnMenuItemProxy)(item is NativeMenuItemSeparator ? factory.CreateMenuItemSeparator() : From 713b85522f34cc768a31ecf0fd8f28410d0ec1f6 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:11:19 +0200 Subject: [PATCH 020/137] feat(OpenGL): Address rule CA1822 --- src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs b/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs index 279e7e750d..6f87ff19ee 100644 --- a/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs +++ b/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs @@ -27,7 +27,7 @@ namespace Avalonia.OpenGL.Controls _context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, _fb); EnsureTextureAttachment(); EnsureDepthBufferAttachment(_context.GlInterface); - if(!CheckFramebufferStatus(_context.GlInterface)) + if(!OpenGlControlBase.CheckFramebufferStatus(_context.GlInterface)) return; OnOpenGlRender(_context.GlInterface, _fb); @@ -38,7 +38,7 @@ namespace Avalonia.OpenGL.Controls base.Render(context); } - private void CheckError(GlInterface gl) + private static void CheckError(GlInterface gl) { int err; while ((err = gl.GetError()) != GL_NO_ERROR) @@ -186,7 +186,7 @@ namespace Avalonia.OpenGL.Controls EnsureDepthBufferAttachment(gl); EnsureTextureAttachment(); - return CheckFramebufferStatus(gl); + return OpenGlControlBase.CheckFramebufferStatus(gl); } catch(Exception e) { @@ -197,7 +197,7 @@ namespace Avalonia.OpenGL.Controls } } - private bool CheckFramebufferStatus(GlInterface gl) + private static bool CheckFramebufferStatus(GlInterface gl) { var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) From 5196ef2cbc559525051938e5714b8342771d6769 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:11:37 +0200 Subject: [PATCH 021/137] feat(Reactive): Address rule CA1822 --- .../AvaloniaActivationForViewFetcher.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs index 9f69b4ee6e..94073506e3 100644 --- a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs +++ b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs @@ -26,15 +26,15 @@ namespace Avalonia.ReactiveUI public IObservable GetActivationForView(IActivatableView view) { if (!(view is IVisual visual)) return Observable.Return(false); - if (view is Control control) return GetActivationForControl(control); - return GetActivationForVisual(visual); + if (view is Control control) return AvaloniaActivationForViewFetcher.GetActivationForControl(control); + return AvaloniaActivationForViewFetcher.GetActivationForVisual(visual); } /// /// Listens to Loaded and Unloaded /// events for Avalonia Control. /// - private IObservable GetActivationForControl(Control control) + private static IObservable GetActivationForControl(Control control) { var controlLoaded = Observable .FromEventPattern( @@ -55,7 +55,7 @@ namespace Avalonia.ReactiveUI /// Listens to AttachedToVisualTree and DetachedFromVisualTree /// events for Avalonia IVisuals. /// - private IObservable GetActivationForVisual(IVisual visual) + private static IObservable GetActivationForVisual(IVisual visual) { var visualLoaded = Observable .FromEventPattern( From a88ba2a16d1eecebb9177da5f8c41a0533068fa2 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:11:53 +0200 Subject: [PATCH 022/137] feat(X11): Address rule CA1822 --- src/Avalonia.X11/X11IconLoader.cs | 6 +++--- src/Avalonia.X11/X11Platform.cs | 10 +++++----- src/Avalonia.X11/X11Window.Ime.cs | 2 +- src/Avalonia.X11/X11Window.cs | 6 +++--- src/Avalonia.X11/XI2Manager.cs | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs index 632a7d39a2..de7c57a556 100644 --- a/src/Avalonia.X11/X11IconLoader.cs +++ b/src/Avalonia.X11/X11IconLoader.cs @@ -9,16 +9,16 @@ namespace Avalonia.X11 { class X11IconLoader : IPlatformIconLoader { - IWindowIconImpl LoadIcon(Bitmap bitmap) + static IWindowIconImpl LoadIcon(Bitmap bitmap) { var rv = new X11IconData(bitmap); bitmap.Dispose(); return rv; } - public IWindowIconImpl LoadIcon(string fileName) => LoadIcon(new Bitmap(fileName)); + public IWindowIconImpl LoadIcon(string fileName) => X11IconLoader.LoadIcon(new Bitmap(fileName)); - public IWindowIconImpl LoadIcon(Stream stream) => LoadIcon(new Bitmap(stream)); + public IWindowIconImpl LoadIcon(Stream stream) => X11IconLoader.LoadIcon(new Bitmap(stream)); public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) { diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 381cdd74c3..312945e713 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -42,10 +42,10 @@ namespace Avalonia.X11 Options = options; bool useXim = false; - if (EnableIme(options)) + if (AvaloniaX11Platform.EnableIme(options)) { // Attempt to configure DBus-based input method and check if we can fall back to XIM - if (!X11DBusImeHelper.DetectAndRegister() && ShouldUseXim()) + if (!X11DBusImeHelper.DetectAndRegister() && AvaloniaX11Platform.ShouldUseXim()) useXim = true; } @@ -143,7 +143,7 @@ namespace Avalonia.X11 throw new NotSupportedException(); } - bool EnableIme(X11PlatformOptions options) + static bool EnableIme(X11PlatformOptions options) { // Disable if explicitly asked by user var avaloniaImModule = Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE"); @@ -164,8 +164,8 @@ namespace Avalonia.X11 return isCjkLocale; } - - bool ShouldUseXim() + + static bool ShouldUseXim() { // Check if we are forbidden from using IME if (Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE") == "none" diff --git a/src/Avalonia.X11/X11Window.Ime.cs b/src/Avalonia.X11/X11Window.Ime.cs index d68feaca78..128d48957c 100644 --- a/src/Avalonia.X11/X11Window.Ime.cs +++ b/src/Avalonia.X11/X11Window.Ime.cs @@ -107,7 +107,7 @@ namespace Avalonia.X11 var filtered = ScheduleKeyInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), _inputRoot, ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, - X11KeyTransform.ConvertKey(key), TranslateModifiers(ev.KeyEvent.state)), ref ev, (int)key, ev.KeyEvent.keycode); + X11KeyTransform.ConvertKey(key), X11Window.TranslateModifiers(ev.KeyEvent.state)), ref ev, (int)key, ev.KeyEvent.keycode); if (ev.type == XEventName.KeyPress && !filtered) TriggerClassicTextInputEvent(ref ev); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index f24c33cafa..b2120b718e 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -463,7 +463,7 @@ namespace Avalonia.X11 : new Vector(-1, 0); ScheduleInput(new RawMouseWheelEventArgs(_mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), delta, - TranslateModifiers(ev.ButtonEvent.state)), ref ev); + X11Window.TranslateModifiers(ev.ButtonEvent.state)), ref ev); } } @@ -683,7 +683,7 @@ namespace Avalonia.X11 } - RawInputModifiers TranslateModifiers(XModifierMask state) + static RawInputModifiers TranslateModifiers(XModifierMask state) { var rv = default(RawInputModifiers); if (state.HasAllFlags(XModifierMask.Button1Mask)) @@ -760,7 +760,7 @@ namespace Avalonia.X11 { var mev = new RawPointerEventArgs( _mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, - type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), TranslateModifiers(mods)); + type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), X11Window.TranslateModifiers(mods)); ScheduleInput(mev, ref ev); } diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs index 7bf1df41b6..952112b6fd 100644 --- a/src/Avalonia.X11/XI2Manager.cs +++ b/src/Avalonia.X11/XI2Manager.cs @@ -193,11 +193,11 @@ namespace Avalonia.X11 { var rev = (XIEnterLeaveEvent*)xev; if (_clients.TryGetValue(rev->EventWindow, out var client)) - OnEnterLeaveEvent(client, ref *rev); + XI2Manager.OnEnterLeaveEvent(client, ref *rev); } } - void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev) + static void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev) { if (ev.evtype == XiEventType.XI_Leave) { From 93f0fcf007c1e51556f25fd292a97b4375c9a3fd Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:12:14 +0200 Subject: [PATCH 023/137] feat(iOS): Address rule CA1822 --- src/iOS/Avalonia.iOS/CombinedSpan3.cs | 2 +- src/iOS/Avalonia.iOS/TouchHandler.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/iOS/Avalonia.iOS/CombinedSpan3.cs b/src/iOS/Avalonia.iOS/CombinedSpan3.cs index e9f44b7d58..13faea1848 100644 --- a/src/iOS/Avalonia.iOS/CombinedSpan3.cs +++ b/src/iOS/Avalonia.iOS/CombinedSpan3.cs @@ -16,7 +16,7 @@ internal ref struct CombinedSpan3 public int Length => Span1.Length + Span2.Length + Span3.Length; - void CopyFromSpan(ReadOnlySpan from, int offset, ref Span to) + static void CopyFromSpan(ReadOnlySpan from, int offset, ref Span to) { if(to.Length == 0) return; diff --git a/src/iOS/Avalonia.iOS/TouchHandler.cs b/src/iOS/Avalonia.iOS/TouchHandler.cs index 959a660d8a..44bf08365f 100644 --- a/src/iOS/Avalonia.iOS/TouchHandler.cs +++ b/src/iOS/Avalonia.iOS/TouchHandler.cs @@ -19,7 +19,7 @@ namespace Avalonia.iOS _tl = tl; } - ulong Ts(UIEvent evt) => (ulong) (evt.Timestamp * 1000); + static ulong Ts(UIEvent evt) => (ulong) (evt.Timestamp * 1000); private IInputRoot Root => _view.InputRoot; private static long _nextTouchPointId = 1; private Dictionary _knownTouches = new Dictionary(); From 4800f7a01b666d962e2f5103ff39dce0e98fea18 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 14 Oct 2022 17:14:27 +0200 Subject: [PATCH 024/137] feat(Markup): Address rule CA1822 --- .../CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs | 6 ++---- .../Converters/AvaloniaPropertyTypeConverter.cs | 8 ++++---- .../Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs | 4 ++-- .../MarkupExtensions/DynamicResourceExtension.cs | 6 +++--- src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs | 2 +- .../Markup/Parsers/Nodes/StringIndexerNode.cs | 6 +++--- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 6c9d510ba0..12406df765 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -67,10 +67,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions string propertyName, IXamlAstTypeReference selectorTypeReference, IXamlLineInfo lineInfo) { XamlAstNamePropertyReference forgedReference; - - var parser = new PropertyParser(); - - var parsedPropertyName = parser.Parse(new CharacterReader(propertyName.AsSpan())); + + var parsedPropertyName = PropertyParser.Parse(new CharacterReader(propertyName.AsSpan())); if(parsedPropertyName.owner == null) forgedReference = new XamlAstNamePropertyReference(lineInfo, selectorTypeReference, propertyName, selectorTypeReference); diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs index 45ca1c4adc..dff315c727 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -22,8 +22,8 @@ namespace Avalonia.Markup.Xaml.Converters { var registry = AvaloniaPropertyRegistry.Instance; var parser = new PropertyParser(); - var (ns, owner, propertyName) = parser.Parse(new CharacterReader(((string)value).AsSpan())); - var ownerType = TryResolveOwnerByName(context, ns, owner); + var (ns, owner, propertyName) = PropertyParser.Parse(new CharacterReader(((string)value).AsSpan())); + var ownerType = AvaloniaPropertyTypeConverter.TryResolveOwnerByName(context, ns, owner); var targetType = context.GetFirstParent()?.TargetType ?? context.GetFirstParent"; - using (StartWithResources(("test:style.xaml", styleXaml))) + using (StyleIncludeTests.StartWithResources(("test:style.xaml", styleXaml))) { var xaml = @" new Styles { - WindowStyle(), + ResourceDictionaryTests.WindowStyle(), }); return UnitTestApplication.Start(services); } - private Style WindowStyle() + private static Style WindowStyle() { return new Style(x => x.OfType()) { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index 77a4932ccc..b164f6c371 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -162,7 +162,7 @@ namespace Avalonia.Markup.Xaml.UnitTests } - void AssertThrows(Action callback, Func check) + static void AssertThrows(Action callback, Func check) { try { @@ -182,7 +182,7 @@ namespace Avalonia.Markup.Xaml.UnitTests public void Bug2570() { SomeStaticProperty = "123"; - AssertThrows(() => AvaloniaRuntimeXamlLoader + XamlIlTests.AssertThrows(() => AvaloniaRuntimeXamlLoader .Load(@" (child); } - private FuncControlTemplate GetTemplate() + private static FuncControlTemplate GetTemplate() { return new FuncControlTemplate((parent, scope) => { diff --git a/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs b/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs index 06e46c1a06..f6e7ba0c48 100644 --- a/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs +++ b/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs @@ -17,7 +17,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media { } - private GeometryDrawing CreateGeometryDrawing() + private static GeometryDrawing CreateGeometryDrawing() { GeometryDrawing geometryDrawing = new GeometryDrawing(); EllipseGeometry ellipse = new EllipseGeometry(); diff --git a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs index b668f4d39e..f921d9fa64 100644 --- a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs @@ -39,7 +39,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media { } - private TextLayout Create(string text, + private static TextLayout Create(string text, string fontFamily, double fontSize, FontStyle fontStyle, @@ -56,7 +56,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media return formattedText; } - private TextLayout Create(string text, double fontSize) + private static TextLayout Create(string text, double fontSize) { return Create(text, FontName, fontSize, FontStyle.Normal, TextAlignment.Left, @@ -64,7 +64,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media -1); } - private TextLayout Create(string text, double fontSize, TextAlignment alignment, double widthConstraint) + private static TextLayout Create(string text, double fontSize, TextAlignment alignment, double widthConstraint) { return Create(text, FontName, fontSize, FontStyle.Normal, alignment, @@ -72,7 +72,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media widthConstraint); } - private TextLayout Create(string text, double fontSize, TextWrapping wrap, double widthConstraint) + private static TextLayout Create(string text, double fontSize, TextWrapping wrap, double widthConstraint) { return Create(text, FontName, fontSize, FontStyle.Normal, TextAlignment.Left, diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index 4d6b313ffc..3f918e2a73 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -237,7 +237,7 @@ namespace Avalonia.Direct2D1.RenderTests return Math.Sqrt(meanSquaresError); } - private string GetTestsDirectory() + private static string GetTestsDirectory() { var path = Directory.GetCurrentDirectory(); diff --git a/tests/Avalonia.Skia.UnitTests/DrawingContextImplTests.cs b/tests/Avalonia.Skia.UnitTests/DrawingContextImplTests.cs index df0cc2fc1a..68595a2f57 100644 --- a/tests/Avalonia.Skia.UnitTests/DrawingContextImplTests.cs +++ b/tests/Avalonia.Skia.UnitTests/DrawingContextImplTests.cs @@ -21,7 +21,7 @@ namespace Avalonia.Skia.UnitTests target.DrawRectangle(Brushes.Black, new Pen(Brushes.Black, 0), new RoundedRect(new Rect(0, 0, 100, 100), new CornerRadius(4))); } - private DrawingContextImpl CreateTarget() + private static DrawingContextImpl CreateTarget() { var canvas = new SKCanvas(new SKBitmap(100, 100)); return (DrawingContextImpl)DrawingContextHelper.WrapSkiaCanvas(canvas, new Vector(96, 96)); From 9e1ff3e3be9a855220153ba72a0dd991e41de19b Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 17 Oct 2022 16:38:15 +0200 Subject: [PATCH 029/137] fix: Addreaa review --- .../Animators/GradientBrushAnimator.cs | 6 +++--- src/Avalonia.Base/Animation/KeySpline.cs | 6 +++--- src/Avalonia.Base/Controls/Classes.cs | 18 +++++++++--------- src/Avalonia.Base/Data/Core/ExpressionNode.cs | 2 +- .../Parsers/ExpressionVisitorNodeBuilder.cs | 6 +++--- .../Plugins/DataAnnotationsValidationPlugin.cs | 2 +- .../Data/Core/Plugins/IndeiValidationPlugin.cs | 2 +- .../Data/Core/Plugins/TaskStreamPlugin.cs | 4 ++-- src/Avalonia.Base/Input/DragDropDevice.cs | 12 ++++++------ src/Avalonia.Base/Input/KeyGesture.cs | 2 +- src/Avalonia.Base/Input/KeyboardDevice.cs | 4 ++-- src/Avalonia.Base/Input/MouseDevice.cs | 11 ++++------- src/Avalonia.Base/Input/PenDevice.cs | 2 +- src/Avalonia.Base/Input/Pointer.cs | 4 ++-- src/Avalonia.Base/Input/TouchDevice.cs | 6 +++--- src/Avalonia.Base/Layout/AttachedLayout.cs | 8 ++++---- src/Avalonia.Base/Layout/StackLayout.cs | 8 ++++---- src/Avalonia.Base/Layout/UniformGridLayout.cs | 6 +++--- src/Avalonia.Base/Platform/AssetLoader.cs | 8 ++++---- .../Composition/CompositingRenderer.cs | 4 ++-- .../Rendering/Composition/CompositionTarget.cs | 6 +++--- .../Automation/Peers/ComboBoxAutomationPeer.cs | 6 +++--- .../CalendarBlackoutDatesCollection.cs | 8 ++++---- .../Calendar/SelectedDatesCollection.cs | 9 ++++----- src/Avalonia.Controls/ComboBox.cs | 14 +++++++------- .../DateTimePickers/DateTimePickerPanel.cs | 4 ++-- src/Avalonia.Controls/Grid.cs | 10 +++++----- src/Avalonia.Controls/GridSplitter.cs | 14 +++++++------- .../Platform/InProcessDragSource.cs | 4 ++-- .../Presenters/ScrollContentPresenter.cs | 8 ++++---- .../Primitives/AdornerLayer.cs | 8 ++++---- src/Avalonia.Controls/Primitives/Popup.cs | 6 ++---- src/Avalonia.Controls/Repeater/RecyclePool.cs | 4 ++-- .../Repeater/RecyclingElementFactory.cs | 6 +++--- src/Avalonia.Controls/SplitView.cs | 9 +++------ src/Avalonia.Controls/TextBox.cs | 9 ++++----- src/Avalonia.Controls/TopLevel.cs | 2 +- src/Avalonia.Controls/TreeView.cs | 6 ++---- .../Screenshots/FilePickerHandler.cs | 2 +- .../ViewModels/ControlDetailsViewModel.cs | 16 ++++++++-------- .../LinuxMountedVolumeInfoListener.cs | 8 ++++---- .../AvaloniaNativeDragSource.cs | 2 +- .../AvaloniaNativeMenuExporter.cs | 2 +- src/Avalonia.Native/IAvnMenu.cs | 3 +-- .../Controls/OpenGlControlBase.cs | 4 ++-- .../AvaloniaActivationForViewFetcher.cs | 4 ++-- src/Avalonia.X11/X11IconLoader.cs | 4 ++-- src/Avalonia.X11/X11Platform.cs | 7 +++---- src/Avalonia.X11/X11Window.Ime.cs | 3 +-- src/Avalonia.X11/X11Window.cs | 6 ++---- src/Avalonia.X11/XI2Manager.cs | 2 +- .../XamlIlAvaloniaPropertyHelper.cs | 2 -- .../Converters/IconTypeConverter.cs | 2 +- .../DynamicResourceExtension.cs | 4 ++-- .../Parsers/PropertyParser.cs | 4 +--- .../Markup/Parsers/Nodes/StringIndexerNode.cs | 8 ++++---- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 4 ++-- src/Windows/Avalonia.Win32/ClipboardImpl.cs | 6 +++--- src/Windows/Avalonia.Win32/CursorFactory.cs | 2 +- src/Windows/Avalonia.Win32/DataObject.cs | 8 ++++---- .../CompositionGenerator/Generator.cs | 2 +- 61 files changed, 169 insertions(+), 190 deletions(-) diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs index f469ea5652..068c190fa1 100644 --- a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs @@ -28,7 +28,7 @@ namespace Avalonia.Animation.Animators { case IRadialGradientBrush oldRadial when newValue is IRadialGradientBrush newRadial: return new ImmutableRadialGradientBrush( - GradientBrushAnimator.InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), + InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), @@ -39,7 +39,7 @@ namespace Avalonia.Animation.Animators case IConicGradientBrush oldConic when newValue is IConicGradientBrush newConic: return new ImmutableConicGradientBrush( - GradientBrushAnimator.InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), + InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), @@ -49,7 +49,7 @@ namespace Avalonia.Animation.Animators case ILinearGradientBrush oldLinear when newValue is ILinearGradientBrush newLinear: return new ImmutableLinearGradientBrush( - GradientBrushAnimator.InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), + InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), diff --git a/src/Avalonia.Base/Animation/KeySpline.cs b/src/Avalonia.Base/Animation/KeySpline.cs index b33cd6b881..6ca5b2e759 100644 --- a/src/Avalonia.Base/Animation/KeySpline.cs +++ b/src/Avalonia.Base/Animation/KeySpline.cs @@ -98,7 +98,7 @@ namespace Avalonia.Animation get => _controlPointX1; set { - if (KeySpline.IsValidXValue(value)) + if (IsValidXValue(value)) { _controlPointX1 = value; _isDirty = true; @@ -131,7 +131,7 @@ namespace Avalonia.Animation get => _controlPointX2; set { - if (KeySpline.IsValidXValue(value)) + if (IsValidXValue(value)) { _controlPointX2 = value; _isDirty = true; @@ -188,7 +188,7 @@ namespace Avalonia.Animation /// acceptable range; false otherwise. public bool IsValid() { - return KeySpline.IsValidXValue(_controlPointX1) && KeySpline.IsValidXValue(_controlPointX2); + return IsValidXValue(_controlPointX1) && IsValidXValue(_controlPointX2); } /// diff --git a/src/Avalonia.Base/Controls/Classes.cs b/src/Avalonia.Base/Controls/Classes.cs index 100c2b2a8f..04193cf3d9 100644 --- a/src/Avalonia.Base/Controls/Classes.cs +++ b/src/Avalonia.Base/Controls/Classes.cs @@ -37,7 +37,7 @@ namespace Avalonia.Controls /// The initial items. public Classes(params string[] items) : base(items) - { + { } /// @@ -63,7 +63,7 @@ namespace Avalonia.Controls /// public override void Add(string name) { - Classes.ThrowIfPseudoclass(name, "added"); + ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -87,7 +87,7 @@ namespace Avalonia.Controls foreach (var name in names) { - Classes.ThrowIfPseudoclass(name, "added"); + ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -127,7 +127,7 @@ namespace Avalonia.Controls /// public override void Insert(int index, string name) { - Classes.ThrowIfPseudoclass(name, "added"); + ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -152,7 +152,7 @@ namespace Avalonia.Controls foreach (var name in names) { - Classes.ThrowIfPseudoclass(name, "added"); + ThrowIfPseudoclass(name, "added"); if (!Contains(name)) { @@ -180,7 +180,7 @@ namespace Avalonia.Controls /// public override bool Remove(string name) { - Classes.ThrowIfPseudoclass(name, "removed"); + ThrowIfPseudoclass(name, "removed"); if (base.Remove(name)) { @@ -206,7 +206,7 @@ namespace Avalonia.Controls foreach (var name in names) { - Classes.ThrowIfPseudoclass(name, "removed"); + ThrowIfPseudoclass(name, "removed"); toRemove ??= new List(); @@ -232,7 +232,7 @@ namespace Avalonia.Controls public override void RemoveAt(int index) { var name = this[index]; - Classes.ThrowIfPseudoclass(name, "removed"); + ThrowIfPseudoclass(name, "removed"); base.RemoveAt(index); NotifyChanged(); } @@ -258,7 +258,7 @@ namespace Avalonia.Controls foreach (var name in source) { - Classes.ThrowIfPseudoclass(name, "added"); + ThrowIfPseudoclass(name, "added"); } foreach (var name in this) diff --git a/src/Avalonia.Base/Data/Core/ExpressionNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNode.cs index d1bc60541c..e4b833176c 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNode.cs @@ -138,7 +138,7 @@ namespace Avalonia.Data.Core if (target == null) { - ValueChanged(ExpressionNode.TargetNullNotification()); + ValueChanged(TargetNullNotification()); _listening = false; } else if (target != AvaloniaProperty.UnsetValue) diff --git a/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs b/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs index 9b9ddf2183..42aefb3f54 100644 --- a/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs +++ b/src/Avalonia.Base/Data/Core/Parsers/ExpressionVisitorNodeBuilder.cs @@ -70,7 +70,7 @@ namespace Avalonia.Data.Core.Parsers if (node.Indexer == AvaloniaObjectIndexer) { - var property = ExpressionVisitorNodeBuilder.GetArgumentExpressionValue(node.Arguments[0]); + var property = GetArgumentExpressionValue(node.Arguments[0]); Nodes.Add(new AvaloniaPropertyAccessorNode(property, _enableDataValidation)); } else @@ -162,7 +162,7 @@ namespace Avalonia.Data.Core.Parsers if (node.Method == CreateDelegateMethod) { var visited = Visit(node.Arguments[1]); - Nodes.Add(new PropertyAccessorNode(ExpressionVisitorNodeBuilder.GetArgumentExpressionValue(node.Object!).Name, _enableDataValidation)); + Nodes.Add(new PropertyAccessorNode(GetArgumentExpressionValue(node.Object!).Name, _enableDataValidation)); return node; } else if (node.Method.Name == StreamBindingExtensions.StreamBindingName || node.Method.Name.StartsWith(StreamBindingExtensions.StreamBindingName + '`')) @@ -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}'."); } - private PropertyInfo? TryGetPropertyFromMethod(MethodInfo method) + private static PropertyInfo? TryGetPropertyFromMethod(MethodInfo method) { var type = method.DeclaringType; return type?.GetRuntimeProperties().FirstOrDefault(prop => prop.GetMethod == method); diff --git a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs index 54d5b5ac28..118b18c020 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs @@ -57,7 +57,7 @@ namespace Avalonia.Data.Core.Plugins else { base.InnerValueChanged(new BindingNotification( - Accessor.CreateException(errors), + CreateException(errors), BindingErrorType.DataValidationError, value)); } diff --git a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs index e45170ff7e..385d96a7b8 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs @@ -92,7 +92,7 @@ namespace Avalonia.Data.Core.Plugins if (errors?.Count > 0) { return new BindingNotification( - Validator.GenerateException(errors), + GenerateException(errors), BindingErrorType.DataValidationError, value); } diff --git a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs index b25d592597..6703d1f54e 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs @@ -44,11 +44,11 @@ namespace Avalonia.Data.Core.Plugins { case TaskStatus.RanToCompletion: case TaskStatus.Faulted: - return TaskStreamPlugin.HandleCompleted(task); + return HandleCompleted(task); default: var subject = new Subject(); task.ContinueWith( - x => TaskStreamPlugin.HandleCompleted(task).Subscribe(subject), + x => HandleCompleted(task).Subscribe(subject), TaskScheduler.FromCurrentSynchronizationContext()) .ConfigureAwait(false); return subject; diff --git a/src/Avalonia.Base/Input/DragDropDevice.cs b/src/Avalonia.Base/Input/DragDropDevice.cs index 16ff428d69..ef4c7f8787 100644 --- a/src/Avalonia.Base/Input/DragDropDevice.cs +++ b/src/Avalonia.Base/Input/DragDropDevice.cs @@ -40,22 +40,22 @@ namespace Avalonia.Input private DragDropEffects DragEnter(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, KeyModifiers modifiers) { - _lastTarget = DragDropDevice.GetTarget(inputRoot, point); - return DragDropDevice.RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); + _lastTarget = GetTarget(inputRoot, point); + return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } private DragDropEffects DragOver(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, KeyModifiers modifiers) { - var target = DragDropDevice.GetTarget(inputRoot, point); + var target = GetTarget(inputRoot, point); if (target == _lastTarget) - return DragDropDevice.RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data, modifiers); + return RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data, modifiers); try { if (_lastTarget != null) _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); - return DragDropDevice.RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); + return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } finally { @@ -81,7 +81,7 @@ namespace Avalonia.Input { try { - return DragDropDevice.RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data, modifiers); + return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data, modifiers); } finally { diff --git a/src/Avalonia.Base/Input/KeyGesture.cs b/src/Avalonia.Base/Input/KeyGesture.cs index 7f4f69590a..b08f5d0ba5 100644 --- a/src/Avalonia.Base/Input/KeyGesture.cs +++ b/src/Avalonia.Base/Input/KeyGesture.cs @@ -138,7 +138,7 @@ namespace Avalonia.Input public bool Matches(KeyEventArgs keyEvent) => keyEvent != null && keyEvent.KeyModifiers == KeyModifiers && - KeyGesture.ResolveNumPadOperationKey(keyEvent.Key) == KeyGesture.ResolveNumPadOperationKey(Key); + ResolveNumPadOperationKey(keyEvent.Key) == ResolveNumPadOperationKey(Key); // TODO: Move that to external key parser private static Key ParseKey(string key) diff --git a/src/Avalonia.Base/Input/KeyboardDevice.cs b/src/Avalonia.Base/Input/KeyboardDevice.cs index 0600b54618..68d09ea19a 100644 --- a/src/Avalonia.Base/Input/KeyboardDevice.cs +++ b/src/Avalonia.Base/Input/KeyboardDevice.cs @@ -26,7 +26,7 @@ namespace Avalonia.Input public IInputElement? FocusedElement => _focusedElement; - private void ClearFocusWithinAncestors(IInputElement? element) + private static void ClearFocusWithinAncestors(IInputElement? element) { var el = element; @@ -65,7 +65,7 @@ namespace Avalonia.Input { if (newElement == null && oldElement != null) { - ClearFocusWithinAncestors(oldElement); + KeyboardDevice.ClearFocusWithinAncestors(oldElement); return; } diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index 6fb34efdb5..a7540b5afa 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -1,12 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Reactive.Linq; using Avalonia.Input.Raw; -using Avalonia.Interactivity; using Avalonia.Platform; using Avalonia.Utilities; -using Avalonia.VisualTree; namespace Avalonia.Input { @@ -71,7 +67,7 @@ namespace Avalonia.Input case RawPointerEventType.MiddleButtonDown: case RawPointerEventType.XButton1Down: case RawPointerEventType.XButton2Down: - if (MouseDevice.ButtonCount(props) > 1) + if (ButtonCount(props) > 1) e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult); else e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult); @@ -81,7 +77,7 @@ namespace Avalonia.Input case RawPointerEventType.MiddleButtonUp: case RawPointerEventType.XButton1Up: case RawPointerEventType.XButton2Up: - if (MouseDevice.ButtonCount(props) != 0) + if (ButtonCount(props) != 0) e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult); else e.Handled = MouseUp(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult); @@ -106,9 +102,10 @@ namespace Avalonia.Input private void LeaveWindow() { + } - PointerPointProperties CreateProperties(RawPointerEventArgs args) + static PointerPointProperties CreateProperties(RawPointerEventArgs args) { return new PointerPointProperties(args.InputModifiers, args.Type.ToUpdateKind()); } diff --git a/src/Avalonia.Base/Input/PenDevice.cs b/src/Avalonia.Base/Input/PenDevice.cs index 876be42be8..b530364fc1 100644 --- a/src/Avalonia.Base/Input/PenDevice.cs +++ b/src/Avalonia.Base/Input/PenDevice.cs @@ -56,7 +56,7 @@ namespace Avalonia.Input e.Handled = PenUp(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult); break; case RawPointerEventType.Move: - e.Handled = PenDevice.PenMove(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult, e.IntermediatePoints); + e.Handled = PenMove(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult, e.IntermediatePoints); break; } diff --git a/src/Avalonia.Base/Input/Pointer.cs b/src/Avalonia.Base/Input/Pointer.cs index be93d9d6b8..7948939d41 100644 --- a/src/Avalonia.Base/Input/Pointer.cs +++ b/src/Avalonia.Base/Input/Pointer.cs @@ -41,7 +41,7 @@ namespace Avalonia.Input PlatformCapture(control); if (oldCapture != null) { - var commonParent = Pointer.FindCommonParent(control, oldCapture); + var commonParent = FindCommonParent(control, oldCapture); foreach (var notifyTarget in oldCapture.GetSelfAndVisualAncestors().OfType()) { if (notifyTarget == commonParent) @@ -54,7 +54,7 @@ namespace Avalonia.Input Captured.DetachedFromVisualTree += OnCaptureDetached; } - IInputElement? GetNextCapture(IVisual parent) + static IInputElement? GetNextCapture(IVisual parent) { return parent as IInputElement ?? parent.FindAncestorOfType(); } diff --git a/src/Avalonia.Base/Input/TouchDevice.cs b/src/Avalonia.Base/Input/TouchDevice.cs index b709b7d0cd..35c7555784 100644 --- a/src/Avalonia.Base/Input/TouchDevice.cs +++ b/src/Avalonia.Base/Input/TouchDevice.cs @@ -73,7 +73,7 @@ namespace Avalonia.Input target.RaiseEvent(new PointerPressedEventArgs(target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(TouchDevice.GetModifiers(args.InputModifiers, true), updateKind), + new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind), keyModifier, _clickCount)); } @@ -84,7 +84,7 @@ namespace Avalonia.Input { target.RaiseEvent(new PointerReleasedEventArgs(target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(TouchDevice.GetModifiers(args.InputModifiers, false), updateKind), + new PointerPointProperties(GetModifiers(args.InputModifiers, false), updateKind), keyModifier, MouseButton.Left)); } } @@ -100,7 +100,7 @@ namespace Avalonia.Input { target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(TouchDevice.GetModifiers(args.InputModifiers, true), updateKind), + new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind), keyModifier, args.IntermediatePoints)); } } diff --git a/src/Avalonia.Base/Layout/AttachedLayout.cs b/src/Avalonia.Base/Layout/AttachedLayout.cs index 594fc04842..ac3a53dabb 100644 --- a/src/Avalonia.Base/Layout/AttachedLayout.cs +++ b/src/Avalonia.Base/Layout/AttachedLayout.cs @@ -67,7 +67,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); + var virtualizingContext = GetVirtualizingLayoutContext(context); virtualizingLayout.InitializeForContextCore(virtualizingContext); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -92,7 +92,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); + var virtualizingContext = GetVirtualizingLayoutContext(context); virtualizingLayout.UninitializeForContextCore(virtualizingContext); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -126,7 +126,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); + var virtualizingContext = GetVirtualizingLayoutContext(context); return virtualizingLayout.MeasureOverride(virtualizingContext, availableSize); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) @@ -157,7 +157,7 @@ namespace Avalonia.Layout { if (this is VirtualizingLayout virtualizingLayout) { - var virtualizingContext = AttachedLayout.GetVirtualizingLayoutContext(context); + var virtualizingContext = GetVirtualizingLayoutContext(context); return virtualizingLayout.ArrangeOverride(virtualizingContext, finalSize); } else if (this is NonVirtualizingLayout nonVirtualizingLayout) diff --git a/src/Avalonia.Base/Layout/StackLayout.cs b/src/Avalonia.Base/Layout/StackLayout.cs index 7983b37843..d36667a7f2 100644 --- a/src/Avalonia.Base/Layout/StackLayout.cs +++ b/src/Avalonia.Base/Layout/StackLayout.cs @@ -90,7 +90,7 @@ namespace Avalonia.Layout // Constants int itemsCount = context.ItemCount; var stackState = (StackLayoutState)context.LayoutState!; - double averageElementSize = StackLayout.GetAverageElementSize(availableSize, context, stackState) + Spacing; + double averageElementSize = GetAverageElementSize(availableSize, context, stackState) + Spacing; _orientation.SetMinorSize(ref extent, stackState.MaxArrangeBounds); _orientation.SetMajorSize(ref extent, Math.Max(0.0f, itemsCount * averageElementSize - Spacing)); @@ -178,7 +178,7 @@ namespace Avalonia.Layout { index = targetIndex; var state = (StackLayoutState)context.LayoutState!; - double averageElementSize = StackLayout.GetAverageElementSize(availableSize, context, state) + Spacing; + double averageElementSize = GetAverageElementSize(availableSize, context, state) + Spacing; offset = index * averageElementSize + _orientation.MajorStart(state.FlowAlgorithm.LastExtent); } @@ -237,7 +237,7 @@ namespace Avalonia.Layout var state = (StackLayoutState)context.LayoutState!; var lastExtent = state.FlowAlgorithm.LastExtent; - double averageElementSize = StackLayout.GetAverageElementSize(availableSize, context, state) + Spacing; + double averageElementSize = GetAverageElementSize(availableSize, context, state) + Spacing; double realizationWindowOffsetInExtent = _orientation.MajorStart(realizationRect) - _orientation.MajorStart(lastExtent); double majorSize = _orientation.MajorSize(lastExtent) == 0 ? Math.Max(0.0, averageElementSize * itemsCount - Spacing) : _orientation.MajorSize(lastExtent); if (itemsCount > 0 && @@ -359,6 +359,6 @@ namespace Avalonia.Layout private void InvalidateLayout() => InvalidateMeasure(); - private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((StackLayoutState)context.LayoutState!).FlowAlgorithm; + private static FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((StackLayoutState)context.LayoutState!).FlowAlgorithm; } } diff --git a/src/Avalonia.Base/Layout/UniformGridLayout.cs b/src/Avalonia.Base/Layout/UniformGridLayout.cs index acb333bcfa..407d115bcd 100644 --- a/src/Avalonia.Base/Layout/UniformGridLayout.cs +++ b/src/Avalonia.Base/Layout/UniformGridLayout.cs @@ -432,7 +432,7 @@ namespace Avalonia.Layout var gridState = (UniformGridLayoutState)context.LayoutState!; gridState.EnsureElementSize(availableSize, context, _minItemWidth, _minItemHeight, _itemsStretch, Orientation, MinRowSpacing, MinColumnSpacing, _maximumRowsOrColumns); - var desiredSize = UniformGridLayout.GetFlowAlgorithm(context).Measure( + var desiredSize = GetFlowAlgorithm(context).Measure( availableSize, context, true, @@ -452,7 +452,7 @@ namespace Avalonia.Layout protected internal override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { - var value = UniformGridLayout.GetFlowAlgorithm(context).Arrange( + var value = GetFlowAlgorithm(context).Arrange( finalSize, context, true, @@ -463,7 +463,7 @@ namespace Avalonia.Layout protected internal override void OnItemsChangedCore(VirtualizingLayoutContext context, object? source, NotifyCollectionChangedEventArgs args) { - UniformGridLayout.GetFlowAlgorithm(context).OnItemsSourceChanged(source, args, context); + GetFlowAlgorithm(context).OnItemsSourceChanged(source, args, context); // Always invalidate layout to keep the view accurate. InvalidateLayout(); diff --git a/src/Avalonia.Base/Platform/AssetLoader.cs b/src/Avalonia.Base/Platform/AssetLoader.cs index 77ae9f4c32..a08e3b3d4c 100644 --- a/src/Avalonia.Base/Platform/AssetLoader.cs +++ b/src/Avalonia.Base/Platform/AssetLoader.cs @@ -126,7 +126,7 @@ namespace Avalonia.Platform uri = uri.EnsureAbsolute(baseUri); if (uri.IsAvares()) { - var (asm, path) = AssetLoader.GetResAsmAndPath(uri); + var (asm, path) = GetResAsmAndPath(uri); if (asm == null) { throw new ArgumentException( @@ -171,7 +171,7 @@ namespace Avalonia.Platform if (uri.IsAvares()) { - var (asm, path) = AssetLoader.GetResAsmAndPath(uri); + var (asm, path) = GetResAsmAndPath(uri); if (asm.AvaloniaResources == null) return null; asm.AvaloniaResources.TryGetValue(path, out var desc); @@ -187,14 +187,14 @@ namespace Avalonia.Platform return (asm, uri.GetUnescapeAbsolutePath()); } - private IAssemblyDescriptor? GetAssembly(Uri? uri) + private static IAssemblyDescriptor? GetAssembly(Uri? uri) { if (uri != null) { if (!uri.IsAbsoluteUri) return null; if (uri.IsAvares()) - return AssetLoader.GetResAsmAndPath(uri).asm; + return GetResAsmAndPath(uri).asm; if (uri.IsResm()) { diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index 3c9a9feac0..3f145c1539 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -233,11 +233,11 @@ public class CompositingRenderer : IRendererWithCompositor visual.Render(_recordingContext); comp.DrawList = _recorder.EndUpdate(); - CompositingRenderer.SyncChildren(visual); + SyncChildren(visual); } foreach(var v in _recalculateChildren) if (!_dirty.Contains(v)) - CompositingRenderer.SyncChildren(v); + SyncChildren(v); _dirty.Clear(); _recalculateChildren.Clear(); CompositionTarget.Size = _root.ClientSize; diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs index 52215e8011..0c24d6cd44 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs @@ -53,7 +53,7 @@ namespace Avalonia.Rendering.Composition var m = Matrix.Identity; while (v != null) { - if (!CompositionTarget.TryGetInvertedTransform(v, out var cm)) + if (!TryGetInvertedTransform(v, out var cm)) return null; m = m * cm; v = v.Parent; @@ -75,10 +75,10 @@ namespace Avalonia.Rendering.Composition 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; - if (CompositionTarget.TryGetInvertedTransform(visual, out var m)) + if (TryGetInvertedTransform(visual, out var m)) { v = globalPoint * m; return true; diff --git a/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs index d6295fdbd9..5d71e7a8e4 100644 --- a/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs @@ -18,7 +18,7 @@ namespace Avalonia.Automation.Peers public new ComboBox Owner => (ComboBox)base.Owner; - public ExpandCollapseState ExpandCollapseState => ComboBoxAutomationPeer.ToState(Owner.IsDropDownOpen); + public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsDropDownOpen); public bool ShowsMenu => true; public void Collapse() => Owner.IsDropDownOpen = false; public void Expand() => Owner.IsDropDownOpen = true; @@ -66,8 +66,8 @@ namespace Avalonia.Automation.Peers { RaisePropertyChangedEvent( ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, - ComboBoxAutomationPeer.ToState((bool)e.OldValue!), - ComboBoxAutomationPeer.ToState((bool)e.NewValue!)); + ToState((bool)e.OldValue!), + ToState((bool)e.NewValue!)); } } diff --git a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs index 61463795ee..fe8b616e02 100644 --- a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs +++ b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs @@ -122,7 +122,7 @@ namespace Avalonia.Controls.Primitives /// protected override void ClearItems() { - CalendarBlackoutDatesCollection.EnsureValidThread(); + EnsureValidThread(); base.ClearItems(); _owner.UpdateMonths(); @@ -140,7 +140,7 @@ namespace Avalonia.Controls.Primitives /// protected override void InsertItem(int index, CalendarDateRange item) { - CalendarBlackoutDatesCollection.EnsureValidThread(); + EnsureValidThread(); if (!IsValid(item)) { @@ -162,7 +162,7 @@ namespace Avalonia.Controls.Primitives /// protected override void RemoveItem(int index) { - CalendarBlackoutDatesCollection.EnsureValidThread(); + EnsureValidThread(); base.RemoveItem(index); _owner.UpdateMonths(); @@ -182,7 +182,7 @@ namespace Avalonia.Controls.Primitives /// protected override void SetItem(int index, CalendarDateRange item) { - CalendarBlackoutDatesCollection.EnsureValidThread(); + EnsureValidThread(); if (!IsValid(item)) { diff --git a/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs b/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs index 8327442fcf..ac4159d536 100644 --- a/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs +++ b/src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs @@ -6,7 +6,6 @@ using Avalonia.Threading; using System; using System.Collections.ObjectModel; -using System.Threading; namespace Avalonia.Controls.Primitives { @@ -133,7 +132,7 @@ namespace Avalonia.Controls.Primitives /// protected override void ClearItems() { - SelectedDatesCollection.EnsureValidThread(); + EnsureValidThread(); Collection addedItems = new Collection(); Collection removedItems = new Collection(); @@ -170,7 +169,7 @@ namespace Avalonia.Controls.Primitives /// protected override void InsertItem(int index, DateTime item) { - SelectedDatesCollection.EnsureValidThread(); + EnsureValidThread(); if (!Contains(item)) { @@ -233,7 +232,7 @@ namespace Avalonia.Controls.Primitives /// protected override void RemoveItem(int index) { - SelectedDatesCollection.EnsureValidThread(); + EnsureValidThread(); if (index >= Count) { @@ -284,7 +283,7 @@ namespace Avalonia.Controls.Primitives /// protected override void SetItem(int index, DateTime item) { - SelectedDatesCollection.EnsureValidThread(); + EnsureValidThread(); if (!Contains(item)) { diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 21918b27a8..1d849ce1e3 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -96,7 +96,7 @@ namespace Avalonia.Controls ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); FocusableProperty.OverrideDefaultValue(true); SelectedItemProperty.Changed.AddClassHandler((x, e) => x.SelectedItemChanged(e)); - KeyDownEvent.AddClassHandler((x, e) => x.OnKeyDown(e), Interactivity.RoutingStrategies.Tunnel); + KeyDownEvent.AddClassHandler((x, e) => x.OnKeyDown(e), RoutingStrategies.Tunnel); IsTextSearchEnabledProperty.OverrideDefaultValue(true); IsDropDownOpenProperty.Changed.AddClassHandler((x, e) => x.DropdownChanged(e)); } @@ -178,8 +178,8 @@ namespace Avalonia.Controls { return new ItemContainerGenerator( this, - ComboBoxItem.ContentProperty, - ComboBoxItem.ContentTemplateProperty); + ContentControl.ContentProperty, + ContentControl.ContentTemplateProperty); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) @@ -236,7 +236,7 @@ namespace Avalonia.Controls else if (IsDropDownOpen && SelectedIndex < 0 && ItemCount > 0 && (e.Key == Key.Up || e.Key == Key.Down) && IsFocused == true) { - var firstChild = Presenter?.Panel?.Children.FirstOrDefault(c => ComboBox.CanFocus(c)); + var firstChild = Presenter?.Panel?.Children.FirstOrDefault(c => CanFocus(c)); if (firstChild != null) { FocusManager.Instance?.Focus(firstChild, NavigationMethod.Directional); @@ -341,7 +341,7 @@ namespace Avalonia.Controls { _subscriptionsOnOpen.Clear(); - if (ComboBox.CanFocus(this)) + if (CanFocus(this)) { Focus(); } @@ -363,7 +363,7 @@ namespace Avalonia.Controls { ev.Handled = true; } - }, Interactivity.RoutingStrategies.Tunnel).DisposeWith(_subscriptionsOnOpen); + }, RoutingStrategies.Tunnel).DisposeWith(_subscriptionsOnOpen); } this.GetObservable(IsVisibleProperty).Subscribe(IsVisibleChanged).DisposeWith(_subscriptionsOnOpen); @@ -403,7 +403,7 @@ namespace Avalonia.Controls container = ItemContainerGenerator.ContainerFromIndex(selectedIndex); } - if (container != null && ComboBox.CanFocus(container)) + if (container != null && CanFocus(container)) { container.Focus(); } diff --git a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs index eb4a7391b0..faf0b6415a 100644 --- a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs +++ b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs @@ -455,7 +455,7 @@ namespace Avalonia.Controls.Primitives { Height = ItemHeight, Classes = new Classes($"{PanelType}Item"), - VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center, + VerticalContentAlignment = Layout.VerticalAlignment.Center, Focusable = false }); } @@ -546,7 +546,7 @@ namespace Avalonia.Controls.Primitives private void OnItemTapped(object? sender, TappedEventArgs e) { if (e.Source is IVisual source && - DateTimePickerPanel.GetItemFromSource(source) is ListBoxItem listBoxItem && + GetItemFromSource(source) is ListBoxItem listBoxItem && listBoxItem.Tag is int tag) { SelectedValue = tag; diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index 4dc88fec6a..7737fdac2e 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -1117,7 +1117,7 @@ namespace Avalonia.Controls else { // otherwise... - cellMeasureWidth = Grid.GetMeasureSizeForRange( + cellMeasureWidth = GetMeasureSizeForRange( DefinitionsU, PrivateCells[cell].ColumnIndex, PrivateCells[cell].ColumnSpan); @@ -1137,7 +1137,7 @@ namespace Avalonia.Controls } else { - cellMeasureHeight = Grid.GetMeasureSizeForRange( + cellMeasureHeight = GetMeasureSizeForRange( DefinitionsV, PrivateCells[cell].RowIndex, PrivateCells[cell].RowSpan); @@ -1192,7 +1192,7 @@ namespace Avalonia.Controls /// Starting index of the range. /// Number of definitions included in the range. /// Length type for given range. - private LayoutTimeSizeType GetLengthTypeForRange( + private static LayoutTimeSizeType GetLengthTypeForRange( IReadOnlyList definitions, int start, int count) @@ -1721,7 +1721,7 @@ namespace Avalonia.Controls /// /// Array of definitions to use for calculations. /// Desired size. - private double CalculateDesiredSize( + private static double CalculateDesiredSize( IReadOnlyList definitions) { double desiredSize = 0; @@ -2281,7 +2281,7 @@ namespace Avalonia.Controls /// Start of the range. /// Number of items in the range. /// Final size. - private double GetFinalSizeForRange( + private static double GetFinalSizeForRange( IReadOnlyList definitions, int start, int count) diff --git a/src/Avalonia.Controls/GridSplitter.cs b/src/Avalonia.Controls/GridSplitter.cs index 1a4736fa92..db8f038177 100644 --- a/src/Avalonia.Controls/GridSplitter.cs +++ b/src/Avalonia.Controls/GridSplitter.cs @@ -288,13 +288,13 @@ namespace Avalonia.Controls _resizeData.Definition1 = GetGridDefinition(_resizeData.Grid, index1, _resizeData.ResizeDirection); _resizeData.OriginalDefinition1Length = _resizeData.Definition1.UserSizeValueCache; // Save Size if user cancels. - _resizeData.OriginalDefinition1ActualLength = GridSplitter.GetActualLength(_resizeData.Definition1); + _resizeData.OriginalDefinition1ActualLength = GetActualLength(_resizeData.Definition1); _resizeData.Definition2Index = index2; _resizeData.Definition2 = GetGridDefinition(_resizeData.Grid, index2, _resizeData.ResizeDirection); _resizeData.OriginalDefinition2Length = _resizeData.Definition2.UserSizeValueCache; // Save Size if user cancels. - _resizeData.OriginalDefinition2ActualLength = GridSplitter.GetActualLength(_resizeData.Definition2); + _resizeData.OriginalDefinition2ActualLength = GetActualLength(_resizeData.Definition2); // Determine how to resize the columns. bool isStar1 = IsStar(_resizeData.Definition1); @@ -537,11 +537,11 @@ namespace Avalonia.Controls /// private void GetDeltaConstraints(out double minDelta, out double maxDelta) { - double definition1Len = GridSplitter.GetActualLength(_resizeData!.Definition1!); + double definition1Len = GetActualLength(_resizeData!.Definition1!); double definition1Min = _resizeData.Definition1!.UserMinSizeValueCache; double definition1Max = _resizeData.Definition1.UserMaxSizeValueCache; - double definition2Len = GridSplitter.GetActualLength(_resizeData.Definition2!); + double definition2Len = GetActualLength(_resizeData.Definition2!); double definition2Min = _resizeData.Definition2!.UserMinSizeValueCache; double definition2Max = _resizeData.Definition2.UserMaxSizeValueCache; @@ -590,7 +590,7 @@ namespace Avalonia.Controls } else if (IsStar(definition)) { - SetDefinitionLength(definition, new GridLength(GridSplitter.GetActualLength(definition), GridUnitType.Star)); + SetDefinitionLength(definition, new GridLength(GetActualLength(definition), GridUnitType.Star)); } } } @@ -629,8 +629,8 @@ namespace Avalonia.Controls if (definition1 != null && definition2 != null) { - double actualLength1 = GridSplitter.GetActualLength(definition1); - double actualLength2 = GridSplitter.GetActualLength(definition2); + double actualLength1 = GetActualLength(definition1); + double actualLength2 = GetActualLength(definition2); double pixelLength = 1 / _resizeData.Scaling; double epsilon = pixelLength + LayoutHelper.LayoutEpsilon; diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index e107d2c217..d0d4bcc8b4 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -64,7 +64,7 @@ namespace Avalonia.Platform var tl = root.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); tl?.PlatformImpl?.Input?.Invoke(rawEvent); - var effect = InProcessDragSource.GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers); + var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers); UpdateCursor(root, effect); return effect; } @@ -80,7 +80,7 @@ namespace Avalonia.Platform return DragDropEffects.Move; } - private StandardCursorType GetCursorForDropEffect(DragDropEffects effects) + private static StandardCursorType GetCursorForDropEffect(DragDropEffects effects) { if (effects.HasAllFlags(DragDropEffects.Copy)) return StandardCursorType.DragCopy; diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs index e5bf924120..2a35fd2a12 100644 --- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs @@ -295,7 +295,7 @@ namespace Avalonia.Controls.Presenters // arrange then that change wasn't just due to scrolling (as scrolling doesn't adjust // relative positions within Child). if (_anchorElement != null && - ScrollContentPresenter.TranslateBounds(_anchorElement, Child!, out var updatedBounds) && + TranslateBounds(_anchorElement, Child!, out var updatedBounds) && updatedBounds.Position != _anchorElementBounds.Position) { var offset = updatedBounds.Position - _anchorElementBounds.Position; @@ -588,7 +588,7 @@ namespace Avalonia.Controls.Presenters private bool GetViewportBounds(IControl element, out Rect bounds) { - if (ScrollContentPresenter.TranslateBounds(element, Child!, out var childBounds)) + if (TranslateBounds(element, Child!, out var childBounds)) { // We want the bounds relative to the new Offset, regardless of whether the child // control has actually been arranged to this offset yet, so translate first to the @@ -603,9 +603,9 @@ namespace Avalonia.Controls.Presenters return false; } - private Rect TranslateBounds(IControl control, IControl to) + private static Rect TranslateBounds(IControl control, IControl to) { - if (ScrollContentPresenter.TranslateBounds(control, to, out var bounds)) + if (TranslateBounds(control, to, out var bounds)) { return bounds; } diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index 12a17b8c9f..b681b43ce3 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -139,7 +139,7 @@ namespace Avalonia.Controls.Primitives private static void Attach(Visual visual, Control adorner) { - var layer = AdornerLayer.GetAdornerLayer(visual); + var layer = GetAdornerLayer(visual); AddVisualAdorner(visual, adorner, layer); visual.SetValue(s_savedAdornerLayerProperty, layer); } @@ -158,8 +158,8 @@ namespace Avalonia.Controls.Primitives return; } - AdornerLayer.SetAdornedElement(adorner, visual); - AdornerLayer.SetIsClipEnabled(adorner, false); + SetAdornedElement(adorner, visual); + SetIsClipEnabled(adorner, false); ((ISetLogicalParent) adorner).SetParent(visual); layer.Children.Add(adorner); @@ -211,7 +211,7 @@ namespace Avalonia.Controls.Primitives { child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform); child.RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Absolute); - AdornerLayer.UpdateClip(child, info.Bounds.Value, isClipEnabled); + UpdateClip(child, info.Bounds.Value, isClipEnabled); child.Arrange(info.Bounds.Value.Bounds); } else diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 581a65f6b9..4fc58d5462 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using System.Linq; using System.Reactive.Disposables; using Avalonia.Automation.Peers; using Avalonia.Controls.Mixins; @@ -15,7 +14,6 @@ using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.VisualTree; using Avalonia.Media; -using Avalonia.Utilities; namespace Avalonia.Controls.Primitives { @@ -475,7 +473,7 @@ namespace Avalonia.Controls.Primitives _openState = new PopupOpenState(placementTarget, topLevel, popupHost, cleanupPopup); - Popup.WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint); + WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint); popupHost.Show(); @@ -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 && layer.GetVisualRoot() is IInputElement root) diff --git a/src/Avalonia.Controls/Repeater/RecyclePool.cs b/src/Avalonia.Controls/Repeater/RecyclePool.cs index 9d6ad37721..0c19a883df 100644 --- a/src/Avalonia.Controls/Repeater/RecyclePool.cs +++ b/src/Avalonia.Controls/Repeater/RecyclePool.cs @@ -32,7 +32,7 @@ namespace Avalonia.Controls public void PutElement(IControl element, string key, IControl? owner) { - var ownerAsPanel = RecyclePool.EnsureOwnerIsPanelOrNull(owner); + var ownerAsPanel = EnsureOwnerIsPanelOrNull(owner); var elementInfo = new ElementInfo(element, ownerAsPanel); if (!_elements.TryGetValue(key, out var pool)) @@ -56,7 +56,7 @@ namespace Avalonia.Controls var elementInfo = elements.FirstOrDefault(x => x.Owner == owner) ?? elements.LastOrDefault(); elements.Remove(elementInfo!); - var ownerAsPanel = RecyclePool.EnsureOwnerIsPanelOrNull(owner); + var ownerAsPanel = EnsureOwnerIsPanelOrNull(owner); if (elementInfo!.Owner != null && elementInfo.Owner != ownerAsPanel) { // Element is still under its parent. remove it from its parent. diff --git a/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs b/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs index 1258c58324..7d09155ea4 100644 --- a/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs +++ b/src/Avalonia.Controls/Repeater/RecyclingElementFactory.cs @@ -72,7 +72,7 @@ namespace Avalonia.Controls element = dataTemplate.Build(args.Data)!; // Associate ReuseKey with element - Avalonia.Controls.RecyclePool.SetReuseKey(element, templateKey); + RecyclePool.SetReuseKey(element, templateKey); } return element; @@ -81,13 +81,13 @@ namespace Avalonia.Controls protected override void RecycleElementCore(ElementFactoryRecycleArgs args) { var element = args.Element!; - var key = Avalonia.Controls.RecyclePool.GetReuseKey(element); + var key = RecyclePool.GetReuseKey(element); RecyclePool.PutElement(element, key, args.Parent); } protected virtual string OnSelectTemplateKeyCore(object? dataContext, IControl? owner) { - if (SelectTemplateKey is object) + if (SelectTemplateKey is not null) { _args ??= new SelectTemplateEventArgs(); _args.TemplateKey = null; diff --git a/src/Avalonia.Controls/SplitView.cs b/src/Avalonia.Controls/SplitView.cs index 2d735a2cbb..d4293446d9 100644 --- a/src/Avalonia.Controls/SplitView.cs +++ b/src/Avalonia.Controls/SplitView.cs @@ -1,14 +1,11 @@ using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Input; -using Avalonia.Input.Raw; using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Metadata; -using Avalonia.Platform; using Avalonia.VisualTree; using System; -using System.Reactive.Disposables; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.LogicalTree; @@ -443,7 +440,7 @@ namespace Avalonia.Controls }; } - private string GetPseudoClass(SplitViewPanePlacement placement) + private static string GetPseudoClass(SplitViewPanePlacement placement) { return placement switch { @@ -463,8 +460,8 @@ namespace Avalonia.Controls private void OnDisplayModeChanged(AvaloniaPropertyChangedEventArgs e) { - var oldState = SplitView.GetPseudoClass(e.GetOldValue()); - var newState = SplitView.GetPseudoClass(e.GetNewValue()); + var oldState = GetPseudoClass(e.GetOldValue()); + var newState = GetPseudoClass(e.GetNewValue()); PseudoClasses.Remove($":{oldState}"); PseudoClasses.Add($":{newState}"); diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 0ac57c9233..331c75cd1f 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -17,7 +17,6 @@ using Avalonia.Controls.Metadata; using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Automation.Peers; -using System.Diagnostics; using Avalonia.Threading; namespace Avalonia.Controls @@ -397,9 +396,9 @@ namespace Avalonia.Controls var selectionStart = SelectionStart; var selectionEnd = SelectionEnd; - CaretIndex = TextBox.CoerceCaretIndex(caretIndex, value); - SelectionStart = TextBox.CoerceCaretIndex(selectionStart, value); - SelectionEnd = TextBox.CoerceCaretIndex(selectionEnd, value); + CaretIndex = CoerceCaretIndex(caretIndex, value); + SelectionStart = CoerceCaretIndex(selectionStart, value); + SelectionEnd = CoerceCaretIndex(selectionEnd, value); var textChanged = SetAndRaise(TextProperty, ref _text, value); @@ -1380,7 +1379,7 @@ namespace Avalonia.Controls } } - private int CoerceCaretIndex(int value) => TextBox.CoerceCaretIndex(value, Text); + private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text); private static int CoerceCaretIndex(int value, string? text) { diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 9fad9824df..b723d21710 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -449,7 +449,7 @@ namespace Avalonia.Controls { if(transparencyLevel == WindowTransparencyLevel.None || TransparencyLevelHint == WindowTransparencyLevel.None || - !TopLevel.TransparencyLevelsMatch(TransparencyLevelHint, transparencyLevel)) + !TransparencyLevelsMatch(TransparencyLevelHint, transparencyLevel)) { _transparencyFallbackBorder.Background = TransparencyBackgroundFallback; } diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index be30792cc8..e897339afd 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -3,13 +3,11 @@ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using System.ComponentModel; using System.Linq; using System.Reactive.Linq; using Avalonia.Collections; using Avalonia.Controls.Generators; using Avalonia.Controls.Primitives; -using Avalonia.Controls.Utils; using Avalonia.Data; using Avalonia.Input; using Avalonia.Input.Platform; @@ -284,7 +282,7 @@ namespace Avalonia.Controls foreach (IControl container in ItemContainerGenerator.Index!.Containers) { - TreeView.MarkContainerSelected(container, false); + MarkContainerSelected(container, false); } if (SelectedItems.Count > 0) @@ -339,7 +337,7 @@ namespace Avalonia.Controls { var container = ItemContainerGenerator.Index!.ContainerFromItem(item)!; - TreeView.MarkContainerSelected(container, selected); + MarkContainerSelected(container, selected); } private void SelectedItemsAdded(IList items) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs b/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs index 325c55783c..dca1e8008c 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Screenshots/FilePickerHandler.cs @@ -61,7 +61,7 @@ namespace Avalonia.Diagnostics.Screenshots protected async override Task GetStream(IControl control) { Stream? output = default; - var result = await FilePickerHandler.GetWindow(control).StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + var result = await GetWindow(control).StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions { SuggestedStartLocation = new BclStorageFolder(new DirectoryInfo(ScreenshotsRoot)), Title = Title, diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs index 869b2fd600..39b9e3d3f0 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs @@ -34,8 +34,8 @@ namespace Avalonia.Diagnostics.ViewModels { _avaloniaObject = avaloniaObject; - TreePage = treePage; - Layout = avaloniaObject is IVisual + TreePage = treePage; + Layout = avaloniaObject is IVisual ? new ControlLayoutViewModel((IVisual)avaloniaObject) : default; @@ -83,7 +83,7 @@ namespace Avalonia.Diagnostics.ViewModels { var setterValue = regularSetter.Value; - var resourceInfo = ControlDetailsViewModel.GetResourceInfo(setterValue); + var resourceInfo = GetResourceInfo(setterValue); SetterViewModel setterVm; @@ -137,7 +137,7 @@ namespace Avalonia.Diagnostics.ViewModels return null; } - private bool IsBinding(object? value) + private static bool IsBinding(object? value) { switch (value) { @@ -254,7 +254,7 @@ namespace Avalonia.Diagnostics.ViewModels } } - private IEnumerable GetAvaloniaProperties(object o) + private static IEnumerable GetAvaloniaProperties(object o) { if (o is AvaloniaObject ao) { @@ -268,7 +268,7 @@ namespace Avalonia.Diagnostics.ViewModels } } - private IEnumerable GetClrProperties(object o, bool showImplementedInterfaces) + private static IEnumerable GetClrProperties(object o, bool showImplementedInterfaces) { foreach (var p in GetClrProperties(o, o.GetType())) { @@ -287,7 +287,7 @@ namespace Avalonia.Diagnostics.ViewModels } } - private IEnumerable GetClrProperties(object o, Type t) + private static IEnumerable GetClrProperties(object o, Type t) { return t.GetProperties() .Where(x => x.GetIndexParameters().Length == 0) @@ -412,7 +412,7 @@ namespace Avalonia.Diagnostics.ViewModels } } - private int GroupIndex(string? group) + private static int GroupIndex(string? group) { switch (group) { diff --git a/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs b/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs index 2d6a2569fb..34c1506a67 100644 --- a/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs +++ b/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs @@ -36,12 +36,12 @@ namespace Avalonia.FreeDesktop private static string GetSymlinkTarget(string x) => Path.GetFullPath(Path.Combine(DevByLabelDir, NativeMethods.ReadLink(x))); - private string UnescapeString(string input, string regexText, int escapeBase) => + private static string UnescapeString(string input, string regexText, int escapeBase) => new Regex(regexText).Replace(input, m => Convert.ToChar(Convert.ToByte(m.Groups[1].Value, escapeBase)).ToString()); - private string UnescapePathFromProcMounts(string input) => UnescapeString(input, @"\\(\d{3})", 8); + private static string UnescapePathFromProcMounts(string input) => UnescapeString(input, @"\\(\d{3})", 8); - private string UnescapeDeviceLabel(string input) => UnescapeString(input, @"\\x([0-9a-f]{2})", 16); + private static string UnescapeDeviceLabel(string input) => UnescapeString(input, @"\\x([0-9a-f]{2})", 16); private void Poll(long _) { @@ -61,7 +61,7 @@ namespace Avalonia.FreeDesktop new DirectoryInfo(DevByLabelDir).GetFiles() : Enumerable.Empty(); var labelDevPathPairs = labelDirEnum - .Select(x => (LinuxMountedVolumeInfoListener.GetSymlinkTarget(x.FullName), UnescapeDeviceLabel(x.Name))); + .Select(x => (GetSymlinkTarget(x.FullName), UnescapeDeviceLabel(x.Name))); var q1 = from mount in fProcMounts join device in fProcPartitions on mount.Item1 equals device.Item2 diff --git a/src/Avalonia.Native/AvaloniaNativeDragSource.cs b/src/Avalonia.Native/AvaloniaNativeDragSource.cs index f93d558d25..84e2b31f23 100644 --- a/src/Avalonia.Native/AvaloniaNativeDragSource.cs +++ b/src/Avalonia.Native/AvaloniaNativeDragSource.cs @@ -48,7 +48,7 @@ namespace Avalonia.Native public Task DoDragDrop(PointerEventArgs triggerEvent, IDataObject data, DragDropEffects allowedEffects) { // Sanity check - var tl = AvaloniaNativeDragSource.FindRoot(triggerEvent.Source); + var tl = FindRoot(triggerEvent.Source); var view = tl?.PlatformImpl as WindowBaseImpl; if (view == null) throw new ArgumentException(); diff --git a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs index ddabfe8f5d..7c7b32f7e4 100644 --- a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs +++ b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs @@ -167,7 +167,7 @@ namespace Avalonia.Native if (appMenu == null) { - appMenu = AvaloniaNativeMenuExporter.CreateDefaultAppMenu(); + appMenu = CreateDefaultAppMenu(); NativeMenu.SetMenu(Application.Current, appMenu); } diff --git a/src/Avalonia.Native/IAvnMenu.cs b/src/Avalonia.Native/IAvnMenu.cs index f75621865c..709980c6b9 100644 --- a/src/Avalonia.Native/IAvnMenu.cs +++ b/src/Avalonia.Native/IAvnMenu.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Reactive.Disposables; using Avalonia.Controls; -using Avalonia.Platform.Interop; namespace Avalonia.Native.Interop { @@ -111,7 +110,7 @@ namespace Avalonia.Native.Interop.Impl private __MicroComIAvnMenuItemProxy CreateNewAt(IAvaloniaNativeFactory factory, int index, NativeMenuItemBase item) { - var result = __MicroComIAvnMenuProxy.CreateNew(factory, item); + var result = CreateNew(factory, item); result.Initialize(item); diff --git a/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs b/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs index 6f87ff19ee..e13ee80864 100644 --- a/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs +++ b/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs @@ -27,7 +27,7 @@ namespace Avalonia.OpenGL.Controls _context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, _fb); EnsureTextureAttachment(); EnsureDepthBufferAttachment(_context.GlInterface); - if(!OpenGlControlBase.CheckFramebufferStatus(_context.GlInterface)) + if(!CheckFramebufferStatus(_context.GlInterface)) return; OnOpenGlRender(_context.GlInterface, _fb); @@ -186,7 +186,7 @@ namespace Avalonia.OpenGL.Controls EnsureDepthBufferAttachment(gl); EnsureTextureAttachment(); - return OpenGlControlBase.CheckFramebufferStatus(gl); + return CheckFramebufferStatus(gl); } catch(Exception e) { diff --git a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs index 94073506e3..ed55192bf5 100644 --- a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs +++ b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs @@ -26,8 +26,8 @@ namespace Avalonia.ReactiveUI public IObservable GetActivationForView(IActivatableView view) { if (!(view is IVisual visual)) return Observable.Return(false); - if (view is Control control) return AvaloniaActivationForViewFetcher.GetActivationForControl(control); - return AvaloniaActivationForViewFetcher.GetActivationForVisual(visual); + if (view is Control control) return GetActivationForControl(control); + return GetActivationForVisual(visual); } /// diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs index de7c57a556..4ae1c1599f 100644 --- a/src/Avalonia.X11/X11IconLoader.cs +++ b/src/Avalonia.X11/X11IconLoader.cs @@ -16,9 +16,9 @@ namespace Avalonia.X11 return rv; } - public IWindowIconImpl LoadIcon(string fileName) => X11IconLoader.LoadIcon(new Bitmap(fileName)); + public IWindowIconImpl LoadIcon(string fileName) => LoadIcon(new Bitmap(fileName)); - public IWindowIconImpl LoadIcon(Stream stream) => X11IconLoader.LoadIcon(new Bitmap(stream)); + public IWindowIconImpl LoadIcon(Stream stream) => LoadIcon(new Bitmap(stream)); public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) { diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 312945e713..6ffebaf32b 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Runtime.InteropServices; using Avalonia.Controls; using Avalonia.Controls.Platform; -using Avalonia.Dialogs; using Avalonia.FreeDesktop; using Avalonia.FreeDesktop.DBusIme; using Avalonia.Input; @@ -42,10 +41,10 @@ namespace Avalonia.X11 Options = options; bool useXim = false; - if (AvaloniaX11Platform.EnableIme(options)) + if (EnableIme(options)) { // Attempt to configure DBus-based input method and check if we can fall back to XIM - if (!X11DBusImeHelper.DetectAndRegister() && AvaloniaX11Platform.ShouldUseXim()) + if (!X11DBusImeHelper.DetectAndRegister() && ShouldUseXim()) useXim = true; } @@ -85,7 +84,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new LinuxMountedVolumeInfoProvider()) .Bind().ToConstant(new X11PlatformLifetimeEvents(this)); - X11Screens = Avalonia.X11.X11Screens.Init(this); + X11Screens = X11.X11Screens.Init(this); Screens = new X11Screens(X11Screens); if (Info.XInputVersion != null) { diff --git a/src/Avalonia.X11/X11Window.Ime.cs b/src/Avalonia.X11/X11Window.Ime.cs index 128d48957c..8b267b2762 100644 --- a/src/Avalonia.X11/X11Window.Ime.cs +++ b/src/Avalonia.X11/X11Window.Ime.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; -using System.Threading.Tasks; using Avalonia.FreeDesktop; using Avalonia.Input; using Avalonia.Input.Raw; @@ -107,7 +106,7 @@ namespace Avalonia.X11 var filtered = ScheduleKeyInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), _inputRoot, ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, - X11KeyTransform.ConvertKey(key), X11Window.TranslateModifiers(ev.KeyEvent.state)), ref ev, (int)key, ev.KeyEvent.keycode); + X11KeyTransform.ConvertKey(key), TranslateModifiers(ev.KeyEvent.state)), ref ev, (int)key, ev.KeyEvent.keycode); if (ev.type == XEventName.KeyPress && !filtered) TriggerClassicTextInputEvent(ref ev); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index b2120b718e..5d8ff0884b 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Linq; -using System.Reactive.Disposables; using System.Text; using System.Threading.Tasks; using System.Threading; @@ -463,7 +461,7 @@ namespace Avalonia.X11 : new Vector(-1, 0); ScheduleInput(new RawMouseWheelEventArgs(_mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), delta, - X11Window.TranslateModifiers(ev.ButtonEvent.state)), ref ev); + TranslateModifiers(ev.ButtonEvent.state)), ref ev); } } @@ -760,7 +758,7 @@ namespace Avalonia.X11 { var mev = new RawPointerEventArgs( _mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, - type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), X11Window.TranslateModifiers(mods)); + type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), TranslateModifiers(mods)); ScheduleInput(mev, ref ev); } diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs index 952112b6fd..cfe55036a3 100644 --- a/src/Avalonia.X11/XI2Manager.cs +++ b/src/Avalonia.X11/XI2Manager.cs @@ -193,7 +193,7 @@ namespace Avalonia.X11 { var rev = (XIEnterLeaveEvent*)xev; if (_clients.TryGetValue(rev->EventWindow, out var client)) - XI2Manager.OnEnterLeaveEvent(client, ref *rev); + OnEnterLeaveEvent(client, ref *rev); } } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 12406df765..264361e743 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Xml; using Avalonia.Markup.Xaml.Parsers; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using Avalonia.Utilities; -using XamlX; using XamlX.Ast; using XamlX.Transform; using XamlX.Transform.Transformers; diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs index 078efcab6e..24b690b6f1 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs @@ -20,7 +20,7 @@ namespace Avalonia.Markup.Xaml.Converters var path = value as string; if (path != null) { - return IconTypeConverter.CreateIconFromPath(context, path); + return CreateIconFromPath(context, path); } var bitmap = value as IBitmap; diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs index 01d98ac9fb..dbcac7a2a3 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs @@ -56,12 +56,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions if (control != null) { - var source = control.GetResourceObservable(ResourceKey, DynamicResourceExtension.GetConverter(targetProperty)); + var source = control.GetResourceObservable(ResourceKey, GetConverter(targetProperty)); return InstancedBinding.OneWay(source, _priority); } else if (_anchor is IResourceProvider resourceProvider) { - var source = resourceProvider.GetResourceObservable(ResourceKey, DynamicResourceExtension.GetConverter(targetProperty)); + var source = resourceProvider.GetResourceObservable(ResourceKey, GetConverter(targetProperty)); return InstancedBinding.OneWay(source, _priority); } diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs index de463e2903..507e0690fd 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs @@ -1,6 +1,4 @@ -using System; -using Avalonia.Data.Core; -using Avalonia.Markup.Parsers; +using Avalonia.Data.Core; using Avalonia.Utilities; namespace Avalonia.Markup.Xaml.Parsers diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/StringIndexerNode.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/StringIndexerNode.cs index 824911902b..6176608196 100644 --- a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/StringIndexerNode.cs +++ b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/StringIndexerNode.cs @@ -113,9 +113,9 @@ namespace Avalonia.Markup.Parsers.Nodes } - private bool SetValueInArray(Array array, int[] indices, object? value) + private static bool SetValueInArray(Array array, int[] indices, object? value) { - if (StringIndexerNode.ValidBounds(indices, array)) + if (ValidBounds(indices, array)) { array.SetValue(value, indices); return true; @@ -223,9 +223,9 @@ namespace Avalonia.Markup.Parsers.Nodes return GetValueFromArray(array, intArgs); } - private object? GetValueFromArray(Array array, int[] indices) + private static object? GetValueFromArray(Array array, int[] indices) { - if (StringIndexerNode.ValidBounds(indices, array)) + if (ValidBounds(indices, array)) { return array.GetValue(indices); } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 46c8109fd8..60be732b8e 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -429,7 +429,7 @@ namespace Avalonia.Skia var spread = (float)boxShadow.Spread; var offsetX = (float)boxShadow.OffsetX; var offsetY = (float)boxShadow.OffsetY; - var outerRect = DrawingContextImpl.AreaCastingShadowInHole(rc, (float)boxShadow.Blur, spread, offsetX, offsetY); + var outerRect = AreaCastingShadowInHole(rc, (float)boxShadow.Blur, spread, offsetX, offsetY); Canvas.Save(); using var shadowRect = new SKRoundRect(skRoundRect); @@ -1044,7 +1044,7 @@ namespace Avalonia.Skia if (brush is IGradientBrush gradient) { - DrawingContextImpl.ConfigureGradientBrush(ref paintWrapper, targetSize, gradient); + ConfigureGradientBrush(ref paintWrapper, targetSize, gradient); return paintWrapper; } diff --git a/src/Windows/Avalonia.Win32/ClipboardImpl.cs b/src/Windows/Avalonia.Win32/ClipboardImpl.cs index 813903c270..85c97307e8 100644 --- a/src/Windows/Avalonia.Win32/ClipboardImpl.cs +++ b/src/Windows/Avalonia.Win32/ClipboardImpl.cs @@ -31,7 +31,7 @@ namespace Avalonia.Win32 public async Task GetTextAsync() { - using(await ClipboardImpl.OpenClipboard()) + using(await OpenClipboard()) { IntPtr hText = UnmanagedMethods.GetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT); if (hText == IntPtr.Zero) @@ -58,7 +58,7 @@ namespace Avalonia.Win32 throw new ArgumentNullException(nameof(text)); } - using(await ClipboardImpl.OpenClipboard()) + using(await OpenClipboard()) { UnmanagedMethods.EmptyClipboard(); @@ -69,7 +69,7 @@ namespace Avalonia.Win32 public async Task ClearAsync() { - using(await ClipboardImpl.OpenClipboard()) + using(await OpenClipboard()) { UnmanagedMethods.EmptyClipboard(); } diff --git a/src/Windows/Avalonia.Win32/CursorFactory.cs b/src/Windows/Avalonia.Win32/CursorFactory.cs index 73e45db6d3..862e99be19 100644 --- a/src/Windows/Avalonia.Win32/CursorFactory.cs +++ b/src/Windows/Avalonia.Win32/CursorFactory.cs @@ -92,7 +92,7 @@ namespace Avalonia.Win32 public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot) { - using var source = CursorFactory.LoadSystemDrawingBitmap(cursor); + using var source = LoadSystemDrawingBitmap(cursor); using var mask = AlphaToMask(source); var info = new UnmanagedMethods.ICONINFO diff --git a/src/Windows/Avalonia.Win32/DataObject.cs b/src/Windows/Avalonia.Win32/DataObject.cs index c6ac9e63f5..27560df35e 100644 --- a/src/Windows/Avalonia.Win32/DataObject.cs +++ b/src/Windows/Avalonia.Win32/DataObject.cs @@ -288,7 +288,7 @@ namespace Avalonia.Win32 var byteArr = bytes is byte[] ? (byte[])bytes : bytes.ToArray(); return WriteBytesToHGlobal(ref hGlobal, byteArr); } - return WriteBytesToHGlobal(ref hGlobal, DataObject.SerializeObject(data)); + return WriteBytesToHGlobal(ref hGlobal, SerializeObject(data)); } private static byte[] SerializeObject(object data) @@ -302,7 +302,7 @@ namespace Avalonia.Win32 } } - private unsafe uint WriteBytesToHGlobal(ref IntPtr hGlobal, ReadOnlySpan data) + private static unsafe uint WriteBytesToHGlobal(ref IntPtr hGlobal, ReadOnlySpan data) { int required = data.Length; if (hGlobal == IntPtr.Zero) @@ -326,7 +326,7 @@ namespace Avalonia.Win32 } } - private uint WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable files) + private static uint WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable files) { if (!files?.Any() ?? false) return unchecked((int)UnmanagedMethods.HRESULT.S_OK); @@ -358,7 +358,7 @@ namespace Avalonia.Win32 } } - private uint WriteStringToHGlobal(ref IntPtr hGlobal, string data) + private static uint WriteStringToHGlobal(ref IntPtr hGlobal, string data) { int required = (data.Length + 1) * sizeof(char); if (hGlobal == IntPtr.Zero) diff --git a/src/tools/DevGenerators/CompositionGenerator/Generator.cs b/src/tools/DevGenerators/CompositionGenerator/Generator.cs index c5f5ffcea4..0fb0389ca8 100644 --- a/src/tools/DevGenerators/CompositionGenerator/Generator.cs +++ b/src/tools/DevGenerators/CompositionGenerator/Generator.cs @@ -540,7 +540,7 @@ var changed = reader.Read<{ChangedFieldsTypeName(cl)}>(); return cl.AddMembers(method); } - ClassDeclarationSyntax WithStartAnimation(ClassDeclarationSyntax cl, BlockSyntax body) + static ClassDeclarationSyntax WithStartAnimation(ClassDeclarationSyntax cl, BlockSyntax body) { body = body.AddStatements( ExpressionStatement(InvocationExpression(MemberAccess("base", "StartAnimation"), From 6213676115ae823cb70b1f8ad674a3900836a87b Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 17 Oct 2022 17:00:15 +0200 Subject: [PATCH 030/137] fix: Address CA1822 rule --- src/Windows/Avalonia.Win32/Win32Platform.cs | 38 +++++++++---------- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 4 +- .../WindowImpl.CustomCaptionProc.cs | 4 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 7 ++-- .../CompositionGenerator/Generator.cs | 36 +++++++++--------- .../RenderTests_Culling.cs | 2 +- .../Rendering/DeferredRendererTests.cs | 10 ++--- .../AutoCompleteBoxTests.cs | 2 +- .../ButtonTests.cs | 2 +- .../CalendarDatePickerTests.cs | 4 +- .../Avalonia.Controls.UnitTests/GridTests.cs | 4 +- .../ListBoxTests.cs | 6 +-- .../MaskedTextBoxTests.cs | 6 +-- .../NumericUpDownTests.cs | 2 +- .../Primitives/PopupTests.cs | 2 +- .../TextBoxTests.cs | 8 ++-- .../TreeViewTests.cs | 2 +- .../CompiledBindingExtensionTests.cs | 10 ++--- .../DynamicResourceExtensionTests.cs | 20 +++++----- .../StaticResourceExtensionTests.cs | 12 +++--- .../Xaml/ResourceDictionaryTests.cs | 26 ++++++------- .../Xaml/XamlIlTests.cs | 2 +- 22 files changed, 105 insertions(+), 104 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 3cdc3586dc..69b47540a9 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -131,10 +131,10 @@ namespace Avalonia.Win32 internal static Compositor Compositor { get; private set; } public Size DoubleClickSize => new Size( - UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK), - UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDOUBLECLK)); + GetSystemMetrics(SystemMetric.SM_CXDOUBLECLK), + GetSystemMetrics(SystemMetric.SM_CYDOUBLECLK)); - public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(UnmanagedMethods.GetDoubleClickTime()); + public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(GetDoubleClickTime()); /// public Size TouchDoubleClickSize => new Size(16,16); @@ -185,16 +185,16 @@ namespace Avalonia.Win32 public bool HasMessages() { UnmanagedMethods.MSG msg; - return UnmanagedMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); + return PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); } public void ProcessMessage() { - if (UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0) > -1) + if (GetMessage(out var msg, IntPtr.Zero, 0, 0) > -1) { - UnmanagedMethods.TranslateMessage(ref msg); - UnmanagedMethods.DispatchMessage(ref msg); + TranslateMessage(ref msg); + DispatchMessage(ref msg); } else { @@ -208,10 +208,10 @@ namespace Avalonia.Win32 { var result = 0; while (!cancellationToken.IsCancellationRequested - && (result = UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0)) > 0) + && (result = GetMessage(out var msg, IntPtr.Zero, 0, 0)) > 0) { - UnmanagedMethods.TranslateMessage(ref msg); - UnmanagedMethods.DispatchMessage(ref msg); + TranslateMessage(ref msg); + DispatchMessage(ref msg); } if (result < 0) { @@ -225,7 +225,7 @@ namespace Avalonia.Win32 UnmanagedMethods.TimerProc timerDelegate = (hWnd, uMsg, nIDEvent, dwTime) => callback(); - IntPtr handle = UnmanagedMethods.SetTimer( + IntPtr handle = SetTimer( IntPtr.Zero, IntPtr.Zero, (uint)interval.TotalMilliseconds, @@ -237,7 +237,7 @@ namespace Avalonia.Win32 return Disposable.Create(() => { _delegates.Remove(timerDelegate); - UnmanagedMethods.KillTimer(IntPtr.Zero, handle); + KillTimer(IntPtr.Zero, handle); }); } @@ -246,9 +246,9 @@ namespace Avalonia.Win32 public void Signal(DispatcherPriority prio) { - UnmanagedMethods.PostMessage( + PostMessage( _hwnd, - (int) UnmanagedMethods.WindowsMessage.WM_DISPATCH_WORK_ITEM, + (int)WindowsMessage.WM_DISPATCH_WORK_ITEM, new IntPtr(SignalW), new IntPtr(SignalL)); } @@ -262,7 +262,7 @@ namespace Avalonia.Win32 [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { - if (msg == (int) UnmanagedMethods.WindowsMessage.WM_DISPATCH_WORK_ITEM && wParam.ToInt64() == SignalW && lParam.ToInt64() == SignalL) + if (msg == (int)WindowsMessage.WM_DISPATCH_WORK_ITEM && wParam.ToInt64() == SignalW && lParam.ToInt64() == SignalL) { Signaled?.Invoke(null); } @@ -284,7 +284,7 @@ namespace Avalonia.Win32 TrayIconImpl.ProcWnd(hWnd, msg, wParam, lParam); - return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); + return DefWindowProc(hWnd, msg, wParam, lParam); } private void CreateMessageWindow() @@ -296,18 +296,18 @@ namespace Avalonia.Win32 { cbSize = Marshal.SizeOf(), lpfnWndProc = _wndProcDelegate, - hInstance = UnmanagedMethods.GetModuleHandle(null), + hInstance = GetModuleHandle(null), lpszClassName = "AvaloniaMessageWindow " + Guid.NewGuid(), }; - ushort atom = UnmanagedMethods.RegisterClassEx(ref wndClassEx); + ushort atom = RegisterClassEx(ref wndClassEx); if (atom == 0) { throw new Win32Exception(); } - _hwnd = UnmanagedMethods.CreateWindowEx(0, atom, null, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + _hwnd = CreateWindowEx(0, atom, null, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (_hwnd == IntPtr.Zero) { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index f8785371d9..9855435e9f 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -356,7 +356,7 @@ namespace Avalonia.Win32 RawPointerEventType.XButton1Down : RawPointerEventType.XButton2Down, }, - PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam)); + PointToClient(WindowImpl.PointFromLParam(lParam)), GetMouseModifiers(wParam)); break; } case WindowsMessage.WM_TOUCH: @@ -948,7 +948,7 @@ namespace Avalonia.Win32 return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / RenderScaling; } - private PixelPoint PointFromLParam(IntPtr lParam) + private static PixelPoint PointFromLParam(IntPtr lParam) { return new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)); } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index e864f32138..c7dc90ed58 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -13,7 +13,7 @@ namespace Avalonia.Win32 private HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) { // Get the point coordinates for the hit test (screen space). - var ptMouse = PointFromLParam(lParam); + var ptMouse = WindowImpl.PointFromLParam(lParam); // Get the window rectangle. GetWindowRect(hWnd, out var rcWindow); @@ -105,7 +105,7 @@ namespace Avalonia.Win32 if (hittestResult == HitTestValues.HTCAPTION) { - var position = PointToClient(PointFromLParam(lParam)); + var position = PointToClient(WindowImpl.PointFromLParam(lParam)); if (_owner is Window window) { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0f243fcf9f..6e849a5b9d 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -639,7 +639,7 @@ namespace Avalonia.Win32 public Point PointToClient(PixelPoint point) { var p = new POINT { X = point.X, Y = point.Y }; - UnmanagedMethods.ScreenToClient(_hwnd, ref p); + ScreenToClient(_hwnd, ref p); return new Point(p.X, p.Y) / RenderScaling; } @@ -1321,12 +1321,13 @@ namespace Avalonia.Win32 private const int MF_DISABLED = 0x2; private const int SC_CLOSE = 0xF060; - void DisableCloseButton(IntPtr hwnd) + static void DisableCloseButton(IntPtr hwnd) { EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); } - void EnableCloseButton(IntPtr hwnd) + + static void EnableCloseButton(IntPtr hwnd) { EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED); diff --git a/src/tools/DevGenerators/CompositionGenerator/Generator.cs b/src/tools/DevGenerators/CompositionGenerator/Generator.cs index 0fb0389ca8..f8d5ad826e 100644 --- a/src/tools/DevGenerators/CompositionGenerator/Generator.cs +++ b/src/tools/DevGenerators/CompositionGenerator/Generator.cs @@ -311,7 +311,7 @@ namespace Avalonia.SourceGenerator.CompositionGenerator "Server", "Server" + cl.Name + ".generated.cs"); } - private ClassDeclarationSyntax GenerateClientProperty(ClassDeclarationSyntax client, GClass cl, GProperty prop, + private static ClassDeclarationSyntax GenerateClientProperty(ClassDeclarationSyntax client, GClass cl, GProperty prop, TypeSyntax propType, bool isObject, bool isNullable) { var fieldName = PropertyBackingFieldName(prop); @@ -344,7 +344,7 @@ namespace Avalonia.SourceGenerator.CompositionGenerator .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon())); } - EnumDeclarationSyntax GenerateChangedFieldsEnum(GClass cl) + static EnumDeclarationSyntax GenerateChangedFieldsEnum(GClass cl) { var changedFieldsEnum = EnumDeclaration(Identifier(ChangedFieldsTypeName(cl))); int count = 0; @@ -371,7 +371,7 @@ namespace Avalonia.SourceGenerator.CompositionGenerator .AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("System.Flags"))))); } - StatementSyntax GeneratePropertySetterAssignment(GClass cl, GProperty prop, bool isObject, bool isNullable) + static StatementSyntax GeneratePropertySetterAssignment(GClass cl, GProperty prop, bool isObject, bool isNullable) { var code = @$" // Update the backing value @@ -404,8 +404,8 @@ namespace Avalonia.SourceGenerator.CompositionGenerator return ParseStatement("{\n" + code + "\n}"); } - - BlockSyntax ApplyStartAnimation(BlockSyntax body, GClass cl, GProperty prop) + + static BlockSyntax ApplyStartAnimation(BlockSyntax body, GClass cl, GProperty prop) { var code = $@" if (propertyName == ""{prop.Name}"") @@ -435,8 +435,8 @@ return; "Color", "Avalonia.Media.Color" }; - - BlockSyntax ApplyGetProperty(BlockSyntax body, GProperty prop, string? expr = null) + + static BlockSyntax ApplyGetProperty(BlockSyntax body, GProperty prop, string? expr = null) { if (VariantPropertyTypes.Contains(prop.Type)) return body.AddStatements( @@ -446,7 +446,7 @@ return; return body; } - private BlockSyntax SerializeChangesPrologue(GClass cl) + private static BlockSyntax SerializeChangesPrologue(GClass cl) { return Block( ParseStatement("base.SerializeChangesCore(writer);"), @@ -454,10 +454,10 @@ return; ); } - private BlockSyntax SerializeChangesEpilogue(GClass cl) => + private static BlockSyntax SerializeChangesEpilogue(GClass cl) => Block(ParseStatement(ChangedFieldsFieldName(cl) + " = default;")); - - BlockSyntax ApplySerializeField(BlockSyntax body, GClass cl, GProperty prop, bool isObject, bool isPassthrough) + + static BlockSyntax ApplySerializeField(BlockSyntax body, GClass cl, GProperty prop, bool isObject, bool isPassthrough) { var changedFields = ChangedFieldsFieldName(cl); var changedFieldsType = ChangedFieldsTypeName(cl); @@ -478,7 +478,7 @@ return; return body.AddStatements(ParseStatement(code)); } - private BlockSyntax DeserializeChangesPrologue(GClass cl) + private static BlockSyntax DeserializeChangesPrologue(GClass cl) { return Block(ParseStatement($@" base.DeserializeChangesCore(reader, commitedAt); @@ -487,12 +487,12 @@ var changed = reader.Read<{ChangedFieldsTypeName(cl)}>(); ")); } - private BlockSyntax ApplyDeserializeChangesEpilogue(BlockSyntax body, GClass cl) + private static BlockSyntax ApplyDeserializeChangesEpilogue(BlockSyntax body, GClass cl) { return body.AddStatements(ParseStatement("OnFieldsDeserialized(changed);")); } - - BlockSyntax ApplyDeserializeField(BlockSyntax body, GClass cl, GProperty prop, string serverType, bool isObject) + + static BlockSyntax ApplyDeserializeField(BlockSyntax body, GClass cl, GProperty prop, string serverType, bool isObject) { var changedFieldsType = ChangedFieldsTypeName(cl); var code = ""; @@ -514,7 +514,7 @@ var changed = reader.Read<{ChangedFieldsTypeName(cl)}>(); return body.AddStatements(ParseStatement(code)); } - ClassDeclarationSyntax WithGetPropertyForAnimation(ClassDeclarationSyntax cl, BlockSyntax body) + static ClassDeclarationSyntax WithGetPropertyForAnimation(ClassDeclarationSyntax cl, BlockSyntax body) { if (body.Statements.Count == 0) return cl; @@ -526,8 +526,8 @@ var changed = reader.Read<{ChangedFieldsTypeName(cl)}>(); return cl.AddMembers(method); } - - ClassDeclarationSyntax WithGetCompositionProperty(ClassDeclarationSyntax cl, BlockSyntax body) + + static ClassDeclarationSyntax WithGetCompositionProperty(ClassDeclarationSyntax cl, BlockSyntax body) { if (body.Statements.Count == 0) return cl; diff --git a/tests/Avalonia.Base.UnitTests/RenderTests_Culling.cs b/tests/Avalonia.Base.UnitTests/RenderTests_Culling.cs index 509d2451a9..d17302808d 100644 --- a/tests/Avalonia.Base.UnitTests/RenderTests_Culling.cs +++ b/tests/Avalonia.Base.UnitTests/RenderTests_Culling.cs @@ -171,7 +171,7 @@ namespace Avalonia.Base.UnitTests } } - private void Render(IControl control) + private static void Render(IControl control) { var ctx = CreateDrawingContext(); control.Measure(Size.Infinity); diff --git a/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests.cs index 7f977103ce..df44575f68 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Base.UnitTests/Rendering/DeferredRendererTests.cs @@ -726,7 +726,7 @@ namespace Avalonia.Base.UnitTests.Rendering } } - private DeferredRenderer CreateTargetAndRunFrame( + private static DeferredRenderer CreateTargetAndRunFrame( TestRoot root, Mock timer = null, ISceneBuilder sceneBuilder = null, @@ -750,25 +750,25 @@ namespace Avalonia.Base.UnitTests.Rendering return Mock.Get(renderer.Layers[layerRoot].Bitmap.Item.CreateDrawingContext(null)); } - private void IgnoreFirstFrame(IRenderLoopTask task, Mock sceneBuilder) + private static void IgnoreFirstFrame(IRenderLoopTask task, Mock sceneBuilder) { RunFrame(task); sceneBuilder.Invocations.Clear(); } - private void RunFrame(IRenderLoopTask task) + private static void RunFrame(IRenderLoopTask task) { task.Update(TimeSpan.Zero); task.Render(); } - private IRenderTargetBitmapImpl CreateLayer() + private static IRenderTargetBitmapImpl CreateLayer() { return Mock.Of(x => x.CreateDrawingContext(It.IsAny()) == Mock.Of()); } - private Mock MockSceneBuilder(IRenderRoot root) + private static Mock MockSceneBuilder(IRenderRoot root) { var result = new Mock(); result.Setup(x => x.UpdateAll(It.IsAny())) diff --git a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs index c8bd289e54..f97b69c752 100644 --- a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs @@ -455,7 +455,7 @@ namespace Avalonia.Controls.UnitTests /// Creates a large list of strings for AutoCompleteBox testing. /// /// Returns a new List of string values. - private IList CreateSimpleStringArray() + private static IList CreateSimpleStringArray() { return new List { diff --git a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs index 42bdffd908..68f46824c1 100644 --- a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs @@ -379,7 +379,7 @@ namespace Avalonia.Controls.UnitTests } } - private KeyEventArgs CreateKeyDownEvent(Key key, IInteractive source = null) + private static KeyEventArgs CreateKeyDownEvent(Key key, IInteractive source = null) { return new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, Source = source }; } diff --git a/tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs b/tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs index a73e14939d..c3acf31caa 100644 --- a/tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs @@ -76,7 +76,7 @@ namespace Avalonia.Controls.UnitTests private static TestServices Services => TestServices.MockThreadingInterface.With( standardCursorFactory: Mock.Of()); - private CalendarDatePicker CreateControl() + private static CalendarDatePicker CreateControl() { var datePicker = new CalendarDatePicker @@ -88,7 +88,7 @@ namespace Avalonia.Controls.UnitTests return datePicker; } - private IControlTemplate CreateTemplate() + private static IControlTemplate CreateTemplate() { return new FuncControlTemplate((control, scope) => { diff --git a/tests/Avalonia.Controls.UnitTests/GridTests.cs b/tests/Avalonia.Controls.UnitTests/GridTests.cs index b2d00929d8..d372bb2af4 100644 --- a/tests/Avalonia.Controls.UnitTests/GridTests.cs +++ b/tests/Avalonia.Controls.UnitTests/GridTests.cs @@ -16,13 +16,13 @@ namespace Avalonia.Controls.UnitTests this.output = output; } - private Grid CreateGrid(params (string name, GridLength width)[] columns) + private static Grid CreateGrid(params (string name, GridLength width)[] columns) { return CreateGrid(columns.Select(c => (c.name, c.width, ColumnDefinition.MinWidthProperty.GetDefaultValue(typeof(ColumnDefinition)))).ToArray()); } - private Grid CreateGrid(params (string name, GridLength width, double minWidth)[] columns) + private static Grid CreateGrid(params (string name, GridLength width, double minWidth)[] columns) { return CreateGrid(columns.Select(c => (c.name, c.width, c.minWidth, ColumnDefinition.MaxWidthProperty.GetDefaultValue(typeof(ColumnDefinition)))).ToArray()); diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index 203df0aded..e65a3b62ee 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -590,7 +590,7 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(new[] { "Bar" }, target.Selection.SelectedItems); } - private FuncControlTemplate ListBoxTemplate() + private static FuncControlTemplate ListBoxTemplate() { return new FuncControlTemplate((parent, scope) => new ScrollViewer @@ -643,7 +643,7 @@ namespace Avalonia.Controls.UnitTests }); } - private void Prepare(ListBox target) + private static void Prepare(ListBox target) { // The ListBox needs to be part of a rooted visual tree. var root = new TestRoot(); @@ -718,7 +718,7 @@ namespace Avalonia.Controls.UnitTests Assert.True(DataValidationErrors.GetErrors(target).SequenceEqual(new[] { exception })); } - private void RaiseKeyEvent(ListBox listBox, Key key, KeyModifiers inputModifiers = 0) + private static void RaiseKeyEvent(ListBox listBox, Key key, KeyModifiers inputModifiers = 0) { listBox.RaiseEvent(new KeyEventArgs { diff --git a/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs index d1fa522206..22b4e0e87d 100644 --- a/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs @@ -118,7 +118,7 @@ namespace Avalonia.Controls.UnitTests target.ApplyTemplate(); target.CaretIndex = 3; target.Measure(Size.Infinity); - + RaiseKeyEvent(target, Key.Right, 0); Assert.Equal(4, target.CaretIndex); @@ -885,7 +885,7 @@ namespace Avalonia.Controls.UnitTests textShaperImpl: new MockTextShaperImpl(), fontManagerImpl: new MockFontManagerImpl()); - private IControlTemplate CreateTemplate() + private static IControlTemplate CreateTemplate() { return new FuncControlTemplate((control, scope) => new TextPresenter @@ -908,7 +908,7 @@ namespace Avalonia.Controls.UnitTests }.RegisterInNameScope(scope)); } - private void RaiseKeyEvent(MaskedTextBox textBox, Key key, KeyModifiers inputModifiers) + private static void RaiseKeyEvent(MaskedTextBox textBox, Key key, KeyModifiers inputModifiers) { textBox.RaiseEvent(new KeyEventArgs { diff --git a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs index dc47b19299..bdb94707de 100644 --- a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs +++ b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs @@ -75,7 +75,7 @@ namespace Avalonia.Controls.UnitTests .OfType() .First(); } - private IControlTemplate CreateTemplate() + private static IControlTemplate CreateTemplate() { return new FuncControlTemplate((control, scope) => { diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 100de7f4f6..68c9fba8b9 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -1074,7 +1074,7 @@ namespace Avalonia.Controls.UnitTests.Primitives } - private PointerPressedEventArgs CreatePointerPressedEventArgs(Window source, Point p) + private static PointerPressedEventArgs CreatePointerPressedEventArgs(Window source, Point p) { var pointer = new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true); return new PointerPressedEventArgs( diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 23a330c96f..d550d7c5f9 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -578,7 +578,7 @@ namespace Avalonia.Controls.UnitTests target1.Focus(); Assert.True(target1.IsFocused); - + RaiseKeyEvent(target1, key, KeyModifiers.None); } } @@ -747,7 +747,7 @@ namespace Avalonia.Controls.UnitTests var clipboard = AvaloniaLocator.CurrentMutable.GetService(); clipboard.SetTextAsync(textInput).GetAwaiter().GetResult(); - + RaiseKeyEvent(target, Key.V, KeyModifiers.Control); clipboard.ClearAsync().GetAwaiter().GetResult(); } @@ -904,7 +904,7 @@ namespace Avalonia.Controls.UnitTests }.RegisterInNameScope(scope)); } - private void RaiseKeyEvent(TextBox textBox, Key key, KeyModifiers inputModifiers) + private static void RaiseKeyEvent(TextBox textBox, Key key, KeyModifiers inputModifiers) { textBox.RaiseEvent(new KeyEventArgs { @@ -914,7 +914,7 @@ namespace Avalonia.Controls.UnitTests }); } - private void RaiseTextEvent(TextBox textBox, string text) + private static void RaiseTextEvent(TextBox textBox, string text) { textBox.RaiseEvent(new TextInputEventArgs { diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index fb21acad9e..81d76f8ca5 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -1247,7 +1247,7 @@ namespace Avalonia.Controls.UnitTests } } - private TreeViewItem GetItem(TreeView target, params int[] indexes) + private static TreeViewItem GetItem(TreeView target, params int[] indexes) { var c = (ItemsControl)target; diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 215ae4d54f..418349e390 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -1568,8 +1568,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions Assert.Equal(typeof(string), node.Property.PropertyType); } } - - void Throws(string type, Action cb) + + static void Throws(string type, Action cb) { try { @@ -1583,8 +1583,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions throw new Exception("Expected " + type); } - void ThrowsXamlParseException(Action cb) => Throws("XamlParseException", cb); - void ThrowsXamlTransformException(Action cb) => Throws("XamlTransformException", cb); + static void ThrowsXamlParseException(Action cb) => Throws("XamlParseException", cb); + static void ThrowsXamlTransformException(Action cb) => Throws("XamlTransformException", cb); static void PerformClick(Button button) @@ -1592,7 +1592,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions button.RaiseEvent(new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, - Key = Input.Key.Enter, + Key = Key.Enter, }); } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs index 4f323d8b2c..ccc460d900 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs @@ -221,7 +221,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions [Fact] public void DynamicResource_From_Style_Can_Be_Assigned_To_Setter() { - using (StyledWindow()) + using (DynamicResourceExtensionTests.StyledWindow()) { var xaml = @" "; - using (StyledWindow(assets: ("test:style.xaml", styleXaml))) + using (DynamicResourceExtensionTests.StyledWindow(assets: ("test:style.xaml", styleXaml))) { var xaml = @" "; - using (StyledWindow(assets: ("test:style.xaml", styleXaml))) + using (DynamicResourceExtensionTests.StyledWindow(assets: ("test:style.xaml", styleXaml))) { var xaml = @" "; - using (StyledWindow( + using (DynamicResourceExtensionTests.StyledWindow( ("test:style1.xaml", style1Xaml), ("test:style2.xaml", style2Xaml))) { @@ -606,7 +606,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions "; - using (StyledWindow( + using (DynamicResourceExtensionTests.StyledWindow( ("test:style1.xaml", style1Xaml), ("test:style2.xaml", style2Xaml))) { @@ -631,7 +631,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions [Fact] public void Control_Property_Is_Updated_When_Parent_Is_Changed() { - using (StyledWindow()) + using (DynamicResourceExtensionTests.StyledWindow()) { var xaml = @" new Styles { - DynamicResourceExtensionTests.WindowStyle(), + WindowStyle(), }); return UnitTestApplication.Start(services); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs index 625785a0b7..94e1e013d2 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs @@ -374,7 +374,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions [Fact] public void StaticResource_Can_Be_Assigned_To_Converter() { - using (StyledWindow()) + using (StaticResourceExtensionTests.StyledWindow()) { var xaml = @" new Styles { - StaticResourceExtensionTests.WindowStyle(), + WindowStyle(), }); return UnitTestApplication.Start(services); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs index 05e69adae0..030fa669b8 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs @@ -15,7 +15,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml [Fact] public void StaticResource_Works_In_ResourceDictionary() { - using (StyledWindow()) + using (ResourceDictionaryTests.StyledWindow()) { var xaml = @" "; - using (StyledWindow(assets: ("test:dict.xaml", dictionaryXaml))) + using (ResourceDictionaryTests.StyledWindow(assets: ("test:dict.xaml", dictionaryXaml))) { var xaml = @" AvaloniaRuntimeXamlLoader + AssertThrows(() => AvaloniaRuntimeXamlLoader .Load(@" Date: Wed, 19 Oct 2022 09:58:58 +0200 Subject: [PATCH 031/137] fix: Apply rule CA1822 --- src/Avalonia.Base/Media/PathMarkupParser.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/Media/PathMarkupParser.cs b/src/Avalonia.Base/Media/PathMarkupParser.cs index 30c5206125..41f97e5d1b 100644 --- a/src/Avalonia.Base/Media/PathMarkupParser.cs +++ b/src/Avalonia.Base/Media/PathMarkupParser.cs @@ -519,7 +519,7 @@ namespace Avalonia.Media return span.Slice(i); } - private bool ReadBool(ref ReadOnlySpan span) + private static bool ReadBool(ref ReadOnlySpan span) { span = SkipWhitespace(span); @@ -543,7 +543,7 @@ namespace Avalonia.Media } } - private double ReadDouble(ref ReadOnlySpan span) + private static double ReadDouble(ref ReadOnlySpan span) { if (!ReadArgument(ref span, out var doubleValue)) { @@ -553,7 +553,7 @@ namespace Avalonia.Media return double.Parse(doubleValue.ToString(), CultureInfo.InvariantCulture); } - private Size ReadSize(ref ReadOnlySpan span) + private static Size ReadSize(ref ReadOnlySpan span) { var width = ReadDouble(ref span); span = ReadSeparator(span); @@ -561,7 +561,7 @@ namespace Avalonia.Media return new Size(width, height); } - private Point ReadPoint(ref ReadOnlySpan span) + private static Point ReadPoint(ref ReadOnlySpan span) { var x = ReadDouble(ref span); span = ReadSeparator(span); @@ -569,7 +569,7 @@ namespace Avalonia.Media return new Point(x, y); } - private Point ReadRelativePoint(ref ReadOnlySpan span, Point origin) + private static Point ReadRelativePoint(ref ReadOnlySpan span, Point origin) { var x = ReadDouble(ref span); span = ReadSeparator(span); @@ -577,7 +577,7 @@ namespace Avalonia.Media return new Point(origin.X + x, origin.Y + y); } - private bool ReadCommand(ref ReadOnlySpan span, out Command command, out bool relative) + private static bool ReadCommand(ref ReadOnlySpan span, out Command command, out bool relative) { span = SkipWhitespace(span); if (span.IsEmpty) From ac2f0f88d6156278dc2de28c63a461a7aaed0d4e Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 3 Nov 2022 14:48:39 +0100 Subject: [PATCH 032/137] fix: Rule CA1822 only private and internal --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index c3989db7f4..488453596d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -145,6 +145,7 @@ dotnet_diagnostic.CA1820.severity = warning dotnet_diagnostic.CA1821.severity = warning # CA1822: Mark members as static dotnet_diagnostic.CA1822.severity = warning +dotnet_code_quality.CA1822.api_surface = private, internal # CA1825: Avoid zero-length array allocations dotnet_diagnostic.CA1825.severity = warning #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters From 581481f7adfe3d56899b04cee811b3d49756c0a0 Mon Sep 17 00:00:00 2001 From: zhouzj Date: Mon, 7 Nov 2022 09:52:06 +0800 Subject: [PATCH 033/137] Indicator size calculation should care about the ProgressBar's Padding property setting --- src/Avalonia.Controls/ProgressBar.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs index 71a7a58da4..165bec3a95 100644 --- a/src/Avalonia.Controls/ProgressBar.cs +++ b/src/Avalonia.Controls/ProgressBar.cs @@ -270,15 +270,16 @@ namespace Avalonia.Controls double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum); // When the Orientation changed, the indicator's Width or Height should set to double.NaN. + // Indicator size calculation should consider the ProgressBar's Padding property setting if (Orientation == Orientation.Horizontal) { - _indicator.Width = barSize.Width * percent; + _indicator.Width = (barSize.Width - _indicator.Margin.Left - _indicator.Margin.Right) * percent; _indicator.Height = double.NaN; } else { _indicator.Width = double.NaN; - _indicator.Height = barSize.Height * percent; + _indicator.Height = (barSize.Height - _indicator.Margin.Top - _indicator.Margin.Bottom) * percent; } From 1e69527ea62b4f97c96fa1d0d2f7fc47d8db57dc Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 15 Nov 2022 10:12:48 +0100 Subject: [PATCH 034/137] fix: address review --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 488453596d..7c0301a124 100644 --- a/.editorconfig +++ b/.editorconfig @@ -144,7 +144,7 @@ dotnet_diagnostic.CA1820.severity = warning # CA1821: Remove empty finalizers dotnet_diagnostic.CA1821.severity = warning # CA1822: Mark members as static -dotnet_diagnostic.CA1822.severity = warning +dotnet_diagnostic.CA1822.severity = suggestion dotnet_code_quality.CA1822.api_surface = private, internal # CA1825: Avoid zero-length array allocations dotnet_diagnostic.CA1825.severity = warning From 2d7c8645d0e82ed71edce10472bb5d5b1360d1d2 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 21 Nov 2022 01:14:43 +0600 Subject: [PATCH 035/137] Recalculate parent's child render nodes on visual tree attachment --- src/Avalonia.Base/Visual.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs index 69389def56..51fc143f72 100644 --- a/src/Avalonia.Base/Visual.cs +++ b/src/Avalonia.Base/Visual.cs @@ -432,6 +432,7 @@ namespace Avalonia OnAttachedToVisualTree(e); AttachedToVisualTree?.Invoke(this, e); InvalidateVisual(); + _visualRoot.Renderer.RecalculateChildren(_visualParent!); if (ZIndex != 0 && this.GetVisualParent() is Visual parent) parent.HasNonUniformZIndexChildren = true; From 16f3114e61b4fdf535613aae47972d028f7f6766 Mon Sep 17 00:00:00 2001 From: amwx <40413319+amwx@users.noreply.github.com> Date: Sun, 20 Nov 2022 23:53:34 -0500 Subject: [PATCH 036/137] TextBox programmatic Undo/Redo & CanUndo/CanRedo --- src/Avalonia.Controls/TextBox.cs | 109 ++++++++++++++---- src/Avalonia.Controls/Utils/UndoRedoHelper.cs | 20 ++++ 2 files changed, 109 insertions(+), 20 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d5b45398e7..b06ec3492c 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -17,7 +17,6 @@ using Avalonia.Controls.Metadata; using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Automation.Peers; -using System.Diagnostics; using Avalonia.Threading; namespace Avalonia.Controls @@ -166,6 +165,18 @@ namespace Avalonia.Controls (o, v) => o.UndoLimit = v, unsetValue: -1); + /// + /// Defines the property + /// + public static readonly DirectProperty CanUndoProperty = + AvaloniaProperty.RegisterDirect(nameof(CanUndo), x => x.CanUndo); + + /// + /// Defines the property + /// + public static readonly DirectProperty CanRedoProperty = + AvaloniaProperty.RegisterDirect(nameof(CanRedo), x => x.CanRedo); + /// /// Defines the event. /// @@ -232,6 +243,8 @@ namespace Avalonia.Controls private bool _canPaste; private string _newLine = Environment.NewLine; private static readonly string[] invalidCharacters = new String[1] { "\u007f" }; + private bool _canUndo; + private bool _canRedo; private int _wordSelectionStart = -1; private int _selectedTextChangesMadeSinceLastUndoSnapshot; @@ -590,6 +603,24 @@ namespace Avalonia.Controls } } + /// + /// Gets a value that indicates whether the undo stack has an action that can be undone + /// + public bool CanUndo + { + get => _canUndo; + private set => SetAndRaise(CanUndoProperty, ref _canUndo, value); + } + + /// + /// Gets a value that indicates whether the redo stack has an action that can be redone + /// + public bool CanRedo + { + get => _canRedo; + private set => SetAndRaise(CanRedoProperty, ref _canRedo, value); + } + public event EventHandler? CopyingToClipboard { add => AddHandler(CopyingToClipboardEvent, value); @@ -943,30 +974,13 @@ namespace Avalonia.Controls } else if (Match(keymap.Undo) && IsUndoEnabled) { - try - { - SnapshotUndoRedo(); - _isUndoingRedoing = true; - _undoRedoHelper.Undo(); - } - finally - { - _isUndoingRedoing = false; - } + Undo(); handled = true; } else if (Match(keymap.Redo) && IsUndoEnabled) { - try - { - _isUndoingRedoing = true; - _undoRedoHelper.Redo(); - } - finally - { - _isUndoingRedoing = false; - } + Redo(); handled = true; } @@ -1703,5 +1717,60 @@ namespace Avalonia.Controls } } } + + /// + /// Undoes the first action in the undo stack + /// + public void Undo() + { + if (IsUndoEnabled && CanUndo) + { + try + { + SnapshotUndoRedo(); + _isUndoingRedoing = true; + _undoRedoHelper.Undo(); + } + finally + { + _isUndoingRedoing = false; + } + } + } + + /// + /// Reapplies the first item on the redo stack + /// + public void Redo() + { + if (IsUndoEnabled && CanRedo) + { + try + { + _isUndoingRedoing = true; + _undoRedoHelper.Redo(); + } + finally + { + _isUndoingRedoing = false; + } + } + } + + /// + /// Called from the UndoRedoHelper when the undo stack is modified + /// + void UndoRedoHelper.IUndoRedoHost.OnUndoStackChanged() + { + CanUndo = _undoRedoHelper.CanUndo; + } + + /// + /// Called from the UndoRedoHelper when the redo stack is modified + /// + void UndoRedoHelper.IUndoRedoHost.OnRedoStackChanged() + { + CanRedo = _undoRedoHelper.CanRedo; + } } } diff --git a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs index 0d5048c080..976dbb5d5f 100644 --- a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs +++ b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs @@ -14,6 +14,10 @@ namespace Avalonia.Controls.Utils public interface IUndoRedoHost { TState UndoRedoState { get; set; } + + void OnUndoStackChanged(); + + void OnRedoStackChanged(); } @@ -28,6 +32,10 @@ namespace Avalonia.Controls.Utils /// public int Limit { get; set; } = 10; + public bool CanUndo => _currentNode?.Previous != null; + + public bool CanRedo => _currentNode?.Next != null; + public UndoRedoHelper(IUndoRedoHost host) { _host = host; @@ -39,6 +47,8 @@ namespace Avalonia.Controls.Utils { _currentNode = _currentNode.Previous; _host.UndoRedoState = _currentNode.Value; + _host.OnUndoStackChanged(); + _host.OnRedoStackChanged(); } } @@ -72,6 +82,8 @@ namespace Avalonia.Controls.Utils { while (_currentNode?.Next != null) _states.Remove(_currentNode.Next); + + _host.OnRedoStackChanged(); } public void Redo() @@ -80,6 +92,8 @@ namespace Avalonia.Controls.Utils { _currentNode = _currentNode.Next; _host.UndoRedoState = _currentNode.Value; + _host.OnRedoStackChanged(); + _host.OnUndoStackChanged(); } } @@ -94,6 +108,9 @@ namespace Avalonia.Controls.Utils _currentNode = _states.Last; if (Limit != -1 && _states.Count > Limit) _states.RemoveFirst(); + + _host.OnUndoStackChanged(); + _host.OnRedoStackChanged(); } } @@ -101,6 +118,9 @@ namespace Avalonia.Controls.Utils { _states.Clear(); _currentNode = null; + + _host.OnUndoStackChanged(); + _host.OnRedoStackChanged(); } } } From 3f1a342e6f3052f0f319924209680dfbe56ae708 Mon Sep 17 00:00:00 2001 From: amwx <40413319+amwx@users.noreply.github.com> Date: Sun, 20 Nov 2022 23:53:41 -0500 Subject: [PATCH 037/137] Add some tests --- .../TextBoxTests.cs | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 23a330c96f..52a89cd13d 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -866,6 +866,176 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void CanUndo_CanRedo_Is_False_When_Initialized() + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + Text = "New Text" + }; + + tb.Measure(Size.Infinity); + + Assert.False(tb.CanUndo); + Assert.False(tb.CanRedo); + } + } + + [Fact] + public void CanUndo_CanRedo_and_Programmatic_Undo_Redo_Works() + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + }; + + tb.Measure(Size.Infinity); + + // See GH #6024 for a bit more insight on when Undo/Redo snapshots are taken: + // - Every 'Space', but only when space is handled in OnKeyDown - Spaces in TextInput event won't work + // - Every 7 chars in a long word + RaiseTextEvent(tb, "ABC"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "DEF"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "123"); + + // NOTE: the spaces won't actually add spaces b/c they're sent only as key events and not Text events + // so our final text is without spaces + Assert.Equal("ABCDEF123", tb.Text); + + Assert.True(tb.CanUndo); + + tb.Undo(); + + // Undo will take us back one step + Assert.Equal("ABCDEF", tb.Text); + + Assert.True(tb.CanRedo); + + tb.Redo(); + + // Redo should restore us + Assert.Equal("ABCDEF123", tb.Text); + } + } + + [Fact] + public void Setting_UndoLimit_Clears_Undo_Redo() + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + }; + + tb.Measure(Size.Infinity); + + // This is all the same as the above test (CanUndo_CanRedo_and_Programmatic_Undo_Redo_Works) + // We do this to get the undo/redo stacks in a state where both are active + RaiseTextEvent(tb, "ABC"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "DEF"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "123"); + + Assert.Equal("ABCDEF123", tb.Text); + Assert.True(tb.CanUndo); + tb.Undo(); + // Undo will take us back one step + Assert.Equal("ABCDEF", tb.Text); + Assert.True(tb.CanRedo); + tb.Redo(); + // Redo should restore us + Assert.Equal("ABCDEF123", tb.Text); + + // Change the undo limit, this should clear both stacks setting CanUndo and CanRedo to false + tb.UndoLimit = 1; + + Assert.False(tb.CanUndo); + Assert.False(tb.CanRedo); + } + } + + [Fact] + public void Setting_IsUndoEnabled_To_False_Clears_Undo_Redo() + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + }; + + tb.Measure(Size.Infinity); + + // This is all the same as the above test (CanUndo_CanRedo_and_Programmatic_Undo_Redo_Works) + // We do this to get the undo/redo stacks in a state where both are active + RaiseTextEvent(tb, "ABC"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "DEF"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "123"); + + Assert.Equal("ABCDEF123", tb.Text); + Assert.True(tb.CanUndo); + tb.Undo(); + // Undo will take us back one step + Assert.Equal("ABCDEF", tb.Text); + Assert.True(tb.CanRedo); + tb.Redo(); + // Redo should restore us + Assert.Equal("ABCDEF123", tb.Text); + + // Disable Undo/Redo, this should clear both stacks setting CanUndo and CanRedo to false + tb.IsUndoEnabled = false; + + Assert.False(tb.CanUndo); + Assert.False(tb.CanRedo); + } + } + + [Fact] + public void UndoLimit_Count_Is_Respected() + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + UndoLimit = 3 // Something small for this test + }; + + tb.Measure(Size.Infinity); + + // Push 3 undoable actions, we should only be able to recover 2 + RaiseTextEvent(tb, "ABC"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "DEF"); + RaiseKeyEvent(tb, Key.Space, KeyModifiers.None); + RaiseTextEvent(tb, "123"); + + Assert.Equal("ABCDEF123", tb.Text); + + // Undo will take us back one step + tb.Undo(); + Assert.Equal("ABCDEF", tb.Text); + + // Undo again + tb.Undo(); + Assert.Equal("ABC", tb.Text); + + // We now should not be able to undo again + Assert.False(tb.CanUndo); + } + } + private static TestServices FocusServices => TestServices.MockThreadingInterface.With( focusManager: new FocusManager(), keyboardDevice: () => new KeyboardDevice(), From 4b089c0e823dfccfab096fe4057a55e5fe9a2b8f Mon Sep 17 00:00:00 2001 From: amwx <40413319+amwx@users.noreply.github.com> Date: Mon, 21 Nov 2022 00:16:44 -0500 Subject: [PATCH 038/137] Add some missing xml docs & a little cleanup --- src/Avalonia.Controls/TextBox.cs | 178 +++++++++++++++++- src/Avalonia.Controls/Utils/UndoRedoHelper.cs | 8 +- 2 files changed, 178 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index b06ec3492c..dbab912716 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -28,60 +28,108 @@ namespace Avalonia.Controls [PseudoClasses(":empty")] public class TextBox : TemplatedControl, UndoRedoHelper.IUndoRedoHost { + /// + /// Gets a platform-specific for the Cut action + /// public static KeyGesture? CutGesture { get; } = AvaloniaLocator.Current .GetService()?.Cut.FirstOrDefault(); + /// + /// Gets a platform-specific for the Copy action + /// public static KeyGesture? CopyGesture { get; } = AvaloniaLocator.Current .GetService()?.Copy.FirstOrDefault(); + /// + /// Gets a platform-specific for the Paste action + /// public static KeyGesture? PasteGesture { get; } = AvaloniaLocator.Current .GetService()?.Paste.FirstOrDefault(); + /// + /// Defines the property + /// public static readonly StyledProperty AcceptsReturnProperty = AvaloniaProperty.Register(nameof(AcceptsReturn)); + /// + /// Defines the property + /// public static readonly StyledProperty AcceptsTabProperty = AvaloniaProperty.Register(nameof(AcceptsTab)); + /// + /// Defines the property + /// public static readonly DirectProperty CaretIndexProperty = AvaloniaProperty.RegisterDirect( nameof(CaretIndex), o => o.CaretIndex, (o, v) => o.CaretIndex = v); + /// + /// Defines the property + /// public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register(nameof(IsReadOnly)); + /// + /// Defines the property + /// public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + /// + /// Defines the property + /// public static readonly StyledProperty SelectionBrushProperty = AvaloniaProperty.Register(nameof(SelectionBrush)); + /// + /// Defines the property + /// public static readonly StyledProperty SelectionForegroundBrushProperty = AvaloniaProperty.Register(nameof(SelectionForegroundBrush)); + /// + /// Defines the property + /// public static readonly StyledProperty CaretBrushProperty = AvaloniaProperty.Register(nameof(CaretBrush)); + /// + /// Defines the property + /// public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( nameof(SelectionStart), o => o.SelectionStart, (o, v) => o.SelectionStart = v); + /// + /// Defines the property + /// public static readonly DirectProperty SelectionEndProperty = AvaloniaProperty.RegisterDirect( nameof(SelectionEnd), o => o.SelectionEnd, (o, v) => o.SelectionEnd = v); + /// + /// Defines the property + /// public static readonly StyledProperty MaxLengthProperty = AvaloniaProperty.Register(nameof(MaxLength), defaultValue: 0); + /// + /// Defines the property + /// public static readonly StyledProperty MaxLinesProperty = AvaloniaProperty.Register(nameof(MaxLines), defaultValue: 0); + /// + /// Defines the property + /// public static readonly DirectProperty TextProperty = TextBlock.TextProperty.AddOwnerWithDataValidation( o => o.Text, @@ -89,6 +137,9 @@ namespace Avalonia.Controls defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); + /// + /// Defines the property + /// public static readonly StyledProperty TextAlignmentProperty = TextBlock.TextAlignmentProperty.AddOwner(); @@ -119,45 +170,78 @@ namespace Avalonia.Controls public static readonly StyledProperty LetterSpacingProperty = TextBlock.LetterSpacingProperty.AddOwner(); + /// + /// Defines the property + /// public static readonly StyledProperty WatermarkProperty = AvaloniaProperty.Register(nameof(Watermark)); + /// + /// Defines the property + /// public static readonly StyledProperty UseFloatingWatermarkProperty = AvaloniaProperty.Register(nameof(UseFloatingWatermark)); + /// + /// Defines the property + /// public static readonly DirectProperty NewLineProperty = AvaloniaProperty.RegisterDirect(nameof(NewLine), textbox => textbox.NewLine, (textbox, newline) => textbox.NewLine = newline); + /// + /// Defines the property + /// public static readonly StyledProperty InnerLeftContentProperty = AvaloniaProperty.Register(nameof(InnerLeftContent)); + /// + /// Defines the property + /// public static readonly StyledProperty InnerRightContentProperty = AvaloniaProperty.Register(nameof(InnerRightContent)); + /// + /// Defines the property + /// public static readonly StyledProperty RevealPasswordProperty = AvaloniaProperty.Register(nameof(RevealPassword)); + /// + /// Defines the property + /// public static readonly DirectProperty CanCutProperty = AvaloniaProperty.RegisterDirect( nameof(CanCut), o => o.CanCut); + /// + /// Defines the property + /// public static readonly DirectProperty CanCopyProperty = AvaloniaProperty.RegisterDirect( nameof(CanCopy), o => o.CanCopy); + /// + /// Defines the property + /// public static readonly DirectProperty CanPasteProperty = AvaloniaProperty.RegisterDirect( nameof(CanPaste), o => o.CanPaste); + /// + /// Defines the property + /// public static readonly StyledProperty IsUndoEnabledProperty = AvaloniaProperty.Register( nameof(IsUndoEnabled), defaultValue: true); + /// + /// Defines the property + /// public static readonly DirectProperty UndoLimitProperty = AvaloniaProperty.RegisterDirect( nameof(UndoLimit), @@ -212,9 +296,13 @@ namespace Avalonia.Controls RoutedEvent.Register( nameof(TextChanging), RoutingStrategies.Bubble); + /// + /// Stores the state information for available actions in the UndoRedoHelper + /// readonly struct UndoRedoState : IEquatable { public string? Text { get; } + public int CaretPosition { get; } public UndoRedoState(string? text, int caretPosition) @@ -287,18 +375,27 @@ namespace Avalonia.Controls UpdatePseudoclasses(); } + /// + /// Gets or sets a value that determines whether the TextBox allows and displays newline or return characters + /// public bool AcceptsReturn { get => GetValue(AcceptsReturnProperty); set => SetValue(AcceptsReturnProperty, value); } + /// + /// Gets or sets a value that determins whether the TextBox allows and displays tabs + /// public bool AcceptsTab { get => GetValue(AcceptsTabProperty); set => SetValue(AcceptsTabProperty, value); } + /// + /// Gets or sets the index of the text caret + /// public int CaretIndex { get => _caretIndex; @@ -315,36 +412,54 @@ namespace Avalonia.Controls } } + /// + /// Gets or sets a value whether this TextBox is read-only + /// public bool IsReadOnly { get => GetValue(IsReadOnlyProperty); set => SetValue(IsReadOnlyProperty, value); } + /// + /// Gets or sets the that should be used for password masking + /// public char PasswordChar { get => GetValue(PasswordCharProperty); set => SetValue(PasswordCharProperty, value); } + /// + /// Gets or sets a brush that is used to highlight selected text + /// public IBrush? SelectionBrush { get => GetValue(SelectionBrushProperty); set => SetValue(SelectionBrushProperty, value); } + /// + /// Gets or sets a brush that is used for the foreground of selected text + /// public IBrush? SelectionForegroundBrush { get => GetValue(SelectionForegroundBrushProperty); set => SetValue(SelectionForegroundBrushProperty, value); } + /// + /// Gets or sets a brush that is used for the text caret + /// public IBrush? CaretBrush { get => GetValue(CaretBrushProperty); set => SetValue(CaretBrushProperty, value); } + /// + /// Gets or sets the starting position of the text selected in the TextBox + /// public int SelectionStart { get => _selectionStart; @@ -365,6 +480,13 @@ namespace Avalonia.Controls } } + /// + /// Gets or sets the end position of the text selected in the TextBox + /// + /// + /// When the SelectionEnd is equal to , there is no + /// selected text and it marks the caret position + /// public int SelectionEnd { get => _selectionEnd; @@ -384,19 +506,28 @@ namespace Avalonia.Controls } } } - + + /// + /// Gets or sets the maximum character length of the TextBox + /// public int MaxLength { get => GetValue(MaxLengthProperty); set => SetValue(MaxLengthProperty, value); } + /// + /// Gets or sets the maximum number of lines the TextBox can contain + /// public int MaxLines { get => GetValue(MaxLinesProperty); set => SetValue(MaxLinesProperty, value); } + /// + /// Gets or sets the spacing between characters + /// public double LetterSpacing { get => GetValue(LetterSpacingProperty); @@ -412,6 +543,9 @@ namespace Avalonia.Controls set => SetValue(LineHeightProperty, value); } + /// + /// Gets or sets the Text content of the TextBox + /// [Content] public string? Text { @@ -441,6 +575,9 @@ namespace Avalonia.Controls } } + /// + /// Gets or sets the text selected in the TextBox + /// public string SelectedText { get => GetSelection(); @@ -477,6 +614,9 @@ namespace Avalonia.Controls set => SetValue(VerticalContentAlignmentProperty, value); } + /// + /// Gets or sets the of the TextBox + /// public TextAlignment TextAlignment { get => GetValue(TextAlignmentProperty); @@ -503,24 +643,36 @@ namespace Avalonia.Controls set => SetValue(UseFloatingWatermarkProperty, value); } + /// + /// Gets or sets custom content that is positioned on the left side of the text layout box + /// public object InnerLeftContent { get => GetValue(InnerLeftContentProperty); set => SetValue(InnerLeftContentProperty, value); } + /// + /// Gets or sets custom content that is positioned on the right side of the text layout box + /// public object InnerRightContent { get => GetValue(InnerRightContentProperty); set => SetValue(InnerRightContentProperty, value); } + /// + /// Gets or sets whether text masked by should be revealed + /// public bool RevealPassword { get => GetValue(RevealPasswordProperty); set => SetValue(RevealPasswordProperty, value); } + /// + /// Gets or sets the of the TextBox + /// public TextWrapping TextWrapping { get => GetValue(TextWrappingProperty); @@ -580,6 +732,9 @@ namespace Avalonia.Controls set => SetValue(IsUndoEnabledProperty, value); } + /// + /// Gets or sets the maximum number of items that can reside in the Undo stack + /// public int UndoLimit { get => _undoRedoHelper.Limit; @@ -621,18 +776,27 @@ namespace Avalonia.Controls private set => SetAndRaise(CanRedoProperty, ref _canRedo, value); } + /// + /// Raised when content is being copied to the clipboard + /// public event EventHandler? CopyingToClipboard { add => AddHandler(CopyingToClipboardEvent, value); remove => RemoveHandler(CopyingToClipboardEvent, value); } + /// + /// Raised when content is being cut to the clipboard + /// public event EventHandler? CuttingToClipboard { add => AddHandler(CuttingToClipboardEvent, value); remove => RemoveHandler(CuttingToClipboardEvent, value); } + /// + /// Raised when content is being pasted from the clipboard + /// public event EventHandler? PastingFromClipboard { add => AddHandler(PastingFromClipboardEvent, value); @@ -862,6 +1026,9 @@ namespace Avalonia.Controls return text; } + /// + /// Cuts the current text onto the clipboard + /// public async void Cut() { var text = GetSelection(); @@ -882,6 +1049,9 @@ namespace Avalonia.Controls } } + /// + /// Copies the current text onto the clipboard + /// public async void Copy() { var text = GetSelection(); @@ -900,6 +1070,9 @@ namespace Avalonia.Controls } } + /// + /// Pastes the current clipboard text content into the TextBox + /// public async void Paste() { var eventArgs = new RoutedEventArgs(PastingFromClipboardEvent); @@ -1434,6 +1607,9 @@ namespace Avalonia.Controls } } + /// + /// Clears the text in the TextBox + /// public void Clear() { Text = string.Empty; diff --git a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs index 976dbb5d5f..6ff72751a6 100644 --- a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs +++ b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs @@ -1,9 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Avalonia.Utilities; namespace Avalonia.Controls.Utils { @@ -20,8 +15,6 @@ namespace Avalonia.Controls.Utils void OnRedoStackChanged(); } - - private readonly LinkedList _states = new LinkedList(); private LinkedListNode? _currentNode; @@ -65,6 +58,7 @@ namespace Avalonia.Controls.Utils } public bool HasState => _currentNode != null; + public void UpdateLastState(TState state) { if (_states.Last != null) From 0db8d5a2d29bddbea21f919a69f3f827f1bf4933 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 21 Nov 2022 12:24:39 +0100 Subject: [PATCH 039/137] Refactored style attach benchmark. Now tries to simulate an application with a lot of styles applied at different points in the logical tree. Make `StyledElement.ApplyStyling` a public API in order to do this. --- src/Avalonia.Base/StyledElement.cs | 6 +- .../Styling/StyleAttachBenchmark.cs | 47 ------- .../Styling/Style_Apply_Detach_Complex.cs | 126 ++++++++++++++++++ 3 files changed, 131 insertions(+), 48 deletions(-) delete mode 100644 tests/Avalonia.Benchmarks/Styling/StyleAttachBenchmark.cs create mode 100644 tests/Avalonia.Benchmarks/Styling/Style_Apply_Detach_Complex.cs diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs index bba9685ed8..2f3f672d54 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -344,10 +344,14 @@ namespace Avalonia /// Applies styling to the control if the control is initialized and styling is not /// already applied. /// + /// + /// The styling system will automatically apply styling when required, so it should not + /// usually be necessary to call this method manually. + /// /// /// A value indicating whether styling is now applied to the control. /// - protected bool ApplyStyling() + public bool ApplyStyling() { if (_initCount == 0 && !_styled) { diff --git a/tests/Avalonia.Benchmarks/Styling/StyleAttachBenchmark.cs b/tests/Avalonia.Benchmarks/Styling/StyleAttachBenchmark.cs deleted file mode 100644 index 7dad517e51..0000000000 --- a/tests/Avalonia.Benchmarks/Styling/StyleAttachBenchmark.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Avalonia.Controls; -using Avalonia.Styling; -using Avalonia.UnitTests; -using BenchmarkDotNet.Attributes; - -namespace Avalonia.Benchmarks.Styling -{ - [MemoryDiagnoser] - public class StyleAttachBenchmark : IDisposable - { - private readonly IDisposable _app; - private readonly TestRoot _root; - private readonly TextBox _control; - - public StyleAttachBenchmark() - { - _app = UnitTestApplication.Start( - TestServices.StyledWindow.With( - renderInterface: new NullRenderingPlatform(), - threadingInterface: new NullThreadingPlatform())); - - _root = new TestRoot(true, null) - { - Renderer = new NullRenderer(), - }; - - _control = new TextBox(); - } - - [Benchmark] - [MethodImpl(MethodImplOptions.NoInlining)] - public void AttachTextBoxStyles() - { - var styles = UnitTestApplication.Current.Styles; - - styles.TryAttach(_control, UnitTestApplication.Current); - ((IStyleable)_control).DetachStyles(); - } - - public void Dispose() - { - _app.Dispose(); - } - } -} diff --git a/tests/Avalonia.Benchmarks/Styling/Style_Apply_Detach_Complex.cs b/tests/Avalonia.Benchmarks/Styling/Style_Apply_Detach_Complex.cs new file mode 100644 index 0000000000..fa8ad00bf8 --- /dev/null +++ b/tests/Avalonia.Benchmarks/Styling/Style_Apply_Detach_Complex.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Avalonia.Controls; +using Avalonia.Styling; +using Avalonia.UnitTests; +using BenchmarkDotNet.Attributes; + +namespace Avalonia.Benchmarks.Styling +{ + [MemoryDiagnoser] + public class Style_Apply_Detach_Complex : IDisposable + { + private readonly IDisposable _app; + private readonly TestRoot _root; + private readonly TextBox _control; + + public Style_Apply_Detach_Complex() + { + _app = UnitTestApplication.Start( + TestServices.StyledWindow.With( + renderInterface: new NullRenderingPlatform(), + threadingInterface: new NullThreadingPlatform())); + + // Simulate an application with a lot of styles by creating a tree of nested panels, + // each with a bunch of styles applied. + var (rootPanel, leafPanel) = CreateNestedPanels(10); + + // We're benchmarking how long it takes to apply styles to a TextBox in this situation. + _control = new TextBox(); + leafPanel.Children.Add(_control); + + _root = new TestRoot(true, rootPanel) + { + Renderer = new NullRenderer(), + }; + } + + [Benchmark] + [MethodImpl(MethodImplOptions.NoInlining)] + public void Apply_Detach_Styles() + { + // Styles will have already been attached when attached to the logical tree, so remove + // the styles first. + if ((string)_control.Tag != "TextBox") + throw new Exception("Invalid benchmark state"); + + ((IStyleable)_control).DetachStyles(); + + if (_control.Tag is not null) + throw new Exception("Invalid benchmark state"); + + // Then re-apply the styles. + _control.ApplyStyling(); + } + + public void Dispose() + { + _app.Dispose(); + } + + private static (Panel, Panel) CreateNestedPanels(int count) + { + var root = new Panel(); + var last = root; + + for (var i = 0; i < count; ++i) + { + var panel = new Panel(); + panel.Styles.AddRange(CreateStyles()); + last.Children.Add(panel); + last = panel; + } + + return (root, last); + } + + private static IEnumerable CreateStyles() + { + var types = new[] + { + typeof(Border), + typeof(Button), + typeof(ButtonSpinner), + typeof(Carousel), + typeof(CheckBox), + typeof(ComboBox), + typeof(ContentControl), + typeof(Expander), + typeof(ItemsControl), + typeof(Label), + typeof(ListBox), + typeof(ProgressBar), + typeof(RadioButton), + typeof(RepeatButton), + typeof(ScrollViewer), + typeof(Slider), + typeof(Spinner), + typeof(SplitView), + typeof(TextBox), + typeof(ToggleSwitch), + typeof(TreeView), + typeof(Viewbox), + typeof(Window), + }; + + foreach (var type in types) + { + yield return new Style(x => x.OfType(type)) + { + Setters = { new Setter(Control.TagProperty, type.Name) } + }; + + yield return new Style(x => x.OfType(type).Class("foo")) + { + Setters = { new Setter(Control.TagProperty, type.Name + " foo") } + }; + + yield return new Style(x => x.OfType(type).Class("bar")) + { + Setters = { new Setter(Control.TagProperty, type.Name + " bar") } + }; + } + } + } +} From 1a338ac087f31b45e4e69513f9d3ab925c690f9c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 10 Nov 2022 10:09:57 +0100 Subject: [PATCH 040/137] Remove IStyler and make style apply internal. - Removes the `IStyler` service and the `Styler` implementation - Moves the logic for applying styles and control themes into `StyledElement` - Removes the style `TryAttach` method from the public API - Removes style caching for now - this will need to be added back --- src/Avalonia.Base/StyledElement.cs | 123 ++++++--- src/Avalonia.Base/Styling/ControlTheme.cs | 27 +- src/Avalonia.Base/Styling/IStyle.cs | 10 - src/Avalonia.Base/Styling/IStyleable.cs | 5 - src/Avalonia.Base/Styling/IStyler.cs | 8 - src/Avalonia.Base/Styling/Style.cs | 54 ++-- src/Avalonia.Base/Styling/StyleBase.cs | 30 ++- src/Avalonia.Base/Styling/StyleCache.cs | 58 ---- src/Avalonia.Base/Styling/Styler.cs | 35 --- src/Avalonia.Base/Styling/Styles.cs | 47 ++-- src/Avalonia.Controls/Application.cs | 2 - src/Avalonia.Controls/TopLevel.cs | 3 +- .../Styling/StyleInclude.cs | 2 - .../Animation/AnimatableTests.cs | 2 +- .../Styling/StyleTests.cs | 194 ++++++-------- .../Styling/StyledElementTests.cs | 78 +++--- .../Styling/StyledElementTests_Theming.cs | 21 +- .../Styling/ResourceBenchmarks.cs | 1 - .../Themes/FluentBenchmark.cs | 1 - .../ContentControlTests.cs | 63 ++--- .../ListBoxTests.cs | 4 +- .../Primitives/SelectingItemsControlTests.cs | 12 + .../Primitives/TemplatedControlTests.cs | 249 +++++++++--------- .../TabControlTests.cs | 28 +- .../TreeViewTests.cs | 2 +- .../UserControlTests.cs | 25 +- .../Utils/HotKeyManagerTests.cs | 21 +- .../CompiledBindingExtensionTests.cs | 6 + tests/Avalonia.UnitTests/TestServices.cs | 14 +- .../Avalonia.UnitTests/UnitTestApplication.cs | 5 +- 30 files changed, 494 insertions(+), 636 deletions(-) delete mode 100644 src/Avalonia.Base/Styling/IStyler.cs delete mode 100644 src/Avalonia.Base/Styling/StyleCache.cs delete mode 100644 src/Avalonia.Base/Styling/Styler.cs diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs index 2f3f672d54..c72f398fd9 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -355,22 +355,19 @@ namespace Avalonia { if (_initCount == 0 && !_styled) { - var styler = AvaloniaLocator.Current.GetService(); var hasPromotedTheme = _hasPromotedTheme; - if (styler is object) - { - GetValueStore().BeginStyling(); + GetValueStore().BeginStyling(); - try - { - styler.ApplyStyles(this); - } - finally - { - _styled = true; - GetValueStore().EndStyling(); - } + try + { + ApplyControlTheme(); + ApplyStyles(this); + } + finally + { + _styled = true; + GetValueStore().EndStyling(); } if (hasPromotedTheme) @@ -509,31 +506,6 @@ namespace Avalonia }; } - ControlTheme? IStyleable.GetEffectiveTheme() - { - var theme = Theme; - - // Explitly set Theme property takes precedence. - if (theme is not null) - return theme; - - // If the Theme property is not set, try to find a ControlTheme resource with our StyleKey. - if (_implicitTheme is null) - { - var key = ((IStyleable)this).StyleKey; - - if (this.TryFindResource(key, out var value) && value is ControlTheme t) - _implicitTheme = t; - else - _implicitTheme = s_invalidTheme; - } - - if (_implicitTheme != s_invalidTheme) - return _implicitTheme; - - return null; - } - void IStyleable.DetachStyles() => DetachStyles(); void IStyleHost.StylesAdded(IReadOnlyList styles) @@ -670,6 +642,31 @@ namespace Avalonia { } + internal ControlTheme? GetEffectiveTheme() + { + var theme = Theme; + + // Explitly set Theme property takes precedence. + if (theme is not null) + return theme; + + // If the Theme property is not set, try to find a ControlTheme resource with our StyleKey. + if (_implicitTheme is null) + { + var key = ((IStyleable)this).StyleKey; + + if (this.TryFindResource(key, out var value) && value is ControlTheme t) + _implicitTheme = t; + else + _implicitTheme = s_invalidTheme; + } + + if (_implicitTheme != s_invalidTheme) + return _implicitTheme; + + return null; + } + private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted) { if (o is StyledElement element) @@ -734,6 +731,56 @@ namespace Avalonia } } + private void ApplyControlTheme() + { + var theme = GetEffectiveTheme(); + + if (theme is not null) + ApplyControlTheme(theme); + + if (TemplatedParent is StyledElement styleableParent && + styleableParent.GetEffectiveTheme() is { } parentTheme) + { + ApplyControlTheme(parentTheme); + } + } + + private void ApplyControlTheme(ControlTheme theme) + { + if (theme.BasedOn is ControlTheme basedOn) + ApplyControlTheme(basedOn); + + theme.TryAttach(this, null); + + if (theme.HasChildren) + { + foreach (var child in theme.Children) + ApplyStyle(child, null); + } + } + + private void ApplyStyles(IStyleHost host) + { + var parent = host.StylingParent; + if (parent != null) + ApplyStyles(parent); + + if (host.IsStylesInitialized) + { + foreach (var style in host.Styles) + ApplyStyle(style, host); + } + } + + private void ApplyStyle(IStyle style, IStyleHost? host) + { + if (style is Style s) + s.TryAttach(this, host); + + foreach (var child in style.Children) + ApplyStyle(child, host); + } + private void OnAttachedToLogicalTreeCore(LogicalTreeAttachmentEventArgs e) { if (this.GetLogicalParent() == null && !(this is ILogicalRoot)) diff --git a/src/Avalonia.Base/Styling/ControlTheme.cs b/src/Avalonia.Base/Styling/ControlTheme.cs index 46a3267f70..2971703c95 100644 --- a/src/Avalonia.Base/Styling/ControlTheme.cs +++ b/src/Avalonia.Base/Styling/ControlTheme.cs @@ -29,34 +29,27 @@ namespace Avalonia.Styling /// public ControlTheme? BasedOn { get; set; } - public override SelectorMatchResult TryAttach(IStyleable target, object? host) + public override string ToString() => TargetType?.Name ?? "ControlTheme"; + + internal override void SetParent(StyleBase? parent) + { + throw new InvalidOperationException("ControlThemes cannot be added as a nested style."); + } + + internal override SelectorMatchResult TryAttach(IStyleable target, object? host) { _ = target ?? throw new ArgumentNullException(nameof(target)); if (TargetType is null) throw new InvalidOperationException("ControlTheme has no TargetType."); - var result = BasedOn?.TryAttach(target, host) ?? SelectorMatchResult.NeverThisType; - if (HasSettersOrAnimations && TargetType.IsAssignableFrom(target.StyleKey)) { Attach(target, null); - result = SelectorMatchResult.AlwaysThisType; + return SelectorMatchResult.AlwaysThisType; } - var childResult = TryAttachChildren(target, host); - - if (childResult > result) - result = childResult; - - return result; - } - - public override string ToString() => TargetType?.Name ?? "ControlTheme"; - - internal override void SetParent(StyleBase? parent) - { - throw new InvalidOperationException("ControlThemes cannot be added as a nested style."); + return SelectorMatchResult.NeverThisType; } } } diff --git a/src/Avalonia.Base/Styling/IStyle.cs b/src/Avalonia.Base/Styling/IStyle.cs index 417739fb28..2dbaf963ee 100644 --- a/src/Avalonia.Base/Styling/IStyle.cs +++ b/src/Avalonia.Base/Styling/IStyle.cs @@ -14,15 +14,5 @@ namespace Avalonia.Styling /// Gets a collection of child styles. /// IReadOnlyList Children { get; } - - /// - /// Attaches the style and any child styles to a control if the style's selector matches. - /// - /// The control to attach to. - /// The element that hosts the style. - /// - /// A describing how the style matches the control. - /// - SelectorMatchResult TryAttach(IStyleable target, object? host); } } diff --git a/src/Avalonia.Base/Styling/IStyleable.cs b/src/Avalonia.Base/Styling/IStyleable.cs index e94fc5c4e6..dcc3988280 100644 --- a/src/Avalonia.Base/Styling/IStyleable.cs +++ b/src/Avalonia.Base/Styling/IStyleable.cs @@ -25,11 +25,6 @@ namespace Avalonia.Styling /// ITemplatedControl? TemplatedParent { get; } - /// - /// Gets the effective theme for the control as used by the syling system. - /// - ControlTheme? GetEffectiveTheme(); - void DetachStyles(); } } diff --git a/src/Avalonia.Base/Styling/IStyler.cs b/src/Avalonia.Base/Styling/IStyler.cs deleted file mode 100644 index d6477d169e..0000000000 --- a/src/Avalonia.Base/Styling/IStyler.cs +++ /dev/null @@ -1,8 +0,0 @@ - -namespace Avalonia.Styling -{ - public interface IStyler - { - void ApplyStyles(IStyleable control); - } -} diff --git a/src/Avalonia.Base/Styling/Style.cs b/src/Avalonia.Base/Styling/Style.cs index 913c437bc4..aad91824d3 100644 --- a/src/Avalonia.Base/Styling/Style.cs +++ b/src/Avalonia.Base/Styling/Style.cs @@ -1,5 +1,4 @@ using System; -using Avalonia.PropertyStore; namespace Avalonia.Styling { @@ -35,35 +34,6 @@ namespace Avalonia.Styling set => _selector = ValidateSelector(value); } - public override SelectorMatchResult TryAttach(IStyleable target, object? host) - { - _ = target ?? throw new ArgumentNullException(nameof(target)); - - var result = SelectorMatchResult.NeverThisType; - - if (HasSettersOrAnimations) - { - var match = Selector?.Match(target, Parent, true) ?? - (target == host ? - SelectorMatch.AlwaysThisInstance : - SelectorMatch.NeverThisInstance); - - if (match.IsMatch) - { - Attach(target, match.Activator); - } - - result = match.Result; - } - - var childResult = TryAttachChildren(target, host); - - if (childResult > result) - result = childResult; - - return result; - } - /// /// Returns a string representation of the style. /// @@ -88,6 +58,30 @@ namespace Avalonia.Styling base.SetParent(parent); } + internal override SelectorMatchResult TryAttach(IStyleable target, object? host) + { + _ = target ?? throw new ArgumentNullException(nameof(target)); + + var result = SelectorMatchResult.NeverThisType; + + if (HasSettersOrAnimations) + { + var match = Selector?.Match(target, Parent, true) ?? + (target == host ? + SelectorMatch.AlwaysThisInstance : + SelectorMatch.NeverThisInstance); + + if (match.IsMatch) + { + Attach(target, match.Activator); + } + + result = match.Result; + } + + return result; + } + private static Selector? ValidateSelector(Selector? selector) { if (selector is TemplateSelector) diff --git a/src/Avalonia.Base/Styling/StyleBase.cs b/src/Avalonia.Base/Styling/StyleBase.cs index c914fbf8cc..dba80df2e5 100644 --- a/src/Avalonia.Base/Styling/StyleBase.cs +++ b/src/Avalonia.Base/Styling/StyleBase.cs @@ -18,7 +18,6 @@ namespace Avalonia.Styling private IResourceDictionary? _resources; private List? _setters; private List? _animations; - private StyleCache? _childCache; private StyleInstance? _sharedInstance; public IList Children => _children ??= new(this); @@ -67,6 +66,7 @@ namespace Avalonia.Styling bool IResourceNode.HasResources => _resources?.Count > 0; IReadOnlyList IStyle.Children => (IReadOnlyList?)_children ?? Array.Empty(); + internal bool HasChildren => _children?.Count > 0; internal bool HasSettersOrAnimations => _setters?.Count > 0 || _animations?.Count > 0; public void Add(ISetter setter) => Setters.Add(setter); @@ -74,14 +74,26 @@ namespace Avalonia.Styling public event EventHandler? OwnerChanged; - public abstract SelectorMatchResult TryAttach(IStyleable target, object? host); - public bool TryGetResource(object key, out object? result) { - result = null; - return _resources?.TryGetResource(key, out result) ?? false; + if (_resources is not null && _resources.TryGetResource(key, out result)) + return true; + + if (_children is not null) + { + for (var i = 0; i < _children.Count; ++i) + { + if (_children[i].TryGetResource(key, out result)) + return true; + } + } + + result= null; + return false; } + internal abstract SelectorMatchResult TryAttach(IStyleable target, object? host); + internal ValueFrame Attach(IStyleable target, IStyleActivator? activator) { if (target is not AvaloniaObject ao) @@ -124,14 +136,6 @@ namespace Avalonia.Styling return instance; } - internal SelectorMatchResult TryAttachChildren(IStyleable target, object? host) - { - if (_children is null || _children.Count == 0) - return SelectorMatchResult.NeverThisType; - _childCache ??= new StyleCache(); - return _childCache.TryAttach(_children, target, host); - } - internal virtual void SetParent(StyleBase? parent) => Parent = parent; void IResourceProvider.AddOwner(IResourceHost owner) diff --git a/src/Avalonia.Base/Styling/StyleCache.cs b/src/Avalonia.Base/Styling/StyleCache.cs deleted file mode 100644 index 81196f6a27..0000000000 --- a/src/Avalonia.Base/Styling/StyleCache.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Avalonia.Styling -{ - /// - /// Simple cache for improving performance of applying styles. - /// - /// - /// Maps to a list of styles that are known be be possible - /// matches. - /// - internal class StyleCache : Dictionary?> - { - public SelectorMatchResult TryAttach(IList styles, IStyleable target, object? host) - { - if (TryGetValue(target.StyleKey, out var cached)) - { - if (cached is object) - { - var result = SelectorMatchResult.NeverThisType; - - foreach (var style in cached) - { - var childResult = style.TryAttach(target, host); - if (childResult > result) - result = childResult; - } - - return result; - } - else - { - return SelectorMatchResult.NeverThisType; - } - } - else - { - List? matches = null; - - foreach (var child in styles) - { - if (child.TryAttach(target, host) != SelectorMatchResult.NeverThisType) - { - matches ??= new List(); - matches.Add(child); - } - } - - Add(target.StyleKey, matches); - - return matches is null ? - SelectorMatchResult.NeverThisType : - SelectorMatchResult.AlwaysThisType; - } - } - } -} diff --git a/src/Avalonia.Base/Styling/Styler.cs b/src/Avalonia.Base/Styling/Styler.cs deleted file mode 100644 index ad5c1cd102..0000000000 --- a/src/Avalonia.Base/Styling/Styler.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -namespace Avalonia.Styling -{ - public class Styler : IStyler - { - public void ApplyStyles(IStyleable target) - { - _ = target ?? throw new ArgumentNullException(nameof(target)); - - // Apply the control theme. - target.GetEffectiveTheme()?.TryAttach(target, target); - - // If the control has a themed templated parent then apply the styles from the - // templated parent theme. - if (target.TemplatedParent is IStyleable styleableParent) - styleableParent.GetEffectiveTheme()?.TryAttach(target, styleableParent); - - // Apply styles from the rest of the tree. - if (target is IStyleHost styleHost) - ApplyStyles(target, styleHost); - } - - private void ApplyStyles(IStyleable target, IStyleHost host) - { - var parent = host.StylingParent; - - if (parent != null) - ApplyStyles(target, parent); - - if (host.IsStylesInitialized) - host.Styles.TryAttach(target, host); - } - } -} diff --git a/src/Avalonia.Base/Styling/Styles.cs b/src/Avalonia.Base/Styling/Styles.cs index c213475bb7..76271b9748 100644 --- a/src/Avalonia.Base/Styling/Styles.cs +++ b/src/Avalonia.Base/Styling/Styles.cs @@ -5,8 +5,6 @@ using System.Collections.Specialized; using Avalonia.Collections; using Avalonia.Controls; -#nullable enable - namespace Avalonia.Styling { /// @@ -20,7 +18,6 @@ namespace Avalonia.Styling private readonly AvaloniaList _styles = new(); private IResourceHost? _owner; private IResourceDictionary? _resources; - private StyleCache? _cache; public Styles() { @@ -116,12 +113,6 @@ namespace Avalonia.Styling set => _styles[index] = value; } - public SelectorMatchResult TryAttach(IStyleable target, object? host) - { - _cache ??= new StyleCache(); - return _cache.TryAttach(this, target, host); - } - /// public bool TryGetResource(object key, out object? value) { @@ -234,6 +225,22 @@ namespace Avalonia.Styling } } + internal SelectorMatchResult TryAttach(IStyleable target, object? host) + { + var result = SelectorMatchResult.NeverThisType; + + foreach (var s in this) + { + if (s is not Style style) + continue; + var r = style.TryAttach(target, host); + if (r > result) + result = r; + } + + return result; + } + private static IReadOnlyList ToReadOnlyList(ICollection list) { if (list is IReadOnlyList readOnlyList) @@ -246,7 +253,7 @@ namespace Avalonia.Styling return result; } - private static void InternalAdd(IList items, IResourceHost? owner, ref StyleCache? cache) + private static void InternalAdd(IList items, IResourceHost? owner) { if (owner is not null) { @@ -260,14 +267,9 @@ namespace Avalonia.Styling (owner as IStyleHost)?.StylesAdded(ToReadOnlyList(items)); } - - if (items.Count > 0) - { - cache = null; - } } - private static void InternalRemove(IList items, IResourceHost? owner, ref StyleCache? cache) + private static void InternalRemove(IList items, IResourceHost? owner) { if (owner is not null) { @@ -281,11 +283,6 @@ namespace Avalonia.Styling (owner as IStyleHost)?.StylesRemoved(ToReadOnlyList(items)); } - - if (items.Count > 0) - { - cache = null; - } } private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -300,14 +297,14 @@ namespace Avalonia.Styling switch (e.Action) { case NotifyCollectionChangedAction.Add: - InternalAdd(e.NewItems!, currentOwner, ref _cache); + InternalAdd(e.NewItems!, currentOwner); break; case NotifyCollectionChangedAction.Remove: - InternalRemove(e.OldItems!, currentOwner, ref _cache); + InternalRemove(e.OldItems!, currentOwner); break; case NotifyCollectionChangedAction.Replace: - InternalRemove(e.OldItems!, currentOwner, ref _cache); - InternalAdd(e.NewItems!, currentOwner, ref _cache); + InternalRemove(e.OldItems!, currentOwner); + InternalAdd(e.NewItems!, currentOwner); break; } diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index 69fd6cabf8..dc9a0207ad 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -39,7 +39,6 @@ namespace Avalonia private readonly Lazy _clipboard = new Lazy(() => (IClipboard?)AvaloniaLocator.Current.GetService(typeof(IClipboard))); - private readonly Styler _styler = new Styler(); private Styles? _styles; private IResourceDictionary? _resources; private bool _notifyingResourcesChanged; @@ -232,7 +231,6 @@ namespace Avalonia .Bind().ToConstant(FocusManager) .Bind().ToConstant(InputManager) .Bind().ToTransient() - .Bind().ToConstant(_styler) .Bind().ToConstant(AvaloniaScheduler.Instance) .Bind().ToConstant(DragDropDevice.Instance); diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 6804c9ecb9..515535bf39 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -145,7 +145,6 @@ namespace Avalonia.Controls _actualTransparencyLevel = PlatformImpl.TransparencyLevel; dependencyResolver = dependencyResolver ?? AvaloniaLocator.Current; - var styler = TryGetService(dependencyResolver); _accessKeyHandler = TryGetService(dependencyResolver); _inputManager = TryGetService(dependencyResolver); @@ -183,7 +182,7 @@ namespace Avalonia.Controls _globalStyles.GlobalStylesRemoved += ((IStyleHost)this).StylesRemoved; } - styler?.ApplyStyles(this); + ApplyStyling(); ClientSize = impl.ClientSize; FrameSize = impl.FrameSize; diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs index b1725245bb..8af49b5480 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs @@ -82,8 +82,6 @@ namespace Avalonia.Markup.Xaml.Styling } } - public SelectorMatchResult TryAttach(IStyleable target, object? host) => Loaded.TryAttach(target, host); - public bool TryGetResource(object key, out object? value) { if (!_isLoading) diff --git a/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs b/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs index 19ae0dc260..668b8a875c 100644 --- a/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs +++ b/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs @@ -498,7 +498,7 @@ namespace Avalonia.Base.UnitTests.Animation private static IDisposable Start() { var clock = new MockGlobalClock(); - var services = TestServices.RealStyler.With(globalClock: clock); + var services = new TestServices(globalClock: clock); return UnitTestApplication.Start(services); } diff --git a/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs b/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs index b7455f9b3f..e7ecba61a7 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs @@ -5,7 +5,6 @@ using Avalonia.Base.UnitTests.Animation; using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Data; -using Avalonia.Diagnostics; using Avalonia.Styling; using Avalonia.UnitTests; using Moq; @@ -301,8 +300,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Inactive_Values_Should_Not_Be_Made_Active_During_Style_Attach() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); - var root = new TestRoot { Styles = @@ -337,8 +334,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Inactive_Bindings_Should_Not_Be_Made_Active_During_Style_Attach() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); - var root = new TestRoot { Styles = @@ -380,8 +375,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Inactive_Values_Should_Not_Be_Made_Active_During_Style_Detach() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); - var root = new TestRoot { Styles = @@ -417,8 +410,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Inactive_Values_Should_Not_Be_Made_Active_During_Style_Detach_2() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); - var root = new TestRoot { Styles = @@ -454,8 +445,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Inactive_Bindings_Should_Not_Be_Made_Active_During_Style_Detach() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); - var root = new TestRoot { Styles = @@ -598,41 +587,36 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Removing_Style_Should_Detach_From_Control() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var border = new Border(); + var root = new TestRoot { - var border = new Border(); - var root = new TestRoot - { - Styles = - { - new Style(x => x.OfType()) + Styles = + { + new Style(x => x.OfType()) + { + Setters = { - Setters = - { - new Setter(Border.BorderThicknessProperty, new Thickness(4)), - } + new Setter(Border.BorderThicknessProperty, new Thickness(4)), } - }, - Child = border, - }; + } + }, + Child = border, + }; - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(4), border.BorderThickness); + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(4), border.BorderThickness); - root.Styles.RemoveAt(0); - Assert.Equal(new Thickness(0), border.BorderThickness); - } + root.Styles.RemoveAt(0); + Assert.Equal(new Thickness(0), border.BorderThickness); } [Fact] public void Adding_Style_Should_Attach_To_Control() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var border = new Border(); + var root = new TestRoot { - var border = new Border(); - var root = new TestRoot - { - Styles = + Styles = { new Style(x => x.OfType()) { @@ -642,34 +626,31 @@ namespace Avalonia.Base.UnitTests.Styling } } }, - Child = border, - }; + Child = border, + }; - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(4), border.BorderThickness); + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(4), border.BorderThickness); - root.Styles.Add(new Style(x => x.OfType()) - { - Setters = + root.Styles.Add(new Style(x => x.OfType()) + { + Setters = { new Setter(Border.BorderThicknessProperty, new Thickness(6)), } - }); + }); - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(6), border.BorderThickness); - } + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(6), border.BorderThickness); } [Fact] public void Removing_Style_With_Nested_Style_Should_Detach_From_Control() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var border = new Border(); + var root = new TestRoot { - var border = new Border(); - var root = new TestRoot - { - Styles = + Styles = { new Styles { @@ -682,96 +663,89 @@ namespace Avalonia.Base.UnitTests.Styling } } }, - Child = border, - }; + Child = border, + }; - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(4), border.BorderThickness); + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(4), border.BorderThickness); - root.Styles.RemoveAt(0); - Assert.Equal(new Thickness(0), border.BorderThickness); - } + root.Styles.RemoveAt(0); + Assert.Equal(new Thickness(0), border.BorderThickness); } - + [Fact] public void Adding_Nested_Style_Should_Attach_To_Control() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var border = new Border(); + var root = new TestRoot { - var border = new Border(); - var root = new TestRoot + Styles = { - Styles = + new Styles { - new Styles + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter(Border.BorderThicknessProperty, new Thickness(4)), - } + new Setter(Border.BorderThicknessProperty, new Thickness(4)), } } - }, - Child = border, - }; + } + }, + Child = border, + }; - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(4), border.BorderThickness); + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(4), border.BorderThickness); - ((Styles)root.Styles[0]).Add(new Style(x => x.OfType()) + ((Styles)root.Styles[0]).Add(new Style(x => x.OfType()) + { + Setters = { - Setters = - { - new Setter(Border.BorderThicknessProperty, new Thickness(6)), - } - }); + new Setter(Border.BorderThicknessProperty, new Thickness(6)), + } + }); - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(6), border.BorderThickness); - } + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(6), border.BorderThickness); } [Fact] public void Removing_Nested_Style_Should_Detach_From_Control() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var border = new Border(); + var root = new TestRoot { - var border = new Border(); - var root = new TestRoot + Styles = { - Styles = + new Styles { - new Styles + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter(Border.BorderThicknessProperty, new Thickness(4)), - } - }, - new Style(x => x.OfType()) + new Setter(Border.BorderThicknessProperty, new Thickness(4)), + } + }, + new Style(x => x.OfType()) + { + Setters = { - Setters = - { - new Setter(Border.BorderThicknessProperty, new Thickness(6)), - } - }, - } - }, - Child = border, - }; + new Setter(Border.BorderThicknessProperty, new Thickness(6)), + } + }, + } + }, + Child = border, + }; - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(6), border.BorderThickness); + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(6), border.BorderThickness); - ((Styles)root.Styles[0]).RemoveAt(1); + ((Styles)root.Styles[0]).RemoveAt(1); - root.Measure(Size.Infinity); - Assert.Equal(new Thickness(4), border.BorderThickness); - } + root.Measure(Size.Infinity); + Assert.Equal(new Thickness(4), border.BorderThickness); } [Fact] diff --git a/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests.cs b/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests.cs index c01e22347b..65fe50b545 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests.cs @@ -249,65 +249,67 @@ namespace Avalonia.Base.UnitTests.Styling } [Fact] - public void Adding_Tree_To_IStyleRoot_Should_Style_Controls() + public void Adding_Tree_To_Root_Should_Style_Controls() { - using (AvaloniaLocator.EnterScope()) + var root = new TestRoot { - var root = new TestRoot(); - var parent = new Border(); - var child = new Border(); - var grandchild = new Control(); - var styler = new Mock(); - - AvaloniaLocator.CurrentMutable.Bind().ToConstant(styler.Object); + Styles = + { + new Style(x => x.Is()) + { + Setters = { new Setter(Control.TagProperty, "foo") } + } + } + }; - parent.Child = child; - child.Child = grandchild; + var grandchild = new Control(); + var child = new Border { Child = grandchild }; + var parent = new Border { Child = child }; - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Never()); + Assert.Null(parent.Tag); + Assert.Null(child.Tag); + Assert.Null(grandchild.Tag); - root.Child = parent; + root.Child = parent; - styler.Verify(x => x.ApplyStyles(parent), Times.Once()); - styler.Verify(x => x.ApplyStyles(child), Times.Once()); - styler.Verify(x => x.ApplyStyles(grandchild), Times.Once()); - } + Assert.Equal("foo", parent.Tag); + Assert.Equal("foo", child.Tag); + Assert.Equal("foo", grandchild.Tag); } [Fact] public void Styles_Not_Applied_Until_Initialization_Finished() { - using (AvaloniaLocator.EnterScope()) + var root = new TestRoot { - var root = new TestRoot(); - var child = new Border(); - var styler = new Mock(); + Styles = + { + new Style(x => x.Is()) + { + Setters = { new Setter(Control.TagProperty, "foo") } + } + } + }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(styler.Object); + var child = new Border(); - ((ISupportInitialize)child).BeginInit(); - root.Child = child; - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Never()); + ((ISupportInitialize)child).BeginInit(); + root.Child = child; + Assert.Null(child.Tag); - ((ISupportInitialize)child).EndInit(); - styler.Verify(x => x.ApplyStyles(child), Times.Once()); - } + ((ISupportInitialize)child).EndInit(); + Assert.Equal("foo", child.Tag); } [Fact] public void Name_Cannot_Be_Set_After_Added_To_Logical_Tree() { - using (AvaloniaLocator.EnterScope()) - { - var root = new TestRoot(); - var child = new Border(); - - AvaloniaLocator.CurrentMutable.BindToSelf(new Styler()); + var root = new TestRoot(); + var child = new Border(); - root.Child = child; + root.Child = child; - Assert.Throws(() => child.Name = "foo"); - } + Assert.Throws(() => child.Name = "foo"); } [Fact] @@ -328,7 +330,7 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Style_Is_Removed_When_Control_Removed_From_Logical_Tree() { - var app = UnitTestApplication.Start(TestServices.RealStyler); + var app = UnitTestApplication.Start(); var target = new Border(); var root = new TestRoot { diff --git a/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs b/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs index 45188de6cb..a1dac931ce 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs @@ -19,7 +19,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Is_Applied_When_Attached_To_Logical_Tree() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); Assert.Null(target.Template); @@ -37,7 +36,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Is_Applied_To_Derived_Class_When_Attached_To_Logical_Tree() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = new DerivedThemedControl { Theme = CreateTheme(), @@ -58,7 +56,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Is_Detached_When_Theme_Property_Cleared() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); var root = CreateRoot(target); @@ -71,8 +68,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Is_Detached_From_Template_Controls_When_Theme_Property_Cleared() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); - var theme = new ControlTheme { TargetType = typeof(ThemedControl), @@ -105,7 +100,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Is_Applied_On_Layout_After_Theme_Property_Changes() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = new ThemedControl(); var root = CreateRoot(target); @@ -124,7 +118,6 @@ public class StyledElementTests_Theming [Fact] public void BasedOn_Theme_Is_Applied_When_Attached_To_Logical_Tree() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(CreateDerivedTheme()); Assert.Null(target.Template); @@ -163,7 +156,6 @@ public class StyledElementTests_Theming [Fact] public void Implicit_Theme_Is_Applied_When_Attached_To_Logical_Tree() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); var root = CreateRoot(target); Assert.NotNull(target.Template); @@ -178,21 +170,19 @@ public class StyledElementTests_Theming [Fact] public void Implicit_Theme_Is_Cleared_When_Removed_From_Logical_Tree() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); var root = CreateRoot(target); - Assert.NotNull(((IStyleable)target).GetEffectiveTheme()); + Assert.NotNull(target.GetEffectiveTheme()); root.Child = null; - Assert.Null(((IStyleable)target).GetEffectiveTheme()); + Assert.Null(target.GetEffectiveTheme()); } [Fact] public void Nested_Style_Can_Override_Property_In_Inner_Templated_Control() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = new ThemedControl2 { Theme = new ControlTheme(typeof(ThemedControl2)) @@ -236,7 +226,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Is_Applied_When_Attached_To_Logical_Tree() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); Assert.Null(target.Theme); @@ -248,16 +237,15 @@ public class StyledElementTests_Theming Assert.NotNull(target.Template); var border = Assert.IsType(target.VisualChild); - Assert.Equal(border.Background, Brushes.Red); + Assert.Equal(Brushes.Red, border.Background); target.Classes.Add("foo"); - Assert.Equal(border.Background, Brushes.Green); + Assert.Equal(Brushes.Green, border.Background); } [Fact] public void Theme_Can_Be_Changed_By_Style_Class() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); var theme1 = CreateTheme(); var theme2 = new ControlTheme(typeof(ThemedControl)); @@ -290,7 +278,6 @@ public class StyledElementTests_Theming [Fact] public void Theme_Can_Be_Set_To_LocalValue_While_Updating_Due_To_Style_Class() { - using var app = UnitTestApplication.Start(TestServices.RealStyler); var target = CreateTarget(); var theme1 = CreateTheme(); var theme2 = new ControlTheme(typeof(ThemedControl)); diff --git a/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs b/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs index b16e891924..59953f457a 100644 --- a/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs +++ b/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs @@ -22,7 +22,6 @@ namespace Avalonia.Benchmarks.Styling platform: new AppBuilder().RuntimePlatform, renderInterface: new MockPlatformRenderInterface(), standardCursorFactory: Mock.Of(), - styler: new Styler(), theme: () => CreateTheme(), threadingInterface: new NullThreadingPlatform(), fontManagerImpl: new MockFontManagerImpl(), diff --git a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs index ae874b8a61..1115bc9760 100644 --- a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs +++ b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs @@ -46,7 +46,6 @@ namespace Avalonia.Benchmarks.Themes platform: new AppBuilder().RuntimePlatform, renderInterface: new MockPlatformRenderInterface(), standardCursorFactory: Mock.Of(), - styler: new Styler(), theme: () => LoadFluentTheme(), threadingInterface: new NullThreadingPlatform(), fontManagerImpl: new MockFontManagerImpl(), diff --git a/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs b/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs index 7cc0bae97f..1e37093736 100644 --- a/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs @@ -37,11 +37,19 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Templated_Children_Should_Be_Styled() { - var root = new TestRoot(); + var root = new TestRoot + { + Styles = + { + new Style(x => x.Is()) + { + Setters = { new Setter(Control.TagProperty, "foo") } + } + } + }; + var target = new ContentControl(); - var styler = new Mock(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(styler.Object); target.Content = "Foo"; target.Template = GetTemplate(); root.Child = target; @@ -49,10 +57,8 @@ namespace Avalonia.Controls.UnitTests target.ApplyTemplate(); target.Presenter.ApplyTemplate(); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); + foreach (Control child in target.GetTemplateChildren()) + Assert.Equal("foo", child.Tag); } [Fact] @@ -332,40 +338,37 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Set_Child_LogicalParent_After_Removing_And_Adding_Back_To_Logical_Tree() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var target = new ContentControl(); + var root = new TestRoot { - var target = new ContentControl(); - var root = new TestRoot + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter(ContentControl.TemplateProperty, GetTemplate()), - } + new Setter(ContentControl.TemplateProperty, GetTemplate()), } - }, - Child = target - }; + } + }, + Child = target + }; - target.Content = "Foo"; - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); + target.Content = "Foo"; + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); - Assert.Equal(target, target.Presenter.Child.LogicalParent); + Assert.Equal(target, target.Presenter.Child.LogicalParent); - root.Child = null; + root.Child = null; - Assert.Null(target.Template); + Assert.Null(target.Template); - target.Content = null; - root.Child = target; - target.Content = "Bar"; + target.Content = null; + root.Child = target; + target.Content = "Bar"; - Assert.Equal(target, target.Presenter.Child.LogicalParent); - } + Assert.Equal(target, target.Presenter.Child.LogicalParent); } private FuncControlTemplate GetTemplate() diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index f6d96edb99..7b7f0fcc98 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -99,7 +99,7 @@ namespace Avalonia.Controls.UnitTests using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) { var items = new[] { "Foo", "Bar", "Baz " }; - var theme = new ControlTheme(); + var theme = new ControlTheme(typeof(ListBoxItem)); var target = new ListBox { Template = ListBoxTemplate(), @@ -121,7 +121,7 @@ namespace Avalonia.Controls.UnitTests using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) { var items = new[] { "Foo", "Bar", "Baz " }; - var theme = new ControlTheme(); + var theme = new ControlTheme(typeof(ListBoxItem)); var target = new ListBox { Template = ListBoxTemplate(), diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index 330cbfd7b9..100e813326 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -998,6 +998,7 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Order_Of_Setting_Items_And_SelectedIndex_During_Initialization_Should_Not_Matter() { + using var app = Start(); var items = new[] { "Foo", "Bar" }; var target = new SelectingItemsControl(); @@ -1015,6 +1016,7 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Order_Of_Setting_Items_And_SelectedItem_During_Initialization_Should_Not_Matter() { + using var app = Start(); var items = new[] { "Foo", "Bar" }; var target = new SelectingItemsControl(); @@ -1847,6 +1849,7 @@ namespace Avalonia.Controls.UnitTests.Primitives public void Preserves_SelectedItem_When_Items_Changed() { // Issue #4048 + using var app = Start(); var target = new SelectingItemsControl { Items = new[] { "foo", "bar", "baz"}, @@ -1867,6 +1870,7 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Setting_SelectedItems_Raises_PropertyChanged() { + using var app = Start(); var target = new TestSelector { Items = new[] { "foo", "bar", "baz" }, @@ -1895,6 +1899,7 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Setting_Selection_Raises_SelectedItems_PropertyChanged() { + using var app = Start(); var target = new TestSelector { Items = new[] { "foo", "bar", "baz" }, @@ -2050,6 +2055,13 @@ namespace Avalonia.Controls.UnitTests.Primitives } } + private static IDisposable Start() + { + return UnitTestApplication.Start(new TestServices( + fontManagerImpl: new MockFontManagerImpl(), + textShaperImpl: new MockTextShaperImpl())); + } + private static void Prepare(SelectingItemsControl target) { var root = new TestRoot diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs index 58d2eedb1f..a7609a6704 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs @@ -170,36 +170,41 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Templated_Children_Should_Be_Styled() { - using (UnitTestApplication.Start(TestServices.MockStyler)) - { - TestTemplatedControl target; + TestTemplatedControl target; - var root = new TestRoot + var root = new TestRoot + { + Styles = { - Child = target = new TestTemplatedControl + new Style(x => x.Is()) { - Template = new FuncControlTemplate((_, __) => + Setters = { - return new StackPanel - { - Children = + new Setter(Control.TagProperty, "foo") + } + } + }, + Child = target = new TestTemplatedControl + { + Template = new FuncControlTemplate((_, __) => + { + return new StackPanel + { + Children = { new TextBlock { } } - }; - }), - } - }; + }; + }), + } + }; - target.ApplyTemplate(); + target.ApplyTemplate(); - var styler = Mock.Get(UnitTestApplication.Current.Services.Styler); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); - styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); - } + foreach (Control child in target.GetTemplateChildren()) + Assert.Equal("foo", child.Tag); } [Fact] @@ -351,166 +356,154 @@ namespace Avalonia.Controls.UnitTests.Primitives [Fact] public void Removing_From_LogicalTree_Should_Not_Remove_Child() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + Border templateChild = new Border(); + TestTemplatedControl target; + var root = new TestRoot { - Border templateChild = new Border(); - TestTemplatedControl target; - var root = new TestRoot + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter( - TemplatedControl.TemplateProperty, - new FuncControlTemplate((_, __) => new Decorator - { - Child = new Border(), - })) - } + new Setter( + TemplatedControl.TemplateProperty, + new FuncControlTemplate((_, __) => new Decorator + { + Child = new Border(), + })) } - }, - Child = target = new TestTemplatedControl() - }; + } + }, + Child = target = new TestTemplatedControl() + }; - Assert.NotNull(target.Template); - target.ApplyTemplate(); + Assert.NotNull(target.Template); + target.ApplyTemplate(); - root.Child = null; + root.Child = null; - Assert.Null(target.Template); - Assert.IsType(target.GetVisualChildren().Single()); - } + Assert.Null(target.Template); + Assert.IsType(target.GetVisualChildren().Single()); } [Fact] public void Re_adding_To_Same_LogicalTree_Should_Not_Recreate_Template() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + TestTemplatedControl target; + var root = new TestRoot { - TestTemplatedControl target; - var root = new TestRoot + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter( - TemplatedControl.TemplateProperty, - new FuncControlTemplate((_, __) => new Decorator - { - Child = new Border(), - })) - } + new Setter( + TemplatedControl.TemplateProperty, + new FuncControlTemplate((_, __) => new Decorator + { + Child = new Border(), + })) } - }, - Child = target = new TestTemplatedControl() - }; + } + }, + Child = target = new TestTemplatedControl() + }; - Assert.NotNull(target.Template); - target.ApplyTemplate(); - var expected = (Decorator)target.GetVisualChildren().Single(); + Assert.NotNull(target.Template); + target.ApplyTemplate(); + var expected = (Decorator)target.GetVisualChildren().Single(); - root.Child = null; - root.Child = target; - target.ApplyTemplate(); + root.Child = null; + root.Child = target; + target.ApplyTemplate(); - Assert.Same(expected, target.GetVisualChildren().Single()); - } + Assert.Same(expected, target.GetVisualChildren().Single()); } [Fact] public void Re_adding_To_Different_LogicalTree_Should_Recreate_Template() { - using (UnitTestApplication.Start(TestServices.RealStyler)) - { - TestTemplatedControl target; + TestTemplatedControl target; - var root = new TestRoot + var root = new TestRoot + { + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter( - TemplatedControl.TemplateProperty, - new FuncControlTemplate((_, __) => new Decorator - { - Child = new Border(), - })) - } + new Setter( + TemplatedControl.TemplateProperty, + new FuncControlTemplate((_, __) => new Decorator + { + Child = new Border(), + })) } - }, - Child = target = new TestTemplatedControl() - }; + } + }, + Child = target = new TestTemplatedControl() + }; - var root2 = new TestRoot + var root2 = new TestRoot + { + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter( - TemplatedControl.TemplateProperty, - new FuncControlTemplate((_, __) => new Decorator - { - Child = new Border(), - })) - } + new Setter( + TemplatedControl.TemplateProperty, + new FuncControlTemplate((_, __) => new Decorator + { + Child = new Border(), + })) } - }, - }; + } + }, + }; - Assert.NotNull(target.Template); - target.ApplyTemplate(); + Assert.NotNull(target.Template); + target.ApplyTemplate(); - var expected = (Decorator)target.GetVisualChildren().Single(); + var expected = (Decorator)target.GetVisualChildren().Single(); - root.Child = null; - root2.Child = target; - target.ApplyTemplate(); + root.Child = null; + root2.Child = target; + target.ApplyTemplate(); - var child = target.GetVisualChildren().Single(); - Assert.NotNull(target.Template); - Assert.NotNull(child); - Assert.NotSame(expected, child); - } + var child = target.GetVisualChildren().Single(); + Assert.NotNull(target.Template); + Assert.NotNull(child); + Assert.NotSame(expected, child); } [Fact] public void Moving_To_New_LogicalTree_Should_Detach_Attach_Template_Child() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + TestTemplatedControl target; + var root = new TestRoot { - TestTemplatedControl target; - var root = new TestRoot + Child = target = new TestTemplatedControl { - Child = target = new TestTemplatedControl - { - Template = new FuncControlTemplate((_, __) => new Decorator()), - } - }; + Template = new FuncControlTemplate((_, __) => new Decorator()), + } + }; - Assert.NotNull(target.Template); - target.ApplyTemplate(); + Assert.NotNull(target.Template); + target.ApplyTemplate(); - var templateChild = (ILogical)target.GetVisualChildren().Single(); - Assert.True(templateChild.IsAttachedToLogicalTree); + var templateChild = (ILogical)target.GetVisualChildren().Single(); + Assert.True(templateChild.IsAttachedToLogicalTree); - root.Child = null; - Assert.False(templateChild.IsAttachedToLogicalTree); + root.Child = null; + Assert.False(templateChild.IsAttachedToLogicalTree); - var newRoot = new TestRoot { Child = target }; - Assert.True(templateChild.IsAttachedToLogicalTree); - } + var newRoot = new TestRoot { Child = target }; + Assert.True(templateChild.IsAttachedToLogicalTree); } [Fact] diff --git a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs index c54d7efe61..d8a897d600 100644 --- a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs @@ -227,28 +227,24 @@ namespace Avalonia.Controls.UnitTests }; var template = new FuncControlTemplate((x, __) => new Decorator()); - - using (UnitTestApplication.Start(TestServices.RealStyler)) + var root = new TestRoot { - var root = new TestRoot + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter(TemplatedControl.TemplateProperty, template) - } + new Setter(TemplatedControl.TemplateProperty, template) } - }, - Child = new TabControl - { - Template = TabControlTemplate(), - Items = collection, } - }; - } + }, + Child = new TabControl + { + Template = TabControlTemplate(), + Items = collection, + } + }; Assert.Same(collection[0].Template, template); Assert.Same(collection[1].Template, template); diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index 9cf21423a3..9ae6fd98b5 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -77,7 +77,7 @@ namespace Avalonia.Controls.UnitTests public void Items_Should_Be_Created_Using_ItemConatinerTheme_If_Present() { TreeView target; - var theme = new ControlTheme(); + var theme = new ControlTheme(typeof(TreeViewItem)); var root = new TestRoot { diff --git a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs index 3d1980b0eb..6342d9d21f 100644 --- a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs @@ -13,26 +13,23 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Be_Styled_As_UserControl() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var target = new UserControl(); + var root = new TestRoot { - var target = new UserControl(); - var root = new TestRoot + Styles = { - Styles = + new Style(x => x.OfType()) { - new Style(x => x.OfType()) + Setters = { - Setters = - { - new Setter(TemplatedControl.TemplateProperty, GetTemplate()) - } + new Setter(TemplatedControl.TemplateProperty, GetTemplate()) } - }, - Child = target, - }; + } + }, + Child = target, + }; - Assert.NotNull(target.Template); - } + Assert.NotNull(target.Template); } private FuncControlTemplate GetTemplate() diff --git a/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs b/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs index e4d177f7ca..3202924a9d 100644 --- a/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs @@ -23,11 +23,8 @@ namespace Avalonia.Controls.UnitTests.Utils { using (AvaloniaLocator.EnterScope()) { - var styler = new Mock(); - AvaloniaLocator.CurrentMutable - .Bind().ToConstant(new WindowingPlatformMock()) - .Bind().ToConstant(styler.Object); + .Bind().ToConstant(new WindowingPlatformMock()); var gesture1 = new KeyGesture(Key.A, KeyModifiers.Control); var gesture2 = new KeyGesture(Key.B, KeyModifiers.Control); @@ -67,13 +64,11 @@ namespace Avalonia.Controls.UnitTests.Utils { using (AvaloniaLocator.EnterScope()) { - var styler = new Mock(); var target = new KeyboardDevice(); var commandResult = 0; var expectedParameter = 1; AvaloniaLocator.CurrentMutable - .Bind().ToConstant(new WindowingPlatformMock()) - .Bind().ToConstant(styler.Object); + .Bind().ToConstant(new WindowingPlatformMock()); var gesture = new KeyGesture(Key.A, KeyModifiers.Control); @@ -112,12 +107,10 @@ namespace Avalonia.Controls.UnitTests.Utils { using (AvaloniaLocator.EnterScope()) { - var styler = new Mock(); var target = new KeyboardDevice(); var isExecuted = false; AvaloniaLocator.CurrentMutable - .Bind().ToConstant(new WindowingPlatformMock()) - .Bind().ToConstant(styler.Object); + .Bind().ToConstant(new WindowingPlatformMock()); var gesture = new KeyGesture(Key.A, KeyModifiers.Control); @@ -154,12 +147,10 @@ namespace Avalonia.Controls.UnitTests.Utils { using (AvaloniaLocator.EnterScope()) { - var styler = new Mock(); var target = new KeyboardDevice(); var clickExecutedCount = 0; AvaloniaLocator.CurrentMutable - .Bind().ToConstant(new WindowingPlatformMock()) - .Bind().ToConstant(styler.Object); + .Bind().ToConstant(new WindowingPlatformMock()); var gesture = new KeyGesture(Key.A, KeyModifiers.Control); @@ -208,13 +199,11 @@ namespace Avalonia.Controls.UnitTests.Utils { using (AvaloniaLocator.EnterScope()) { - var styler = new Mock(); var target = new KeyboardDevice(); var clickExecutedCount = 0; var commandExecutedCount = 0; AvaloniaLocator.CurrentMutable - .Bind().ToConstant(new WindowingPlatformMock()) - .Bind().ToConstant(styler.Object); + .Bind().ToConstant(new WindowingPlatformMock()); var gesture = new KeyGesture(Key.A, KeyModifiers.Control); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 2d7dcf4b45..88d2cc2912 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using System.Globalization; using System.Linq; using System.Reactive.Subjects; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Presenters; @@ -26,6 +27,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions { public class CompiledBindingExtensionTests { + static CompiledBindingExtensionTests() + { + RuntimeHelpers.RunClassConstructor(typeof(RelativeSource).TypeHandle); + } + [Fact] public void ResolvesClrPropertyBasedOnDataContextType() { diff --git a/tests/Avalonia.UnitTests/TestServices.cs b/tests/Avalonia.UnitTests/TestServices.cs index 49da2794c1..c421adaf21 100644 --- a/tests/Avalonia.UnitTests/TestServices.cs +++ b/tests/Avalonia.UnitTests/TestServices.cs @@ -23,7 +23,6 @@ namespace Avalonia.UnitTests platform: new AppBuilder().RuntimePlatform, renderInterface: new MockPlatformRenderInterface(), standardCursorFactory: Mock.Of(), - styler: new Styler(), theme: () => CreateSimpleTheme(), threadingInterface: Mock.Of(x => x.CurrentThreadIsLoopThread == true), fontManagerImpl: new MockFontManagerImpl(), @@ -39,9 +38,6 @@ namespace Avalonia.UnitTests public static readonly TestServices MockPlatformWrapper = new TestServices( platform: Mock.Of()); - public static readonly TestServices MockStyler = new TestServices( - styler: Mock.Of()); - public static readonly TestServices MockThreadingInterface = new TestServices( threadingInterface: Mock.Of(x => x.CurrentThreadIsLoopThread == true)); @@ -58,9 +54,6 @@ namespace Avalonia.UnitTests fontManagerImpl: new MockFontManagerImpl(), textShaperImpl: new MockTextShaperImpl()); - public static readonly TestServices RealStyler = new TestServices( - styler: new Styler()); - public static readonly TestServices TextServices = new TestServices( assetLoader: new AssetLoader(), renderInterface: new MockPlatformRenderInterface(), @@ -80,7 +73,6 @@ namespace Avalonia.UnitTests IRenderTimer renderLoop = null, IScheduler scheduler = null, ICursorFactory standardCursorFactory = null, - IStyler styler = null, Func theme = null, IPlatformThreadingInterface threadingInterface = null, IFontManagerImpl fontManagerImpl = null, @@ -101,7 +93,6 @@ namespace Avalonia.UnitTests TextShaperImpl = textShaperImpl; Scheduler = scheduler; StandardCursorFactory = standardCursorFactory; - Styler = styler; Theme = theme; ThreadingInterface = threadingInterface; WindowImpl = windowImpl; @@ -121,7 +112,6 @@ namespace Avalonia.UnitTests public ITextShaperImpl TextShaperImpl { get; } public IScheduler Scheduler { get; } public ICursorFactory StandardCursorFactory { get; } - public IStyler Styler { get; } public Func Theme { get; } public IPlatformThreadingInterface ThreadingInterface { get; } public IWindowImpl WindowImpl { get; } @@ -140,8 +130,7 @@ namespace Avalonia.UnitTests IRenderTimer renderLoop = null, IScheduler scheduler = null, ICursorFactory standardCursorFactory = null, - IStyler styler = null, - Func theme = null, + Func theme = null, IPlatformThreadingInterface threadingInterface = null, IFontManagerImpl fontManagerImpl = null, ITextShaperImpl textShaperImpl = null, @@ -162,7 +151,6 @@ namespace Avalonia.UnitTests textShaperImpl: textShaperImpl ?? TextShaperImpl, scheduler: scheduler ?? Scheduler, standardCursorFactory: standardCursorFactory ?? StandardCursorFactory, - styler: styler ?? Styler, theme: theme ?? Theme, threadingInterface: threadingInterface ?? ThreadingInterface, windowingPlatform: windowingPlatform ?? WindowingPlatform, diff --git a/tests/Avalonia.UnitTests/UnitTestApplication.cs b/tests/Avalonia.UnitTests/UnitTestApplication.cs index 260771c9ab..03e19359c3 100644 --- a/tests/Avalonia.UnitTests/UnitTestApplication.cs +++ b/tests/Avalonia.UnitTests/UnitTestApplication.cs @@ -68,14 +68,13 @@ namespace Avalonia.UnitTests .Bind().ToConstant(Services.ThreadingInterface) .Bind().ToConstant(Services.Scheduler) .Bind().ToConstant(Services.StandardCursorFactory) - .Bind().ToConstant(Services.Styler) .Bind().ToConstant(Services.WindowingPlatform) .Bind().ToSingleton(); var theme = Services.Theme?.Invoke(); - if (theme is Styles styles) + if (theme is Style styles) { - Styles.AddRange(styles); + Styles.AddRange(styles.Children); } else if (theme is not null) { From 086c2c7e707df65c0ade4192b01b13a623bcee82 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 10 Nov 2022 11:25:44 +0100 Subject: [PATCH 041/137] Don't apply styling in TopLevel ctor. Applying styling in the constructor isn't a good idea as demonstrated by #8549.. Instead apply styling when showing a window, or if it's needed call `ApplyStyling` manually, e.g. in unit tests. Fixes #8549 --- src/Avalonia.Base/PropertyStore/ValueStore.cs | 3 +-- src/Avalonia.Controls/TopLevel.cs | 2 -- src/Avalonia.Controls/Window.cs | 2 ++ src/Avalonia.Controls/WindowBase.cs | 1 + .../AutoCompleteBoxTests.cs | 1 + tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs | 10 +++++++++- tests/Avalonia.Controls.UnitTests/MenuItemTests.cs | 3 +++ .../Avalonia.Controls.UnitTests/NumericUpDownTests.cs | 1 + .../Primitives/PopupRootTests.cs | 2 ++ .../Primitives/PopupTests.cs | 2 ++ tests/Avalonia.Controls.UnitTests/ToolTipTests.cs | 8 ++++++++ .../Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs | 7 ++++++- 12 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs index 8790991182..d858e30212 100644 --- a/src/Avalonia.Base/PropertyStore/ValueStore.cs +++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs @@ -610,8 +610,7 @@ namespace Avalonia.PropertyStore private int InsertFrame(ValueFrame frame) { - // Uncomment this line when #8549 is fixed. - //Debug.Assert(!_frames.Contains(frame)); + Debug.Assert(!_frames.Contains(frame)); var index = BinarySearchFrame(frame.Priority); _frames.Insert(index, frame); diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 515535bf39..90af881adc 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -182,8 +182,6 @@ namespace Avalonia.Controls _globalStyles.GlobalStylesRemoved += ((IStyleHost)this).StylesRemoved; } - ApplyStyling(); - ClientSize = impl.ClientSize; FrameSize = impl.FrameSize; diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 1a7dca737e..559d674c02 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -647,6 +647,7 @@ namespace Avalonia.Controls RaiseEvent(new RoutedEventArgs(WindowOpenedEvent)); EnsureInitialized(); + ApplyStyling(); IsVisible = true; var initialSize = new Size( @@ -726,6 +727,7 @@ namespace Avalonia.Controls RaiseEvent(new RoutedEventArgs(WindowOpenedEvent)); EnsureInitialized(); + ApplyStyling(); IsVisible = true; var initialSize = new Size( diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 89483cd566..8f1b2198ad 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -149,6 +149,7 @@ namespace Avalonia.Controls try { EnsureInitialized(); + ApplyStyling(); IsVisible = true; if (!_hasExecutedInitialLayoutPass) diff --git a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs index c8bd289e54..9d71e3bffc 100644 --- a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs @@ -1056,6 +1056,7 @@ namespace Avalonia.Controls.UnitTests control.Items = CreateSimpleStringArray(); TextBox textBox = GetTextBox(control); var window = new Window {Content = control}; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); Dispatcher.UIThread.RunJobs(); diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs index b63cbd286e..a798801f20 100644 --- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs @@ -29,6 +29,7 @@ namespace Avalonia.Controls.UnitTests }; var window = new Window { Content = target }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -61,6 +62,7 @@ namespace Avalonia.Controls.UnitTests }; var window = new Window { Content = target }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -130,6 +132,7 @@ namespace Avalonia.Controls.UnitTests }; var window = new Window { Content = target }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -158,6 +161,7 @@ namespace Avalonia.Controls.UnitTests }; var window = new Window { Content = target }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -186,6 +190,7 @@ namespace Avalonia.Controls.UnitTests }; var window = new Window { Content = target }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -207,6 +212,7 @@ namespace Avalonia.Controls.UnitTests }; var window = new Window { Content = target }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -390,7 +396,8 @@ namespace Avalonia.Controls.UnitTests var sp = new StackPanel { Children = { target1, target2 } }; var window = new Window { Content = sp }; - + + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -594,6 +601,7 @@ namespace Avalonia.Controls.UnitTests windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); var w = new Window(windowImpl.Object) { Content = content }; + w.ApplyStyling(); w.ApplyTemplate(); w.Presenter.ApplyTemplate(); return w; diff --git a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs index d25a790fde..c19a01facb 100644 --- a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs +++ b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs @@ -193,6 +193,7 @@ namespace Avalonia.Controls.UnitTests var target = new MenuItem(); var contextMenu = new ContextMenu { Items = new AvaloniaList { target } }; var window = new Window { Content = new Panel { ContextMenu = contextMenu } }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -232,6 +233,7 @@ namespace Avalonia.Controls.UnitTests var flyout = new MenuFlyout { Items = new AvaloniaList { target } }; var button = new Button { Flyout = flyout }; var window = new Window { Content = button }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -271,6 +273,7 @@ namespace Avalonia.Controls.UnitTests var parentMenuItem = new MenuItem { Items = new AvaloniaList { target } }; var contextMenu = new ContextMenu { Items = new AvaloniaList { parentMenuItem } }; var window = new Window { Content = new Panel { ContextMenu = contextMenu } }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); contextMenu.Open(); diff --git a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs index 4cef7e4d05..d50faf8be9 100644 --- a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs +++ b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs @@ -50,6 +50,7 @@ namespace Avalonia.Controls.UnitTests var control = CreateControl(); TextBox textBox = GetTextBox(control); var window = new Window { Content = control }; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); Dispatcher.UIThread.RunJobs(); diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs index 6d3351d2b2..f283681088 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs @@ -51,6 +51,7 @@ namespace Avalonia.Controls.UnitTests.Primitives }; window.Content = target; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); target.ApplyTemplate(); @@ -177,6 +178,7 @@ namespace Avalonia.Controls.UnitTests.Primitives }; window.Content = target; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); target.ApplyTemplate(); diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 5f91f2e2a1..7e695612df 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -569,6 +569,7 @@ namespace Avalonia.Controls.UnitTests.Primitives windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); var window = new Window(windowImpl.Object); + window.ApplyStyling(); window.ApplyTemplate(); var target = new Popup() @@ -1090,6 +1091,7 @@ namespace Avalonia.Controls.UnitTests.Primitives private Window PreparedWindow(object content = null) { var w = new Window { Content = content }; + w.ApplyStyling(); w.ApplyTemplate(); return w; } diff --git a/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs b/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs index 25969a58e3..25f38f8665 100644 --- a/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs @@ -51,6 +51,7 @@ namespace Avalonia.Controls.UnitTests window.Content = panel; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -114,6 +115,7 @@ namespace Avalonia.Controls.UnitTests window.Content = target; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -140,6 +142,7 @@ namespace Avalonia.Controls.UnitTests window.Content = target; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -183,6 +186,7 @@ namespace Avalonia.Controls.UnitTests window.Content = target; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -215,6 +219,7 @@ namespace Avalonia.Controls.UnitTests window.Content = decorator; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -237,6 +242,7 @@ namespace Avalonia.Controls.UnitTests window.Content = decorator; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -261,6 +267,7 @@ namespace Avalonia.Controls.UnitTests window.Content = decorator; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); @@ -286,6 +293,7 @@ namespace Avalonia.Controls.UnitTests window.Content = target; + window.ApplyStyling(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs index 2a2e5f2478..af133cca73 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs @@ -720,7 +720,12 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml //ensure binding is set and operational first Assert.Equal(100.0, tracker.Tag); - Assert.Equal("EndInit 0", tracker.Order.Last()); + // EndInit should be second-to-last operation, as last operation will be + // caused by styling being applied on EndInit. + Assert.Equal("EndInit 0", tracker.Order[tracker.Order.Count - 2]); + + // Caused by styling. + Assert.Equal("Property Foreground Changed", tracker.Order[tracker.Order.Count - 1]); } } From 05d3786116b27049a39098bd1338b48f36ef6548 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 21 Nov 2022 13:05:57 +0100 Subject: [PATCH 042/137] *Web* projects were renamed to *Browser*. --- ...3.ncrunchproject => Avalonia.Browser.Blazor.v3.ncrunchproject} | 0 ...a.Web.v3.ncrunchproject => Avalonia.Browser.v3.ncrunchproject} | 0 ...nchproject => ControlCatalog.Browser.Blazor.v3.ncrunchproject} | 0 ...v3.ncrunchproject => ControlCatalog.Browser.v3.ncrunchproject} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename .ncrunch/{Avalonia.Web.Blazor.v3.ncrunchproject => Avalonia.Browser.Blazor.v3.ncrunchproject} (100%) rename .ncrunch/{Avalonia.Web.v3.ncrunchproject => Avalonia.Browser.v3.ncrunchproject} (100%) rename .ncrunch/{ControlCatalog.Blazor.Web.v3.ncrunchproject => ControlCatalog.Browser.Blazor.v3.ncrunchproject} (100%) rename .ncrunch/{ControlCatalog.Web.v3.ncrunchproject => ControlCatalog.Browser.v3.ncrunchproject} (100%) diff --git a/.ncrunch/Avalonia.Web.Blazor.v3.ncrunchproject b/.ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.Web.Blazor.v3.ncrunchproject rename to .ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Web.v3.ncrunchproject b/.ncrunch/Avalonia.Browser.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.Web.v3.ncrunchproject rename to .ncrunch/Avalonia.Browser.v3.ncrunchproject diff --git a/.ncrunch/ControlCatalog.Blazor.Web.v3.ncrunchproject b/.ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject similarity index 100% rename from .ncrunch/ControlCatalog.Blazor.Web.v3.ncrunchproject rename to .ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject diff --git a/.ncrunch/ControlCatalog.Web.v3.ncrunchproject b/.ncrunch/ControlCatalog.Browser.v3.ncrunchproject similarity index 100% rename from .ncrunch/ControlCatalog.Web.v3.ncrunchproject rename to .ncrunch/ControlCatalog.Browser.v3.ncrunchproject From 2c085b6e12a70a1dc9ee35e7e3dd3cf5289ed792 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 21 Nov 2022 13:08:33 +0100 Subject: [PATCH 043/137] Don't instrument theme projects. Was failing with an `IndexOutOfRangeException` inside ncrunch. It's not important to have code coverage for these projects anyway. --- .ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject | 5 +++++ .../Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject | 5 +++++ .../Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject | 5 +++++ 4 files changed, 20 insertions(+) create mode 100644 .ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject new file mode 100644 index 0000000000..02eb0d211e --- /dev/null +++ b/.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject new file mode 100644 index 0000000000..02eb0d211e --- /dev/null +++ b/.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject new file mode 100644 index 0000000000..02eb0d211e --- /dev/null +++ b/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject new file mode 100644 index 0000000000..02eb0d211e --- /dev/null +++ b/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file From ca7b99ef48be17bd88266eaffd7de93191d52282 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 21 Nov 2022 13:41:01 +0100 Subject: [PATCH 044/137] Ignore a few more projects. That aren't needed for tests to run. --- .ncrunch/Avalonia.Benchmarks.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject | 5 +++++ .ncrunch/MobileSandbox.v3.ncrunchproject | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 .ncrunch/Avalonia.Benchmarks.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject create mode 100644 .ncrunch/MobileSandbox.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject b/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject b/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.v3.ncrunchproject b/.ncrunch/MobileSandbox.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/MobileSandbox.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file From 273124603f184b8de42a22067b7dfc560f7d9792 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 21 Nov 2022 15:03:33 +0100 Subject: [PATCH 045/137] Added benchmark for changing control theme. --- .../Styling/ControlTheme_Change.cs | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 tests/Avalonia.Benchmarks/Styling/ControlTheme_Change.cs diff --git a/tests/Avalonia.Benchmarks/Styling/ControlTheme_Change.cs b/tests/Avalonia.Benchmarks/Styling/ControlTheme_Change.cs new file mode 100644 index 0000000000..627edfdeb6 --- /dev/null +++ b/tests/Avalonia.Benchmarks/Styling/ControlTheme_Change.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Styling; +using Avalonia.UnitTests; +using BenchmarkDotNet.Attributes; + +namespace Avalonia.Benchmarks.Styling +{ + [MemoryDiagnoser] + public class ControlTheme_Change : IDisposable + { + private readonly IDisposable _app; + private readonly TestRoot _root; + private readonly TextBox _control; + private readonly ControlTheme _theme1; + private readonly ControlTheme _theme2; + + public ControlTheme_Change() + { + _app = UnitTestApplication.Start( + TestServices.StyledWindow.With( + renderInterface: new NullRenderingPlatform(), + threadingInterface: new NullThreadingPlatform())); + + // Simulate an application with a lot of styles by creating a tree of nested panels, + // each with a bunch of styles applied. + var (rootPanel, leafPanel) = CreateNestedPanels(10); + + // We're benchmarking how long it takes to switch control theme on a TextBox in this + // situation. + var baseTheme = (ControlTheme)Application.Current.FindResource(typeof(TextBox)) ?? + throw new Exception("Base TextBox theme not found."); + + _theme1 = new ControlTheme(typeof(TextBox)) + { + BasedOn = baseTheme, + Setters = { new Setter(TextBox.BackgroundProperty, Brushes.Red) }, + }; + + _theme2 = new ControlTheme(typeof(TextBox)) + { + BasedOn = baseTheme, + Setters = { new Setter(TextBox.BackgroundProperty, Brushes.Green) }, + }; + + _control = new TextBox { Theme = _theme1 }; + leafPanel.Children.Add(_control); + + _root = new TestRoot(true, rootPanel) + { + Renderer = new NullRenderer(), + }; + + _root.LayoutManager.ExecuteInitialLayoutPass(); + } + + [Benchmark] + [MethodImpl(MethodImplOptions.NoInlining)] + public void Change_ControlTheme() + { + if (_control.Background != Brushes.Red) + throw new Exception("Invalid benchmark state"); + + _control.Theme = _theme2; + _root.LayoutManager.ExecuteLayoutPass(); + + if (_control.Background != Brushes.Green) + throw new Exception("Invalid benchmark state"); + + _control.Theme = _theme1; + _root.LayoutManager.ExecuteLayoutPass(); + + if (_control.Background != Brushes.Red) + throw new Exception("Invalid benchmark state"); + } + + public void Dispose() + { + _app.Dispose(); + } + + private static (Panel, Panel) CreateNestedPanels(int count) + { + var root = new Panel(); + var last = root; + + for (var i = 0; i < count; ++i) + { + var panel = new Panel(); + panel.Styles.AddRange(CreateStyles()); + last.Children.Add(panel); + last = panel; + } + + return (root, last); + } + + private static IEnumerable CreateStyles() + { + var types = new[] + { + typeof(Border), + typeof(Button), + typeof(ButtonSpinner), + typeof(Carousel), + typeof(CheckBox), + typeof(ComboBox), + typeof(ContentControl), + typeof(Expander), + typeof(ItemsControl), + typeof(Label), + typeof(ListBox), + typeof(ProgressBar), + typeof(RadioButton), + typeof(RepeatButton), + typeof(ScrollViewer), + typeof(Slider), + typeof(Spinner), + typeof(SplitView), + typeof(TextBox), + typeof(ToggleSwitch), + typeof(TreeView), + typeof(Viewbox), + typeof(Window), + }; + + foreach (var type in types) + { + yield return new Style(x => x.OfType(type)) + { + Setters = { new Setter(Control.TagProperty, type.Name) } + }; + + yield return new Style(x => x.OfType(type).Class("foo")) + { + Setters = { new Setter(Control.TagProperty, type.Name + " foo") } + }; + + yield return new Style(x => x.OfType(type).Class("bar")) + { + Setters = { new Setter(Control.TagProperty, type.Name + " bar") } + }; + } + } + } +} From 326dac232899a17d7f6ae8852c81357282af0cfa Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 18 Nov 2022 12:02:32 +0100 Subject: [PATCH 046/137] Refactored how we switch control themes. Instead of simply wiping all control themes and styles that are applied to a control, we can now just remove the `ValueFrame`s which relate to the control theme that was changed. To do this, added `ValueFrame.FramePriority` which encodes both the `BindingPriority` and source of the frame (style, control theme, templated parent control theme). --- src/Avalonia.Base/Layout/Layoutable.cs | 7 + .../PropertyStore/FramePriority.cs | 36 +++ .../PropertyStore/ImmediateValueFrame.cs | 2 +- src/Avalonia.Base/PropertyStore/ValueFrame.cs | 20 +- src/Avalonia.Base/PropertyStore/ValueStore.cs | 33 ++- src/Avalonia.Base/StyledElement.cs | 95 ++++---- src/Avalonia.Base/Styling/ControlTheme.cs | 7 +- src/Avalonia.Base/Styling/Style.cs | 5 +- src/Avalonia.Base/Styling/StyleBase.cs | 6 +- src/Avalonia.Base/Styling/StyleInstance.cs | 13 +- src/Avalonia.Base/Styling/Styles.cs | 3 +- .../Primitives/TemplatedControl.cs | 59 ++--- .../Animation/AnimatableTests.cs | 3 +- .../PropertyStore/ValueStoreTests_Frames.cs | 2 +- .../Styling/SetterTests.cs | 3 +- .../Styling/StyleTests.cs | 17 +- .../Styling/StyledElementTests_Theming.cs | 218 +++++++++++++++++- .../Styling/Style_Activation.cs | 3 +- .../Styling/Style_Apply.cs | 3 +- .../Styling/Style_ClassSelector.cs | 7 +- .../Styling/Style_NonActive.cs | 3 +- .../StyleTests.cs | 3 +- 22 files changed, 410 insertions(+), 138 deletions(-) create mode 100644 src/Avalonia.Base/PropertyStore/FramePriority.cs diff --git a/src/Avalonia.Base/Layout/Layoutable.cs b/src/Avalonia.Base/Layout/Layoutable.cs index 527b63292d..d09d1dc8d2 100644 --- a/src/Avalonia.Base/Layout/Layoutable.cs +++ b/src/Avalonia.Base/Layout/Layoutable.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Logging; +using Avalonia.Styling; using Avalonia.VisualTree; #nullable enable @@ -795,6 +796,12 @@ namespace Avalonia.Layout base.OnVisualParentChanged(oldParent, newParent); } + private protected override void OnControlThemeChanged() + { + base.OnControlThemeChanged(); + InvalidateMeasure(); + } + /// /// Called when the layout manager raises a LayoutUpdated event. /// diff --git a/src/Avalonia.Base/PropertyStore/FramePriority.cs b/src/Avalonia.Base/PropertyStore/FramePriority.cs new file mode 100644 index 0000000000..950a8375f2 --- /dev/null +++ b/src/Avalonia.Base/PropertyStore/FramePriority.cs @@ -0,0 +1,36 @@ +using System.Diagnostics; +using Avalonia.Data; + +namespace Avalonia.PropertyStore +{ + internal enum FramePriority : sbyte + { + Animation, + AnimationTemplatedParentTheme, + AnimationTheme, + StyleTrigger, + StyleTriggerTemplatedParentTheme, + StyleTriggerTheme, + Template, + TemplateTemplatedParentTheme, + TemplateTheme, + Style, + StyleTemplatedParentTheme, + StyleTheme, + } + + internal static class FramePriorityExtensions + { + public static FramePriority ToFramePriority(this BindingPriority priority, FrameType type = FrameType.Style) + { + Debug.Assert(priority != BindingPriority.LocalValue); + var p = (int)(priority > 0 ? priority : priority + 1); + return (FramePriority)(p * 3 + (int)type); + } + + public static bool IsType(this FramePriority priority, FrameType type) + { + return (FrameType)((int)priority % 3) == type; + } + } +} diff --git a/src/Avalonia.Base/PropertyStore/ImmediateValueFrame.cs b/src/Avalonia.Base/PropertyStore/ImmediateValueFrame.cs index 1d886e7501..756ab7aadf 100644 --- a/src/Avalonia.Base/PropertyStore/ImmediateValueFrame.cs +++ b/src/Avalonia.Base/PropertyStore/ImmediateValueFrame.cs @@ -10,8 +10,8 @@ namespace Avalonia.PropertyStore internal class ImmediateValueFrame : ValueFrame { public ImmediateValueFrame(BindingPriority priority) + : base(priority, FrameType.Style) { - Priority = priority; } public TypedBindingEntry AddBinding( diff --git a/src/Avalonia.Base/PropertyStore/ValueFrame.cs b/src/Avalonia.Base/PropertyStore/ValueFrame.cs index 5ada4b3c84..7a9d1bb13a 100644 --- a/src/Avalonia.Base/PropertyStore/ValueFrame.cs +++ b/src/Avalonia.Base/PropertyStore/ValueFrame.cs @@ -1,13 +1,18 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Avalonia.Data; using Avalonia.Utilities; -using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot; namespace Avalonia.PropertyStore { + internal enum FrameType + { + Style, + TemplatedParentTheme, + Theme, + } + internal abstract class ValueFrame { private List? _entries; @@ -15,11 +20,18 @@ namespace Avalonia.PropertyStore private ValueStore? _owner; private bool _isShared; + protected ValueFrame(BindingPriority priority, FrameType type) + { + Priority = priority; + FramePriority = priority.ToFramePriority(type); + } + public int EntryCount => _index.Count; public bool IsActive => GetIsActive(out _); public ValueStore? Owner => !_isShared ? _owner : throw new AvaloniaInternalException("Cannot get owner for shared ValueFrame"); - public BindingPriority Priority { get; protected set; } + public BindingPriority Priority { get; } + public FramePriority FramePriority { get; } public bool Contains(AvaloniaProperty property) => _index.ContainsKey(property); diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs index d858e30212..e14d018564 100644 --- a/src/Avalonia.Base/PropertyStore/ValueStore.cs +++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs @@ -4,8 +4,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Avalonia.Data; using Avalonia.Diagnostics; -using Avalonia.Logging; using Avalonia.Utilities; +using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot; namespace Avalonia.PropertyStore { @@ -580,6 +580,29 @@ namespace Avalonia.PropertyStore return false; } + public void RemoveFrames(FrameType type) + { + var removed = false; + + for (var i = _frames.Count - 1; i >= 0; --i) + { + var frame = _frames[i]; + + if (frame.FramePriority.IsType(type)) + { + _frames.RemoveAt(i); + frame.Dispose(); + removed = true; + } + } + + if (removed) + { + ++_frameGeneration; + ReevaluateEffectiveValues(); + } + } + public AvaloniaPropertyValue GetDiagnostic(AvaloniaProperty property) { object? value; @@ -612,7 +635,7 @@ namespace Avalonia.PropertyStore { Debug.Assert(!_frames.Contains(frame)); - var index = BinarySearchFrame(frame.Priority); + var index = BinarySearchFrame(frame.FramePriority); _frames.Insert(index, frame); ++_frameGeneration; frame.SetOwner(this); @@ -626,7 +649,7 @@ namespace Avalonia.PropertyStore { Debug.Assert(priority != BindingPriority.LocalValue); - var index = BinarySearchFrame(priority); + var index = BinarySearchFrame(priority.ToFramePriority()); if (index > 0 && _frames[index - 1] is ImmediateValueFrame f && f.Priority == priority && @@ -914,7 +937,7 @@ namespace Avalonia.PropertyStore } } - private int BinarySearchFrame(BindingPriority priority) + private int BinarySearchFrame(FramePriority priority) { var lo = 0; var hi = _frames.Count - 1; @@ -923,7 +946,7 @@ namespace Avalonia.PropertyStore while (lo <= hi) { var i = lo + ((hi - lo) >> 1); - var order = priority - _frames[i].Priority; + var order = priority - _frames[i].FramePriority; if (order <= 0) { diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs index c72f398fd9..33bca9b0ab 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; using System.Linq; using Avalonia.Animation; using Avalonia.Collections; @@ -11,6 +12,7 @@ using Avalonia.Data; using Avalonia.Diagnostics; using Avalonia.Logging; using Avalonia.LogicalTree; +using Avalonia.PropertyStore; using Avalonia.Styling; namespace Avalonia @@ -69,10 +71,10 @@ namespace Avalonia private IAvaloniaList? _logicalChildren; private IResourceDictionary? _resources; private Styles? _styles; - private bool _styled; + private bool _stylesApplied; + private bool _themeApplied; private ITemplatedControl? _templatedParent; private bool _dataContextUpdating; - private bool _hasPromotedTheme; private ControlTheme? _implicitTheme; /// @@ -141,7 +143,7 @@ namespace Avalonia set { - if (_styled) + if (_stylesApplied) { throw new InvalidOperationException("Cannot set Name : styled element already styled."); } @@ -353,31 +355,31 @@ namespace Avalonia /// public bool ApplyStyling() { - if (_initCount == 0 && !_styled) + if (_initCount == 0 && (!_stylesApplied || !_themeApplied)) { - var hasPromotedTheme = _hasPromotedTheme; - GetValueStore().BeginStyling(); try { - ApplyControlTheme(); - ApplyStyles(this); + if (!_themeApplied) + { + ApplyControlTheme(); + _themeApplied = true; + } + + if (!_stylesApplied) + { + ApplyStyles(this); + _stylesApplied = true; + } } finally { - _styled = true; GetValueStore().EndStyling(); } - - if (hasPromotedTheme) - { - _hasPromotedTheme = false; - ClearValue(ThemeProperty); - } } - return _styled; + return _stylesApplied; } /// @@ -615,31 +617,25 @@ namespace Avalonia if (change.Property == ThemeProperty) { - var (oldValue, newValue) = change.GetOldAndNewValue(); - - // Changing the theme detaches all styles, meaning that if the theme property was - // set via a style, it will get cleared! To work around this, if the value was - // applied at less than local value priority then promote the value to local value - // priority until styling is re-applied. - if (change.Priority > BindingPriority.LocalValue) - { - Theme = newValue; - _hasPromotedTheme = true; - } - else if (_hasPromotedTheme && change.Priority == BindingPriority.LocalValue) - { - _hasPromotedTheme = false; - } - - InvalidateStyles(); - - if (oldValue is not null) - DetachControlThemeFromTemplateChildren(oldValue); + OnControlThemeChanged(); + _themeApplied = false; } } - internal virtual void DetachControlThemeFromTemplateChildren(ControlTheme theme) + private protected virtual void OnControlThemeChanged() { + var values = GetValueStore(); + values.BeginStyling(); + try { values.RemoveFrames(FrameType.Theme); } + finally { values.EndStyling(); } + } + + internal virtual void OnTemplatedParentControlThemeChanged() + { + var values = GetValueStore(); + values.BeginStyling(); + try { values.RemoveFrames(FrameType.TemplatedParentTheme); } + finally { values.EndStyling(); } } internal ControlTheme? GetEffectiveTheme() @@ -736,26 +732,28 @@ namespace Avalonia var theme = GetEffectiveTheme(); if (theme is not null) - ApplyControlTheme(theme); + ApplyControlTheme(theme, FrameType.Theme); if (TemplatedParent is StyledElement styleableParent && styleableParent.GetEffectiveTheme() is { } parentTheme) { - ApplyControlTheme(parentTheme); + ApplyControlTheme(parentTheme, FrameType.TemplatedParentTheme); } } - private void ApplyControlTheme(ControlTheme theme) + private void ApplyControlTheme(ControlTheme theme, FrameType type) { + Debug.Assert(type is FrameType.Theme or FrameType.TemplatedParentTheme); + if (theme.BasedOn is ControlTheme basedOn) - ApplyControlTheme(basedOn); + ApplyControlTheme(basedOn, type); - theme.TryAttach(this, null); + theme.TryAttach(this, type); if (theme.HasChildren) { foreach (var child in theme.Children) - ApplyStyle(child, null); + ApplyStyle(child, null, type); } } @@ -768,17 +766,17 @@ namespace Avalonia if (host.IsStylesInitialized) { foreach (var style in host.Styles) - ApplyStyle(style, host); + ApplyStyle(style, host, FrameType.Style); } } - private void ApplyStyle(IStyle style, IStyleHost? host) + private void ApplyStyle(IStyle style, IStyleHost? host, FrameType type) { if (style is Style s) - s.TryAttach(this, host); + s.TryAttach(this, host, type); foreach (var child in style.Children) - ApplyStyle(child, host); + ApplyStyle(child, host, type); } private void OnAttachedToLogicalTreeCore(LogicalTreeAttachmentEventArgs e) @@ -895,6 +893,7 @@ namespace Avalonia for (var i = valueStore.Frames.Count - 1; i >= 0; --i) { if (valueStore.Frames[i] is StyleInstance si && + si.Source is not ControlTheme && (styles is null || styles.Contains(si.Source))) { valueStore.RemoveFrame(si); @@ -902,7 +901,7 @@ namespace Avalonia } valueStore.EndStyling(); - _styled = false; + _stylesApplied = false; } private void InvalidateStylesOnThisAndDescendents() diff --git a/src/Avalonia.Base/Styling/ControlTheme.cs b/src/Avalonia.Base/Styling/ControlTheme.cs index 2971703c95..5fc900d2cb 100644 --- a/src/Avalonia.Base/Styling/ControlTheme.cs +++ b/src/Avalonia.Base/Styling/ControlTheme.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using Avalonia.PropertyStore; namespace Avalonia.Styling @@ -36,8 +37,10 @@ namespace Avalonia.Styling throw new InvalidOperationException("ControlThemes cannot be added as a nested style."); } - internal override SelectorMatchResult TryAttach(IStyleable target, object? host) + internal SelectorMatchResult TryAttach(IStyleable target, FrameType type) { + Debug.Assert(type is FrameType.Theme or FrameType.TemplatedParentTheme); + _ = target ?? throw new ArgumentNullException(nameof(target)); if (TargetType is null) @@ -45,7 +48,7 @@ namespace Avalonia.Styling if (HasSettersOrAnimations && TargetType.IsAssignableFrom(target.StyleKey)) { - Attach(target, null); + Attach(target, null, type); return SelectorMatchResult.AlwaysThisType; } diff --git a/src/Avalonia.Base/Styling/Style.cs b/src/Avalonia.Base/Styling/Style.cs index aad91824d3..15d8a9fe2e 100644 --- a/src/Avalonia.Base/Styling/Style.cs +++ b/src/Avalonia.Base/Styling/Style.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.PropertyStore; namespace Avalonia.Styling { @@ -58,7 +59,7 @@ namespace Avalonia.Styling base.SetParent(parent); } - internal override SelectorMatchResult TryAttach(IStyleable target, object? host) + internal SelectorMatchResult TryAttach(IStyleable target, object? host, FrameType type) { _ = target ?? throw new ArgumentNullException(nameof(target)); @@ -73,7 +74,7 @@ namespace Avalonia.Styling if (match.IsMatch) { - Attach(target, match.Activator); + Attach(target, match.Activator, type); } result = match.Result; diff --git a/src/Avalonia.Base/Styling/StyleBase.cs b/src/Avalonia.Base/Styling/StyleBase.cs index dba80df2e5..83fcf04d2f 100644 --- a/src/Avalonia.Base/Styling/StyleBase.cs +++ b/src/Avalonia.Base/Styling/StyleBase.cs @@ -92,9 +92,7 @@ namespace Avalonia.Styling return false; } - internal abstract SelectorMatchResult TryAttach(IStyleable target, object? host); - - internal ValueFrame Attach(IStyleable target, IStyleActivator? activator) + internal ValueFrame Attach(IStyleable target, IStyleActivator? activator, FrameType type) { if (target is not AvaloniaObject ao) throw new InvalidOperationException("Styles can only be applied to AvaloniaObjects."); @@ -109,7 +107,7 @@ namespace Avalonia.Styling { var canShareInstance = activator is null; - instance = new StyleInstance(this, activator); + instance = new StyleInstance(this, activator, type); if (_setters is not null) { diff --git a/src/Avalonia.Base/Styling/StyleInstance.cs b/src/Avalonia.Base/Styling/StyleInstance.cs index 2d7c695b32..4985aa16c7 100644 --- a/src/Avalonia.Base/Styling/StyleInstance.cs +++ b/src/Avalonia.Base/Styling/StyleInstance.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Reactive.Subjects; using Avalonia.Animation; using Avalonia.Data; @@ -27,10 +26,13 @@ namespace Avalonia.Styling private List? _animations; private Subject? _animationTrigger; - public StyleInstance(IStyle style, IStyleActivator? activator) + public StyleInstance( + IStyle style, + IStyleActivator? activator, + FrameType type) + : base(GetPriority(activator), type) { _activator = activator; - Priority = activator is object ? BindingPriority.StyleTrigger : BindingPriority.Style; Source = style; } @@ -99,5 +101,10 @@ namespace Avalonia.Styling hasChanged = _isActive != previous; return _isActive; } + + private static BindingPriority GetPriority(IStyleActivator? activator) + { + return activator is not null ? BindingPriority.StyleTrigger : BindingPriority.Style; + } } } diff --git a/src/Avalonia.Base/Styling/Styles.cs b/src/Avalonia.Base/Styling/Styles.cs index 76271b9748..f22bbc0eae 100644 --- a/src/Avalonia.Base/Styling/Styles.cs +++ b/src/Avalonia.Base/Styling/Styles.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using Avalonia.Collections; using Avalonia.Controls; +using Avalonia.PropertyStore; namespace Avalonia.Styling { @@ -233,7 +234,7 @@ namespace Avalonia.Styling { if (s is not Style style) continue; - var r = style.TryAttach(target, host); + var r = style.TryAttach(target, host, FrameType.Style); if (r > result) result = r; } diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index 80151fbfb3..17d90e6dd0 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -5,6 +5,7 @@ using Avalonia.Interactivity; using Avalonia.Logging; using Avalonia.LogicalTree; using Avalonia.Media; +using Avalonia.PropertyStore; using Avalonia.Styling; using Avalonia.VisualTree; @@ -395,56 +396,36 @@ namespace Avalonia.Controls.Primitives } } - internal override void DetachControlThemeFromTemplateChildren(ControlTheme theme) + private protected override void OnControlThemeChanged() { - static ControlTheme? GetControlTheme(StyleBase style) - { - var s = style; + base.OnControlThemeChanged(); - while (s is not null) + var count = VisualChildren.Count; + for (var i = 0; i < count; ++i) + { + if (VisualChildren[i] is StyledElement child && + child.TemplatedParent == this) { - if (s is ControlTheme c) - return c; - s = s.Parent as StyleBase; + child.OnTemplatedParentControlThemeChanged(); } - - return null; } + } - static void Detach(Visual control, ITemplatedControl templatedParent, ControlTheme theme) - { - var valueStore = control.GetValueStore(); - var count = valueStore.Frames.Count; - - if (control != templatedParent) - { - valueStore.BeginStyling(); - - for (var i = count - 1; i >= 0; --i) - { - if (valueStore.Frames[i] is StyleInstance si && - si.Source is StyleBase style && - GetControlTheme(style) == theme) - { - valueStore.RemoveFrame(si); - } - } - - valueStore.EndStyling(); - } + internal override void OnTemplatedParentControlThemeChanged() + { + base.OnTemplatedParentControlThemeChanged(); - var children = ((IVisual)control).VisualChildren; - count = children.Count; + var count = VisualChildren.Count; + var templatedParent = TemplatedParent; - for (var i = 0; i < count; i++) + for (var i = 0; i < count; ++i) + { + if (VisualChildren[i] is TemplatedControl child && + child.TemplatedParent == templatedParent) { - if (children[i] is Visual v && - v.TemplatedParent == templatedParent) - Detach(v, templatedParent, theme); + child.OnTemplatedParentControlThemeChanged(); } } - - Detach(this, this, theme); } } } diff --git a/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs b/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs index 668b8a875c..dec813b3b0 100644 --- a/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs +++ b/tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs @@ -5,6 +5,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Data; using Avalonia.Layout; using Avalonia.Media; +using Avalonia.PropertyStore; using Avalonia.Styling; using Avalonia.UnitTests; using Moq; @@ -435,7 +436,7 @@ namespace Avalonia.Base.UnitTests.Animation } }; - style.TryAttach(control, control); + style.TryAttach(control, control, FrameType.Style); // Which means that the transition state hasn't been initialized with the new // Transitions when the Opacity change notification gets raised here. diff --git a/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs b/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs index bb726a1d63..3a307447ac 100644 --- a/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs +++ b/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs @@ -117,7 +117,7 @@ namespace Avalonia.Base.UnitTests.PropertyStore private static StyleInstance InstanceStyle(Style style, StyledElement target) { - var result = new StyleInstance(style, null); + var result = new StyleInstance(style, null, FrameType.Style); foreach (var setter in style.Setters) result.Add(setter.Instance(result, target)); diff --git a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs index dc31d3d3ec..18f572dedc 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs @@ -6,6 +6,7 @@ using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Data.Converters; using Avalonia.Media; +using Avalonia.PropertyStore; using Avalonia.Styling; using Avalonia.UnitTests; using Moq; @@ -503,7 +504,7 @@ namespace Avalonia.Base.UnitTests.Styling private void Apply(Style style, Control control) { - style.TryAttach(control, null); + style.TryAttach(control, null, FrameType.Style); } private void Apply(Setter setter, Control control) diff --git a/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs b/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs index e7ecba61a7..a318a8d76a 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs @@ -5,6 +5,7 @@ using Avalonia.Base.UnitTests.Animation; using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Data; +using Avalonia.PropertyStore; using Avalonia.Styling; using Avalonia.UnitTests; using Moq; @@ -27,7 +28,7 @@ namespace Avalonia.Base.UnitTests.Styling var target = new Class1(); - style.TryAttach(target, null); + style.TryAttach(target, null, FrameType.Style); Assert.Equal("Foo", target.Foo); } @@ -45,7 +46,7 @@ namespace Avalonia.Base.UnitTests.Styling var target = new Class1(); - style.TryAttach(target, null); + style.TryAttach(target, null, FrameType.Style); Assert.Equal("foodefault", target.Foo); target.Classes.Add("foo"); Assert.Equal("Foo", target.Foo); @@ -66,7 +67,7 @@ namespace Avalonia.Base.UnitTests.Styling var target = new Class1(); - style.TryAttach(target, target); + style.TryAttach(target, target, FrameType.Style); Assert.Equal("Foo", target.Foo); } @@ -92,7 +93,7 @@ namespace Avalonia.Base.UnitTests.Styling var target = new Class1(); var other = new Class1(); - style.TryAttach(target, other); + style.TryAttach(target, other, FrameType.Style); Assert.Equal("foodefault", target.Foo); } @@ -113,7 +114,7 @@ namespace Avalonia.Base.UnitTests.Styling Foo = "Original", }; - style.TryAttach(target, null); + style.TryAttach(target, null, FrameType.Style); Assert.Equal("Original", target.Foo); } @@ -577,7 +578,7 @@ namespace Avalonia.Base.UnitTests.Styling Child = border = new Border(), }; - style.TryAttach(border, null); + style.TryAttach(border, null, FrameType.Style); Assert.Equal(new Thickness(4), border.BorderThickness); root.Child = null; @@ -761,7 +762,7 @@ namespace Avalonia.Base.UnitTests.Styling var target = new Class1(); - style.TryAttach(target, null); + style.TryAttach(target, null, FrameType.Style); Assert.Equal(1, target.Classes.ListenerCount); @@ -874,7 +875,7 @@ namespace Avalonia.Base.UnitTests.Styling var clock = new TestClock(); var target = new Class1 { Clock = clock }; - style.TryAttach(target, null); + style.TryAttach(target, null, FrameType.Style); Assert.Equal(0.0, target.Double); diff --git a/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs b/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs index a1dac931ce..b5524affb7 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs @@ -23,7 +23,7 @@ public class StyledElementTests_Theming Assert.Null(target.Template); - var root = CreateRoot(target); + CreateRoot(target); Assert.NotNull(target.Template); var border = Assert.IsType(target.VisualChild); @@ -43,7 +43,7 @@ public class StyledElementTests_Theming Assert.Null(target.Template); - var root = CreateRoot(target); + CreateRoot(target); Assert.NotNull(target.Template); var border = Assert.IsType(target.VisualChild); @@ -57,7 +57,7 @@ public class StyledElementTests_Theming public void Theme_Is_Detached_When_Theme_Property_Cleared() { var target = CreateTarget(); - var root = CreateRoot(target); + CreateRoot(target); Assert.NotNull(target.Template); @@ -66,7 +66,47 @@ public class StyledElementTests_Theming } [Fact] - public void Theme_Is_Detached_From_Template_Controls_When_Theme_Property_Cleared() + public void Setting_Explicit_Theme_Detaches_Default_Theme() + { + var target = new ThemedControl(); + var root = new TestRoot + { + Resources = { { typeof(ThemedControl), CreateTheme() } }, + Child = target, + }; + + root.LayoutManager.ExecuteInitialLayoutPass(); + + Assert.Equal("theme", target.Tag); + + target.Theme = new ControlTheme(typeof(ThemedControl)) + { + Setters = + { + new Setter(ThemedControl.BackgroundProperty, Brushes.Yellow), + } + }; + + root.LayoutManager.ExecuteLayoutPass(); + + Assert.Null(target.Tag); + Assert.Equal(Brushes.Yellow, target.Background); + } + + [Fact] + public void Unrelated_Styles_Are_Not_Detached_When_Theme_Property_Cleared() + { + var target = CreateTarget(); + CreateRoot(target, createAdditionalStyles: true); + + Assert.Equal("style", target.Tag); + + target.Theme = null; + Assert.Equal("style", target.Tag); + } + + [Fact] + public void TemplatedParent_Theme_Is_Detached_From_Template_Controls_When_Theme_Property_Cleared() { var theme = new ControlTheme { @@ -93,10 +133,115 @@ public class StyledElementTests_Theming target.Theme = null; - Assert.IsType(target.VisualChild); + Assert.Same(canvas, target.VisualChild); Assert.Null(canvas.Background); } + [Fact] + public void Primary_Theme_Is_Not_Detached_From_Template_Controls_When_Theme_Property_Cleared() + { + var templatedParentTheme = new ControlTheme + { + TargetType = typeof(ThemedControl), + Children = + { + new Style(x => x.Nesting().Template().OfType - internal class ImmediateValueFrame : ValueFrame + internal sealed class ImmediateValueFrame : ValueFrame { public ImmediateValueFrame(BindingPriority priority) : base(priority, FrameType.Style) diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs index e14d018564..92e5288255 100644 --- a/src/Avalonia.Base/PropertyStore/ValueStore.cs +++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Avalonia.Data; using Avalonia.Diagnostics; +using Avalonia.Styling; using Avalonia.Utilities; using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot; @@ -588,7 +590,31 @@ namespace Avalonia.PropertyStore { var frame = _frames[i]; - if (frame.FramePriority.IsType(type)) + if (frame is not ImmediateValueFrame && frame.FramePriority.IsType(type)) + { + _frames.RemoveAt(i); + frame.Dispose(); + removed = true; + } + } + + if (removed) + { + ++_frameGeneration; + ReevaluateEffectiveValues(); + } + } + + + public void RemoveFrames(IReadOnlyList styles) + { + var removed = false; + + for (var i = _frames.Count - 1; i >= 0; --i) + { + var frame = _frames[i]; + + if (frame is StyleInstance style && styles.Contains(style.Source)) { _frames.RemoveAt(i); frame.Dispose(); diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs index 33bca9b0ab..187edd8335 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -382,11 +382,6 @@ namespace Avalonia return _stylesApplied; } - /// - /// Detaches all styles from the element and queues a restyle. - /// - protected virtual void InvalidateStyles() => DetachStyles(); - protected void InitializeIfNeeded() { if (_initCount == 0 && !IsInitialized) @@ -508,17 +503,16 @@ namespace Avalonia }; } - void IStyleable.DetachStyles() => DetachStyles(); - void IStyleHost.StylesAdded(IReadOnlyList styles) { - InvalidateStylesOnThisAndDescendents(); + if (HasSettersOrAnimations(styles)) + InvalidateStyles(recurse: true); } void IStyleHost.StylesRemoved(IReadOnlyList styles) { - var allStyles = RecurseStyles(styles); - DetachStylesFromThisAndDescendents(allStyles); + if (FlattenStyles(styles) is { } allStyles) + DetachStyles(allStyles); } protected virtual void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -663,6 +657,23 @@ namespace Avalonia return null; } + internal virtual void InvalidateStyles(bool recurse) + { + var values = GetValueStore(); + values.BeginStyling(); + try { values.RemoveFrames(FrameType.Style); } + finally { values.EndStyling(); } + + _stylesApplied = false; + + if (recurse && GetInheritanceChildren() is { } children) + { + var childCount = children.Count; + for (var i = 0; i < childCount; ++i) + (children[i] as StyledElement)?.InvalidateStyles(recurse); + } + } + private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted) { if (o is StyledElement element) @@ -822,7 +833,7 @@ namespace Avalonia { _logicalRoot = null; _implicitTheme = null; - DetachStyles(); + InvalidateStyles(recurse: false); OnDetachedFromLogicalTree(e); DetachedFromLogicalTree?.Invoke(this, e); @@ -884,71 +895,81 @@ namespace Avalonia } } - private void DetachStyles(IReadOnlyList? styles = null) + private void DetachStyles(IReadOnlyList -"; - - using (StyledWindow(assets: ("test:style.xaml", styleXaml))) - { - var xaml = @" +"), + new RuntimeXamlLoaderDocument(@" - + -"; - - var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); +") + }; + + using (StyledWindow()) + { + var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents); + var window = Assert.IsType(compiled[1]); var border = window.FindControl("border"); var brush = (ISolidColorBrush)border.Background; @@ -284,13 +286,14 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions [Fact] public void DynamicResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File() { - var styleXaml = @" + var documents = new[] + { + new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style.xaml"), @" #ff506070 - -"; - - using (StyledWindow(assets: ("test:style.xaml", styleXaml))) - { - var xaml = @" +"), + new RuntimeXamlLoaderDocument(@" - + public class StyleInclude : IStyle, IResourceProvider { + private readonly IServiceProvider _serviceProvider; private readonly Uri? _baseUri; private IStyle[]? _loaded; private bool _isLoading; @@ -31,6 +32,7 @@ namespace Avalonia.Markup.Xaml.Styling /// The XAML service provider. public StyleInclude(IServiceProvider serviceProvider) { + _serviceProvider = serviceProvider; _baseUri = serviceProvider.GetContextBaseUri(); } @@ -52,7 +54,7 @@ namespace Avalonia.Markup.Xaml.Styling { _isLoading = true; var source = Source ?? throw new InvalidOperationException("StyleInclude.Source must be set."); - var loaded = (IStyle)AvaloniaXamlLoader.Load(source, _baseUri); + var loaded = (IStyle)AvaloniaXamlLoader.Load(_serviceProvider, source, _baseUri); _loaded = new[] { loaded }; _isLoading = false; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs index eec5d62fd3..2ca9a66fdc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs @@ -167,18 +167,24 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime #line hidden public static IServiceProvider CreateRootServiceProviderV2() { - return new RootServiceProvider(new NameScope()); + return new RootServiceProvider(new NameScope(), null); + } + public static IServiceProvider CreateRootServiceProviderV3(IServiceProvider parentServiceProvider) + { + return new RootServiceProvider(new NameScope(), parentServiceProvider); } #line default - class RootServiceProvider : IServiceProvider, IAvaloniaXamlIlParentStackProvider + class RootServiceProvider : IServiceProvider { private readonly INameScope _nameScope; + private readonly IServiceProvider _parentServiceProvider; private readonly IRuntimePlatform _runtimePlatform; - public RootServiceProvider(INameScope nameScope) + public RootServiceProvider(INameScope nameScope, IServiceProvider parentServiceProvider) { _nameScope = nameScope; + _parentServiceProvider = parentServiceProvider; _runtimePlatform = AvaloniaLocator.Current.GetService(); } @@ -187,19 +193,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime if (serviceType == typeof(INameScope)) return _nameScope; if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider)) - return this; + return _parentServiceProvider?.GetService() + ?? DefaultAvaloniaXamlIlParentStackProvider.Instance; if (serviceType == typeof(IRuntimePlatform)) return _runtimePlatform ?? throw new KeyNotFoundException($"{nameof(IRuntimePlatform)} was not registered"); return null; } - public IEnumerable Parents + private class DefaultAvaloniaXamlIlParentStackProvider : IAvaloniaXamlIlParentStackProvider { - get + public static DefaultAvaloniaXamlIlParentStackProvider Instance { get; } = new(); + + public IEnumerable Parents { - if (Application.Current != null) - yield return Application.Current; + get + { + if (Application.Current != null) + yield return Application.Current; + } } } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj index bcb4bac457..a9528edc91 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj @@ -30,6 +30,7 @@ + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs index 8eed5013a2..f148d95bf9 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs @@ -2,6 +2,10 @@ using System.Collections.Generic; using System.Linq; using Avalonia.Controls; +using Avalonia.Markup.Xaml.Styling; +using Avalonia.Markup.Xaml.XamlIl.Runtime; +using Avalonia.Media; +using Avalonia.Platform; using Avalonia.Styling; using Avalonia.Themes.Simple; using Avalonia.UnitTests; @@ -265,4 +269,43 @@ public class StyleIncludeTests Assert.IsType(control.Styles[0]); Assert.IsType(control.Styles[1]); } + + [Fact] + public void StyleInclude_From_CodeBehind_Resolves_Compiled() + { + using var locatorScope = AvaloniaLocator.EnterScope(); + AvaloniaLocator.CurrentMutable.BindToSelf(new AssetLoader(GetType().Assembly)); + + var sp = new TestServiceProvider(); + var styleInclude = new StyleInclude(sp) + { + Source = new Uri("avares://Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml") + }; + + var loaded = Assert.IsType(styleInclude.Loaded); + + Assert.Equal( + sp.GetService().Parents, + loaded.ServiceProvider.GetService().Parents); + } + + private class TestServiceProvider : IServiceProvider, IUriContext, IAvaloniaXamlIlParentStackProvider + { + private IServiceProvider _root = XamlIlRuntimeHelpers.CreateRootServiceProviderV2(); + public object GetService(Type serviceType) + { + if (serviceType == typeof(IUriContext)) + { + return this; + } + if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider)) + { + return this; + } + return _root.GetService(serviceType); + } + + public Uri BaseUri { get; set; } + public IEnumerable Parents { get; } = new[] { new ContentControl() }; + } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml new file mode 100644 index 0000000000..987c0f321a --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml @@ -0,0 +1,5 @@ + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml.cs new file mode 100644 index 0000000000..ceb122f05c --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml.cs @@ -0,0 +1,16 @@ +using System; +using Avalonia.Controls; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.UnitTests.Xaml; + +public class StyleWithServiceLocator : Style +{ + public IServiceProvider ServiceProvider { get; } + + public StyleWithServiceLocator(IServiceProvider sp = null) + { + ServiceProvider = sp; + AvaloniaXamlLoader.Load(sp, this); + } +} From afa7c320282734392f04901be46106e3177d99e4 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 30 Nov 2022 23:27:37 -0500 Subject: [PATCH 095/137] Fix merge conflict --- ...niaXamlIlConstructorServiceProviderTransformer.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs index 0304165995..35e2624ff9 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs @@ -41,18 +41,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public bool NeedsParentStack => true; public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen) { - if (_inheritContext) - { - codeGen.Ldloc(context.ContextLocal); - } - else - { - codeGen.Ldloc(context.ContextLocal); - var method = context.GetAvaloniaTypes().RuntimeHelpers - .FindMethod(m => m.Name == "CreateRootServiceProviderV3"); - codeGen.EmitCall(method); - } - codeGen.Ldloc(context.ContextLocal); return XamlILNodeEmitResult.Type(0, Type.GetClrType()); } From f4898667345648ac27b08a8e77626fcda6971d0f Mon Sep 17 00:00:00 2001 From: zhouzj Date: Thu, 1 Dec 2022 16:28:34 +0800 Subject: [PATCH 096/137] Replace ContentControl to ContentPresenter --- .../Controls/CalendarButton.xaml | 16 ++++++++-------- .../Controls/CalendarButton.xaml | 18 +++++++++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml index 06b6cf30c2..76b51ca819 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml @@ -35,13 +35,13 @@ - + @@ -70,7 +70,7 @@ - diff --git a/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml index 59fb24663f..9e13e1e996 100644 --- a/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml +++ b/src/Avalonia.Themes.Simple/Controls/CalendarButton.xaml @@ -32,14 +32,14 @@ Opacity="0.5" /> - + - From 2f3c5ef98fefb19a81f59870cc1fbc7645477469 Mon Sep 17 00:00:00 2001 From: ShadowMarker789 <37165910+ShadowMarker789@users.noreply.github.com> Date: Thu, 1 Dec 2022 17:42:44 +0800 Subject: [PATCH 097/137] Add Support for low-latency Dxgi-swapchain based presentation model (#9572) * Got the swapchain working * Removed unneeded field * Code cleanup * Fixed and added custom control with smiles. * Update DXGI_SWAP_CHAIN_FLAG.cs All of the new members should be internal. Leaving the minimum (handles?) for the interoperability. * > Please, use our COM interop codegen instead. It provides at least some safety with reference tracking / disposal DONE * Code cleanup, using statements for correct disposal, disposing of fields in the render-target. * Further code refactoring, reorganized folder structure under DirectX Co-authored-by: michael.david.howard@outlook.com --- samples/ControlCatalog.NetCore/Program.cs | 9 + .../Properties/launchSettings.json | 11 + samples/ControlCatalog/ControlCatalog.csproj | 10 + .../Converter/DegToRadConverter.cs | 29 + samples/ControlCatalog/MainView.xaml | 3 + .../ControlCatalog/Pages/CustomDrawing.xaml | 107 ++ .../Pages/CustomDrawing.xaml.cs | 67 + .../Pages/CustomDrawingExampleControl.cs | 215 +++ .../Avalonia.Win32/Avalonia.Win32.csproj | 1 + .../Avalonia.Win32/DirectX/DirectXEnums.cs | 139 ++ .../Avalonia.Win32/DirectX/DirectXStructs.cs | 1370 +++++++++++++++++ .../DirectX/DirectXUnmanagedMethods.cs | 29 + .../Avalonia.Win32/DirectX/DxgiConnection.cs | 202 +++ .../DirectX/DxgiRenderTarget.cs | 184 +++ .../DirectX/DxgiSwapchainWindow.cs | 32 + .../Avalonia.Win32/DirectX/directx.idl | 305 ++++ src/Windows/Avalonia.Win32/Win32GlManager.cs | 5 + src/Windows/Avalonia.Win32/Win32Platform.cs | 10 + src/Windows/Avalonia.Win32/WindowImpl.cs | 17 + 19 files changed, 2745 insertions(+) create mode 100644 samples/ControlCatalog.NetCore/Properties/launchSettings.json create mode 100644 samples/ControlCatalog/Converter/DegToRadConverter.cs create mode 100644 samples/ControlCatalog/Pages/CustomDrawing.xaml create mode 100644 samples/ControlCatalog/Pages/CustomDrawing.xaml.cs create mode 100644 samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/DirectXEnums.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/DirectXUnmanagedMethods.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs create mode 100644 src/Windows/Avalonia.Win32/DirectX/directx.idl diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index b1bacc6483..d5e5cb14dc 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -99,6 +99,15 @@ namespace ControlCatalog.NetCore SilenceConsole(); return builder.StartLinuxDrm(args, scaling: GetScaling()); } + else if (args.Contains("--dxgi")) + { + builder.With(new Win32PlatformOptions() + { + UseLowLatencyDxgiSwapChain = true, + UseWindowsUIComposition = false + }); + return builder.StartWithClassicDesktopLifetime(args); + } else return builder.StartWithClassicDesktopLifetime(args); } diff --git a/samples/ControlCatalog.NetCore/Properties/launchSettings.json b/samples/ControlCatalog.NetCore/Properties/launchSettings.json new file mode 100644 index 0000000000..5964ca320e --- /dev/null +++ b/samples/ControlCatalog.NetCore/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "ControlCatalog.NetCore": { + "commandName": "Project" + }, + "Dxgi": { + "commandName": "Project", + "commandLineArgs": "--dxgi" + } + } +} \ No newline at end of file diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index 6b550a30be..18f0dd16ba 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -33,4 +33,14 @@ + + + + + + + + + + diff --git a/samples/ControlCatalog/Converter/DegToRadConverter.cs b/samples/ControlCatalog/Converter/DegToRadConverter.cs new file mode 100644 index 0000000000..b062bcb64a --- /dev/null +++ b/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; + } + } +} diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index b5a09b5fbd..b95b455ca4 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -66,6 +66,9 @@ + + + diff --git a/samples/ControlCatalog/Pages/CustomDrawing.xaml b/samples/ControlCatalog/Pages/CustomDrawing.xaml new file mode 100644 index 0000000000..04b7fcfea5 --- /dev/null +++ b/samples/ControlCatalog/Pages/CustomDrawing.xaml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +