From 38ce4a2a2891ef409c90f73790de05c0bc1ef314 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Tue, 8 Dec 2020 18:41:40 +0300 Subject: [PATCH] Added ability to use non well known property types in style selector --- .../Activators/PropertyEqualsActivator.cs | 2 +- .../Styling/PropertyEqualsSelector.cs | 32 +++++++++++++++++-- .../SelectorTests_PropertyEquals.cs | 20 ++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Styling/Styling/Activators/PropertyEqualsActivator.cs b/src/Avalonia.Styling/Styling/Activators/PropertyEqualsActivator.cs index 9e30e4fa14..8d446ebc9c 100644 --- a/src/Avalonia.Styling/Styling/Activators/PropertyEqualsActivator.cs +++ b/src/Avalonia.Styling/Styling/Activators/PropertyEqualsActivator.cs @@ -33,6 +33,6 @@ namespace Avalonia.Styling.Activators void IObserver.OnCompleted() { } void IObserver.OnError(Exception error) { } - void IObserver.OnNext(object value) => PublishNext(Equals(value, _value)); + void IObserver.OnNext(object value) => PublishNext(PropertyEqualsSelector.Compare(_property.PropertyType, value, _value)); } } diff --git a/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs b/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs index cdd985ac80..5d9c3fe56b 100644 --- a/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs +++ b/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs @@ -1,4 +1,6 @@ using System; +using System.ComponentModel; +using System.Globalization; using System.Text; using Avalonia.Styling.Activators; @@ -75,11 +77,37 @@ namespace Avalonia.Styling } else { - var result = (control.GetValue(_property) ?? string.Empty).Equals(_value); - return result ? SelectorMatch.AlwaysThisInstance : SelectorMatch.NeverThisInstance; + return Compare(_property.PropertyType, control.GetValue(_property), _value) + ? SelectorMatch.AlwaysThisInstance + : SelectorMatch.NeverThisInstance; } + } protected override Selector? MovePrevious() => _previous; + + internal static bool Compare(Type propertyType, object propertyValue, object? value) + { + if (propertyType == typeof(object) && + propertyValue?.GetType() is Type inferredType) + { + propertyType = inferredType; + } + + var valueType = value?.GetType(); + + if (valueType is null || propertyType.IsAssignableFrom(valueType)) + { + return Equals(propertyValue, value); + } + + var converter = TypeDescriptor.GetConverter(propertyType); + if (converter?.CanConvertFrom(valueType) == true) + { + return Equals(propertyValue, converter.ConvertFrom(null, CultureInfo.InvariantCulture, value)); + } + + return false; + } } } diff --git a/tests/Avalonia.Styling.UnitTests/SelectorTests_PropertyEquals.cs b/tests/Avalonia.Styling.UnitTests/SelectorTests_PropertyEquals.cs index e149410152..581a655c8e 100644 --- a/tests/Avalonia.Styling.UnitTests/SelectorTests_PropertyEquals.cs +++ b/tests/Avalonia.Styling.UnitTests/SelectorTests_PropertyEquals.cs @@ -22,6 +22,20 @@ namespace Avalonia.Styling.UnitTests Assert.False(await activator.Take(1)); } + [Fact] + public async Task PropertyEquals_Matches_When_Property_Has_Matching_Value_And_Different_Type() + { + var control = new TextBlock(); + var target = default(Selector).PropertyEquals(TextBlock.TagProperty, "Bar"); + var activator = target.Match(control).Activator.ToObservable(); + + Assert.False(await activator.Take(1)); + control.Tag = FooBar.Bar; + Assert.True(await activator.Take(1)); + control.Tag = null; + Assert.False(await activator.Take(1)); + } + [Fact] public void OfType_PropertyEquals_Doesnt_Match_Control_Of_Wrong_Type() { @@ -40,5 +54,11 @@ namespace Avalonia.Styling.UnitTests Assert.Equal("TextBlock[Text=foo]", target.ToString()); } + + private enum FooBar + { + Foo, + Bar + } } }