Skip to content

Commit

Permalink
perf(Style): Implement Style.IsSealed to allow for flattened lists ca…
Browse files Browse the repository at this point in the history
…ching

This update also removes the use of dictionary enumeration for setters application, and delegate to apply the setters.
  • Loading branch information
jeromelaban committed Dec 8, 2021
1 parent 669f4d3 commit 1970c77
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 80 deletions.
2 changes: 1 addition & 1 deletion src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<PackageReference Update="Uno.Wasm.Bootstrap.DevServer" Version="2.1.0" />
<PackageReference Update="xamarin.build.download" Version="0.10.0" PrivateAssets="all" />
<PackageReference Update="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Update="MSTest.TestFramework" Version="2.2.6" />
<PackageReference Update="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Update="Uno.MonoAnalyzers" Version="1.0.0" PrivateAssets="all" />
<PackageReference Update="System.Memory" Version="4.5.4" />
<PackageReference Update="Uno.Wasm.WebSockets" Version="1.1.0" />
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Tests/App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ override void OnLaunched(LaunchActivatedEventArgs args)
/// <returns>The 'running' application.</returns>
public static App EnsureApplication()
{
if (Current == null)
if (Current is not App)
{
var application = new App();
#if !NETFX_CORE
Expand Down
118 changes: 118 additions & 0 deletions src/Uno.UI.Tests/Windows_UI_Xaml/Given_Style.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Uno.UI.Tests.App.Xaml;
using Uno.UI.Tests.Helpers;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace Uno.UI.Tests.Windows_UI_Xaml
{
[TestClass]
public class Given_Style
{
[TestInitialize]
public void Init()
{
UnitTestsApp.App.EnsureApplication();
}

[TestMethod]
public void When_Sealed_Style_Add_Setter()
{
var SUT = new Style(typeof(Control));

SUT.Setters.Add(new Setter(Control.IsEnabledProperty, true));

SUT.Seal();

Assert.IsTrue(SUT.IsSealed);
Assert.IsTrue(SUT.Setters.IsSealed);
Assert.IsTrue(SUT.Setters[0].IsSealed);

Assert.ThrowsException<InvalidOperationException>(() => SUT.Setters.Add(new Setter(Control.IsHitTestVisibleProperty, true)));
}

[TestMethod]
public void When_Sealed_Style_Remove()
{
var SUT = new Style(typeof(Control));

SUT.Setters.Add(new Setter(Control.IsEnabledProperty, true));

SUT.Seal();

Assert.IsTrue(SUT.IsSealed);
Assert.IsTrue(SUT.Setters.IsSealed);
Assert.IsTrue(SUT.Setters[0].IsSealed);

SUT.Setters.Clear();
}

[TestMethod]
public void When_Sealed_Style_Setter_Update()
{
var SUT = new Style(typeof(Control));

Setter s;
SUT.Setters.Add(s = new Setter(Control.IsEnabledProperty, true));

SUT.Seal();

Assert.IsTrue(SUT.IsSealed);
Assert.IsTrue(SUT.Setters.IsSealed);
Assert.IsTrue(SUT.Setters[0].IsSealed);

Assert.ThrowsException<InvalidOperationException>(() => s.Value = null);
}

[TestMethod]
public void When_Sealed_Style_BasedOn_Sealed()
{
var SUT = new Style(typeof(Control));
SUT.Setters.Add(new Setter(Control.IsEnabledProperty, true));

var SUT2 = new Style(typeof(Control)) { BasedOn = SUT };
SUT2.Setters.Add(new Setter(Control.IsEnabledProperty, true));

SUT2.Seal();

Assert.IsTrue(SUT.IsSealed);
Assert.IsTrue(SUT.Setters.IsSealed);
Assert.IsTrue(SUT.Setters[0].IsSealed);

Assert.IsTrue(SUT2.IsSealed);
Assert.IsTrue(SUT2.Setters.IsSealed);
Assert.IsTrue(SUT2.Setters[0].IsSealed);
}

[TestMethod]
public void When_Sealed_Style_On_Apply()
{
var SUT = new Style(typeof(Control));
SUT.Setters.Add(new Setter(Control.IsEnabledProperty, true));

var SUT2 = new Style(typeof(Control)) { BasedOn = SUT };
SUT2.Setters.Add(new Setter(Control.IsEnabledProperty, true));

SUT2.Seal();

Control control = new();
control.Style = SUT2;

Assert.IsTrue(SUT.IsSealed);
Assert.IsTrue(SUT.Setters.IsSealed);
Assert.IsTrue(SUT.Setters[0].IsSealed);

Assert.IsTrue(SUT2.IsSealed);
Assert.IsTrue(SUT2.Setters.IsSealed);
Assert.IsTrue(SUT2.Setters[0].IsSealed);
}
}
}
13 changes: 2 additions & 11 deletions src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml/SetterBase.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
#pragma warning disable 108 // new keyword hiding
#pragma warning disable 114 // new keyword hiding
using System;

namespace Windows.UI.Xaml
{
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial class SetterBase : global::Windows.UI.Xaml.DependencyObject
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public bool IsSealed
{
get
{
throw new global::System.NotImplementedException("The member bool SetterBase.IsSealed is not implemented in Uno.");
}
}
#endif
// Forced skipping of method Windows.UI.Xaml.SetterBase.IsSealed.get
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,7 @@ namespace Windows.UI.Xaml
#endif
public partial class SetterBaseCollection : global::System.Collections.Generic.IList<global::Windows.UI.Xaml.SetterBase>,global::System.Collections.Generic.IEnumerable<global::Windows.UI.Xaml.SetterBase>
{
// Skipping already declared property Size
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public bool IsSealed
{
get
{
throw new global::System.NotImplementedException("The member bool SetterBaseCollection.IsSealed is not implemented in Uno.");
}
}
#endif

// Skipping already declared method Windows.UI.Xaml.SetterBaseCollection.SetterBaseCollection()
// Forced skipping of method Windows.UI.Xaml.SetterBaseCollection.SetterBaseCollection()
// Forced skipping of method Windows.UI.Xaml.SetterBaseCollection.IsSealed.get
Expand Down
30 changes: 0 additions & 30 deletions src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml/Style.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,5 @@ namespace Windows.UI.Xaml
#endif
public partial class Style : global::Windows.UI.Xaml.DependencyObject
{
// Skipping already declared property TargetType
// Skipping already declared property BasedOn
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public bool IsSealed
{
get
{
throw new global::System.NotImplementedException("The member bool Style.IsSealed is not implemented in Uno.");
}
}
#endif
// Skipping already declared property Setters
// Skipping already declared method Windows.UI.Xaml.Style.Style(System.Type)
// Forced skipping of method Windows.UI.Xaml.Style.Style(System.Type)
// Skipping already declared method Windows.UI.Xaml.Style.Style()
// Forced skipping of method Windows.UI.Xaml.Style.Style()
// Forced skipping of method Windows.UI.Xaml.Style.IsSealed.get
// Forced skipping of method Windows.UI.Xaml.Style.Setters.get
// Forced skipping of method Windows.UI.Xaml.Style.TargetType.get
// Forced skipping of method Windows.UI.Xaml.Style.TargetType.set
// Forced skipping of method Windows.UI.Xaml.Style.BasedOn.get
// Forced skipping of method Windows.UI.Xaml.Style.BasedOn.set
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public void Seal()
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Style", "void Style.Seal()");
}
#endif
}
}
8 changes: 8 additions & 0 deletions src/Uno.UI/UI/Xaml/DependencyObjectCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,15 @@ internal void UpdateParent(object parent)

public bool IsReadOnly => ((ICollection<T>)_list).IsReadOnly;

private protected virtual void ValidateItem(T item) { }

public T this[int index]
{
get => _list[index];
set
{
ValidateItem(value);

var originalValue = _list[index];

if (!ReferenceEquals(originalValue, value))
Expand All @@ -118,6 +122,8 @@ public T this[int index]

public void Insert(int index, T item)
{
ValidateItem(item);

EnsureNotLocked();

_list.Insert(index, item);
Expand All @@ -142,6 +148,8 @@ public void Add(T item)
{
EnsureNotLocked();

ValidateItem(item);

_list.Add(item);

OnAdded(item);
Expand Down
35 changes: 31 additions & 4 deletions src/Uno.UI/UI/Xaml/Setter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public Setter()
private readonly SetterValueProviderHandler? _valueProvider;
private object? _value;
private int _targetNameResolutionFailureCount;
private DependencyProperty? _property;
private TargetPropertyPath? _target;

public object? Value
{
Expand All @@ -43,19 +45,44 @@ public object? Value

return _value;
}
set => _value = value;
set
{
ValidateIsSealed();

_value = value;
}
}

private void ValidateIsSealed()
{
if (IsSealed)
{
throw new InvalidOperationException($"The setter is sealed and cannot be modified");
}
}

public TargetPropertyPath? Target
{
get;
set;
get => _target;
set
{
ValidateIsSealed();
_target = value;
}
}

/// <summary>
/// The property being set by this setter
/// </summary>
public DependencyProperty? Property { get; set; }
public DependencyProperty? Property
{
get => _property;
set
{
ValidateIsSealed();
_property = value;
}
}

/// <summary>
/// The name of the ThemeResource applied to the value, if any, as an optimized key.
Expand Down
8 changes: 8 additions & 0 deletions src/Uno.UI/UI/Xaml/SetterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ partial void OnDataContextChangedPartial(DependencyPropertyChangedEventArgs e)
{
this.Log().Debug("SetterBase.DataContextChanged");
}

public bool IsSealed
{
get; private set;
}

internal void Seal()
=> IsSealed = true;
}
}

25 changes: 25 additions & 0 deletions src/Uno.UI/UI/Xaml/SetterBaseCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,30 @@ internal SetterBaseCollection(DependencyObject parent, bool isAutoPropertyInheri
: base(parent, isAutoPropertyInheritanceEnabled: false)
{
}

public bool IsSealed { get; private set; }

internal void Seal()
=> IsSealed = true;

private protected override void ValidateItem(SetterBase item)
{
base.ValidateItem(item);

if (IsSealed)
{
throw new InvalidOperationException($"The SetterBaseCollection is sealed and cannot be modified");
}
}

private protected override void OnAdded(SetterBase setterBase)
{
base.OnAdded(setterBase);

if(setterBase is Setter setter && setter.Target is null)
{
setterBase.Seal();
}
}
}
}
Loading

0 comments on commit 1970c77

Please sign in to comment.