[C] Lowest specificity for propagated values (#17648)
IsEnabled value is propagated on parenting. Do this with the special (fromHandler) specificity, to allow styling - fixes #17597
This commit is contained in:
Родитель
6f6d1929d3
Коммит
2cdf7234bb
|
@ -124,19 +124,29 @@ namespace Microsoft.Maui.Controls
|
|||
if (bpcontext == null)
|
||||
return;
|
||||
|
||||
var original = bpcontext.Values.GetSpecificityAndValue().Value;
|
||||
var newValue = bpcontext.Values.GetClearedValue();
|
||||
var changed = !Equals(original, newValue);
|
||||
var original = bpcontext.Values.GetSpecificityAndValue();
|
||||
if (original.Key == SetterSpecificity.FromHandler)
|
||||
bpcontext.Values.Remove(SetterSpecificity.FromHandler);
|
||||
|
||||
|
||||
var newValue = bpcontext.Values.GetClearedValue(specificity);
|
||||
var changed = !Equals(original.Value, newValue);
|
||||
if (changed)
|
||||
{
|
||||
property.PropertyChanging?.Invoke(this, original, newValue);
|
||||
property.PropertyChanging?.Invoke(this, original.Value, newValue);
|
||||
OnPropertyChanging(property.PropertyName);
|
||||
}
|
||||
|
||||
bpcontext.Values.Remove(specificity);
|
||||
|
||||
//there's some side effect implemented in CoerceValue (see IsEnabled) that we need to trigger here
|
||||
if (property.CoerceValue != null)
|
||||
property.CoerceValue(this, newValue);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
OnPropertyChanged(property.PropertyName);
|
||||
property.PropertyChanged?.Invoke(this, original, newValue);
|
||||
property.PropertyChanged?.Invoke(this, original.Value, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Microsoft.Maui.Controls
|
|||
else
|
||||
{
|
||||
// support normal/code properties
|
||||
self.SetValue(property, value);
|
||||
self.SetValue(property, value, SetterSpecificity.FromHandler);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,26 +91,24 @@ namespace Microsoft.Maui.Controls
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by ClearValueCore, returns what the value would be if cleared
|
||||
/// Called by ClearValueCore, returns what the top value would be if cleared
|
||||
/// </summary>
|
||||
public object? GetClearedValue()
|
||||
public object? GetClearedValue(SetterSpecificity clearedSpecificity)
|
||||
{
|
||||
if (_values is not null)
|
||||
{
|
||||
return _values.Count >= 2 ? _values[_values.Keys[_values.Count - 2]] : null;
|
||||
var index = _values.IndexOfKey(clearedSpecificity);
|
||||
if (index == _values.Count -1) //last value will be cleared
|
||||
return _values.Count >= 2 ? _values[_values.Keys[_values.Count - 2]] : null;
|
||||
return _values.Last().Value;
|
||||
}
|
||||
|
||||
// Fast path should return the "lower" value
|
||||
if (_first is not null && _second is not null)
|
||||
{
|
||||
if (_second.Value.Key.CompareTo(_first.Value.Key) >= 0)
|
||||
{
|
||||
return _first.Value.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_first.Value.Key == clearedSpecificity)
|
||||
return _second.Value.Value;
|
||||
}
|
||||
return _first.Value.Value;
|
||||
}
|
||||
else if (_first is not null)
|
||||
{
|
||||
|
|
|
@ -63,9 +63,10 @@ namespace Microsoft.Maui.Controls.Core.UnitTests
|
|||
{
|
||||
var list = new SetterSpecificityList();
|
||||
list.SetValue(SetterSpecificity.DefaultValue, nameof(SetterSpecificity.DefaultValue));
|
||||
Assert.Equal(nameof(SetterSpecificity.DefaultValue), list.GetClearedValue());
|
||||
Assert.Equal(nameof(SetterSpecificity.DefaultValue), list.GetClearedValue(SetterSpecificity.DefaultValue));
|
||||
list.SetValue(SetterSpecificity.ManualValueSetter, nameof(SetterSpecificity.ManualValueSetter));
|
||||
Assert.Equal(nameof(SetterSpecificity.DefaultValue), list.GetClearedValue());
|
||||
Assert.Equal(nameof(SetterSpecificity.DefaultValue), list.GetClearedValue(SetterSpecificity.ManualValueSetter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:local="clr-namespace:Microsoft.Maui.Controls.Xaml.UnitTests"
|
||||
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui17597">
|
||||
<StackLayout>
|
||||
<Entry x:Name="Test_Entry" Text="Remove Text To Disable Button"/>
|
||||
<Button x:Name="button" Text="Test Button" Margin="0,10,0,0" >
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="IsEnabled" Value="True"/> <!-- Does not seem to honor this statement at all -->
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Source={x:Reference Test_Entry}, Path=Text.Length}" TargetType="Button" Value="0">
|
||||
<Setter Property="IsEnabled" Value="False" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</StackLayout>
|
||||
</ContentPage>
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.Controls.Core.UnitTests;
|
||||
using Microsoft.Maui.Controls.Shapes;
|
||||
using Microsoft.Maui.Devices;
|
||||
using Microsoft.Maui.Graphics;
|
||||
using Microsoft.Maui.UnitTests;
|
||||
using Microsoft.Maui.Dispatching;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Microsoft.Maui.Controls.Xaml.UnitTests;
|
||||
|
||||
public partial class Maui17597 : ContentPage
|
||||
{
|
||||
|
||||
public Maui17597() => InitializeComponent();
|
||||
|
||||
public Maui17597(bool useCompiledXaml)
|
||||
{
|
||||
//this stub will be replaced at compile time
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
class Test
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Application.SetCurrentApplication(new MockApplication());
|
||||
DispatcherProvider.SetCurrent(new DispatcherProviderStub());
|
||||
}
|
||||
|
||||
|
||||
[TearDown] public void TearDown() => AppInfo.SetCurrent(null);
|
||||
[Test]
|
||||
public void DataTriggerInStyle([Values(false, true)] bool useCompiledXaml)
|
||||
{
|
||||
var page = new Maui17597(useCompiledXaml);
|
||||
Assert.That(page.Test_Entry.Text, Is.EqualTo("Remove Text To Disable Button"));
|
||||
Assert.That(page.button.IsEnabled, Is.True);
|
||||
|
||||
page.Test_Entry.SetValueFromRenderer(Entry.TextProperty, "");
|
||||
Assert.That(page.Test_Entry.Text, Is.Empty);
|
||||
Assert.That(page.Test_Entry.Text.Length, Is.EqualTo(0));
|
||||
Assert.That(page.button.IsEnabled, Is.False);
|
||||
|
||||
page.Test_Entry.SetValueFromRenderer(Entry.TextProperty, "foo");
|
||||
Assert.That(page.Test_Entry.Text, Is.Not.Empty);
|
||||
Assert.That(page.button.IsEnabled, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче