From 2fd70994adc8535c8380459a0505aaf43faac77c Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sat, 14 Nov 2020 19:48:45 +0100 Subject: [PATCH 1/3] Remove enumerator allocations and LINQ from children change notifications. --- src/Avalonia.Styling/StyledElement.cs | 48 ++++++++++++++++----------- src/Avalonia.Visuals/Visual.cs | 37 ++++++++++----------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index 65885ddebe..cc8d91462d 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -1,8 +1,8 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; -using System.Linq; using Avalonia.Animation; using Avalonia.Collections; using Avalonia.Controls; @@ -479,16 +479,16 @@ namespace Avalonia switch (e.Action) { case NotifyCollectionChangedAction.Add: - SetLogicalParent(e.NewItems.Cast()); + SetLogicalParent(e.NewItems); break; case NotifyCollectionChangedAction.Remove: - ClearLogicalParent(e.OldItems.Cast()); + ClearLogicalParent(e.OldItems); break; case NotifyCollectionChangedAction.Replace: - ClearLogicalParent(e.OldItems.Cast()); - SetLogicalParent(e.NewItems.Cast()); + ClearLogicalParent(e.OldItems); + SetLogicalParent(e.NewItems); break; case NotifyCollectionChangedAction.Reset: @@ -702,13 +702,32 @@ namespace Avalonia OnDataContextChanged(EventArgs.Empty); } - private void SetLogicalParent(IEnumerable children) + private void SetLogicalParent(IList children) { - foreach (var i in children) + var count = children.Count; + + for (var i = 0; i < count; i++) + { + var logical = (ILogical) children[i]; + + if (logical.LogicalParent is null) + { + ((ISetLogicalParent)logical).SetParent(this); + } + } + } + + private void ClearLogicalParent(IList children) + { + var count = children.Count; + + for (var i = 0; i < count; i++) { - if (i.LogicalParent == null) + var logical = (ILogical) children[i]; + + if (logical.LogicalParent == this) { - ((ISetLogicalParent)i).SetParent(this); + ((ISetLogicalParent)logical).SetParent(null); } } } @@ -784,17 +803,6 @@ namespace Avalonia } } - private void ClearLogicalParent(IEnumerable children) - { - foreach (var i in children) - { - if (i.LogicalParent == this) - { - ((ISetLogicalParent)i).SetParent(null); - } - } - } - private void NotifyResourcesChanged( ResourcesChangedEventArgs? e = null, bool propagate = true) diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index 283d9deb52..30073c9966 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Specialized; using Avalonia.Collections; using Avalonia.Data; @@ -619,34 +620,30 @@ namespace Avalonia switch (e.Action) { case NotifyCollectionChangedAction.Add: - foreach (Visual v in e.NewItems) - { - v.SetVisualParent(this); - } - + SetVisualParent(e.NewItems, this); break; case NotifyCollectionChangedAction.Remove: - foreach (Visual v in e.OldItems) - { - v.SetVisualParent(null); - } - + SetVisualParent(e.OldItems, null); break; case NotifyCollectionChangedAction.Replace: - foreach (Visual v in e.OldItems) - { - v.SetVisualParent(null); - } - - foreach (Visual v in e.NewItems) - { - v.SetVisualParent(this); - } - + SetVisualParent(e.OldItems, null); + SetVisualParent(e.NewItems, this); break; } } + + private static void SetVisualParent(IList children, Visual parent) + { + var count = children.Count; + + for (var i = 0; i < count; i++) + { + var visual = (Visual) children[i]; + + visual.SetVisualParent(parent); + } + } } } From a778800d2e706524895426dae254f07d046dd802 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 15 Nov 2020 14:19:07 +0100 Subject: [PATCH 2/3] Remove boxing from TemplatedControl as well. --- src/Avalonia.Controls/Primitives/TemplatedControl.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index d18cf7da71..9c73ff2411 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -354,11 +354,14 @@ namespace Avalonia.Controls.Primitives { control.SetValue(TemplatedParentProperty, this); - foreach (var child in control.LogicalChildren) + var children = control.LogicalChildren; + var count = children.Count; + + for (var i = 0; i < count; i++) { - if (child is IControl c) + if (children[i] is IControl child) { - ApplyTemplatedParent(c); + ApplyTemplatedParent(child); } } } From cde8f4cf1aa5ee1ad969a99b8363456c09aa53e7 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 15 Nov 2020 14:27:10 +0100 Subject: [PATCH 3/3] Fix control benchmarks. --- tests/Avalonia.Benchmarks/NullRenderingPlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs index f632d85c26..1570205456 100644 --- a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs +++ b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs @@ -28,7 +28,7 @@ namespace Avalonia.Benchmarks public IGeometryImpl CreateRectangleGeometry(Rect rect) { - throw new NotImplementedException(); + return new MockStreamGeometryImpl(); } public IStreamGeometryImpl CreateStreamGeometry()