简体   繁体   中英

Trigger on UserControl property changed from code behind

I'm writing a UserControl TextBox that will change color when the text inside it is not a valid number.

This is the class declaration:

public partial class ValidatedNumberBox : UserControl, INotifyPropertyChanged
{
    public bool IsValid { get; set; }
    public static readonly DependencyProperty IsValidProperty = DependencyProperty.RegisterAttached(
        nameof(IsValid), typeof(bool), typeof(ValidatedNumberBox), new PropertyMetadata(true));
    public ValidatedNumberBox()
    {
        InitializeComponent();
        IsValid = CheckValidity();
    }

    private void PART_TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        IsValid = CheckValidity();
        OnPropertyChanged(nameof(IsValid));
        TextChanged?.Invoke(sender, e);
    }

    private bool CheckValidity()
    {
        return !PART_TextBox.Text.Any(char.IsLetter);
    }

    #region INotify

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion

}

The xaml is simply a TextBox:

<UserControl x:Class="fisWPF.Controls.ValidatedNumberBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         mc:Ignorable="d">
<Grid>
    <TextBox Name="PART_TextBox" TextChanged="PART_TextBox_OnTextChanged" />
</Grid>

I'm trying to get a border to change when the property IsValid is false like so:

<Style TargetType="{x:Type Controls:ValidatedNumberBox}">
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Controls:ValidatedNumberBox}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            Background="{TemplateBinding Background}" 
                            Padding="{TemplateBinding Padding}"
                            SnapsToDevicePixels="True">
                        <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
                                          Content="{TemplateBinding Content}" 
                                          ContentStringFormat="{TemplateBinding ContentStringFormat}" 
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsValid" Value="False">
                            <Setter Property="BorderBrush" Value="Red"/>
                            <Setter Property="BorderThickness" Value="20"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

If I change the trigger from False to True the red border appears on the control, and if I bind IsValid to, for instance, a CheckBox's IsChecked property it works too. The only thing that won't change the border is changing the value in code behind. As can be seen, I've tried using the INorifyPropertyChanged interface as is the answer to many questions in this page. However, the value of the PropertyChanged event is always null and nothing happens when I write letters in the TextBox.

IsValid is a dependency property that is supposed to have a CLR wrapper:

public partial class ValidatedNumberBox : UserControl
{
    public static readonly DependencyProperty IsValidProperty = DependencyProperty.RegisterAttached(
        nameof(IsValid), typeof(bool), typeof(ValidatedNumberBox), new PropertyMetadata(true));

    // .NET property wrapper
    public bool IsValid
    {
        get { return (bool)GetValue(IsValidProperty); }
        set { SetValue(IsValidProperty, value); }
    }

    public ValidatedNumberBox()
    {
        InitializeComponent();
        IsValid = CheckValidity();
    }

    private void PART_TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        IsValid = CheckValidity();
        TextChanged?.Invoke(sender, e);
    }

    private bool CheckValidity()
    {
        return !PART_TextBox.Text.Any(char.IsLetter);
    }
}

You don't have to implement the INotifyPropertyChanged interface to raise change notifications for dependency properties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM