如果文本值已更改,则更改自定义文本框的背景 属性

Changing custom TextBox's background property if Text value has changed

我有一个自定义 TextBox 控件,它继承了 System.Windows.Controls.TextBox 并实现了 INotifyPropertyChanged 接口。

public partial class V3TextBox : TextBox, INotifyPropertyChanged

它有一个自定义 OriginalValue 属性 并且覆盖基础 Text 属性.

我想象它的工作方式是将 TextOriginalValue 绑定到两个不同的字符串属性,并将其 Background 设置为,比方说,如果这两个属性为黄色字符串不一样,如果它们再次变得相同,则变回白色。

这些是我的 TextPropertyChanged 属性:

private Binding PropertyChangedBinding = new Binding()
{
    Path = new PropertyPath("ChangedPropertyBackground")
};

public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

private string text { get; set; } = "";
public new string Text
{
    get
    {
        return text;
    }
    set
    {
        text = value;
        if (value == originalValue)
            BindingOperations.ClearBinding(this, BackgroundProperty);
        else
            SetBinding(BackgroundProperty, PropertyChangedBinding);
        OnPropertyChanged("Background");
    }
}

现在,问题可能出在为我的 OriginalValue 属性.

设置 DependencyProperty

它们看起来像这样:

private string originalValue;
public string OriginalValue
{
    get
    {
        return (string)GetValue(TestProperty);
    }
    set
    {
        originalValue = value;
        SetValue(TestProperty, value);
    }
}

public static readonly DependencyProperty TestProperty =
    DependencyProperty.Register("OriginalValue", typeof(string),
    typeof(V3TextBox), new FrameworkPropertyMetadata(default(string)));

private void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    SetValue(TestProperty, e.NewValue);
}

XAML 中的控件用法如下所示:

<Ctrls:V3TextBox x:Name="txtBxDiscountNote"
    Text="{Binding EditedNote, Mode=TwoWay, NotifyOnTargetUpdated=True}"
    OriginalValue="{Binding OriginalNote, Mode=TwoWay}"/>

DataContext设置在XAML.

问题是 OriginalValue 属性 永远不会改变,它总是 null 并且只有在 [=19= 时才会触发改变 Background 的代码] 属性 以编程方式更改,而不是通过 GUI 输入。使用 IValueConverter 会更容易实现吗?一个表单上将有大约 30 个这样的控件。

像这样的东西应该可以工作:

public class V3TextBox : TextBox
{
    public static readonly DependencyProperty OriginalValueProperty =
        DependencyProperty.Register("OriginalValue", typeof(string),  typeof(V3TextBox));

    public static readonly DependencyProperty ChangedBackgroundProperty =
        DependencyProperty.Register("ChangedBackground", typeof(Brush), typeof(V3TextBox));

    public string OriginalValue
    {
        get { return (string)GetValue(OriginalValueProperty); }
        set { SetValue(OriginalValueProperty, value); }
    }

    public Brush ChangedBackground
    {
        get { return (Brush)GetValue(ChangedBackgroundProperty); }
        set { SetValue(ChangedBackgroundProperty, value); }
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        base.OnTextChanged(e);

        if (Text == OriginalValue)
        {
            ClearValue(BackgroundProperty);
        }
        else
        {
            Background = ChangedBackground;
        }
    }
}

这样使用:

<local:V3TextBox OriginalValue="Hello" ChangedBackground="Yellow"/>

这是我当前的代码:

public partial class V3TextBox : TextBox
{
    public static readonly DependencyProperty OriginalValueProperty =
        DependencyProperty.Register("OriginalValue", typeof(string), typeof(V3TextBox));
    public string OriginalValue
    {
        get
        {
            return (string)GetValue(OriginalValueProperty);
        }
        set
        {
            SetValue(OriginalValueProperty, value);
        }
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        base.OnTextChanged(e);

        if (Text == OriginalValue)
            SetResourceReference(BackgroundProperty, "V3CtrlDefaultBackground");
        else
            SetResourceReference(BackgroundProperty, "V3CtrlChangedBackground");
    }


    public V3TextBox()
    {
        InitializeComponent();
    }
}

我是这样使用它的:

<Ctrls:V3TextBox x:Name="txtBxLocID"
    OriginalValue="{Binding LocationID, Mode=OneTime}"
    Text="{Binding LocationID, Mode=TwoWay}"/>

这意味着,我将 TextOriginalValue 绑定到相同的 属性,但后者具有设置 Mode=OneTime.

所以 OriginalValue 只被设置一次,并且只要它还活着就会保持它的值,我可以将它与当前的 Text 值进行比较。

@Clemens 我正在使用你的一些代码,所以它会被标记为正确答案,如果你对我的代码有更多建议,请告诉我?我需要使用您的代码在 XAML 中再设置一个 属性,因此我不会将 DependencyProperty 用于 Background Brush。也许如果有一种方法可以在XAML中设置Text 属性,第一次在代码中将其设置为OriginalValue,然后比较它是否有进一步的变化?背后的代码能否以某种方式意识到第一次调用事实绑定或类似的事情?如果 XAML 可以不写 OriginalValue 属性 就好了。 OriginalValueV3TextBox 本身的 XAML 中看不到,只 One-way 将它绑定到 Text.

也可以