【问题标题】:Changing custom TextBox's background property if Text value has changed如果 Text 值已更改,则更改自定义 TextBox 的背景属性
【发布时间】:2018-02-05 15:51:37
【问题描述】:

我有一个自定义的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,并且更改Background 的代码仅在Text 属性以编程方式更改时触发,而不是通过GUI 输入。使用IValueConverter 会更容易实现吗?一个表单上将有大约 30 个这样的控件。

【问题讨论】:

  • 请注意,像 originalValue 这样的依赖属性有一个“支持字段”是没有意义的。还有强制性的命名约定。您的 DependencyProperty 字段应为 OriginalValueProperty,而不是 TestProperty。除此之外,您没有在任何地方注册 OnTextPropertyChanged 回调。请仔细阅读Custom Dependency Properties
  • 您真的打算在 Text 更改时更新 OriginalValue(正如 OnTextPropertyChanged 方法所暗示的那样)?这有意义吗?
  • 另外说明,实现 INotifyPropertyChanged 也是没有意义的。背景是一个依赖属性,因此已经支持更改通知。
  • 另外,在文本绑定上设置Mode=TwoWay 是多余的。默认情况下,Text 属性已经绑定了 TwoWay。 NotifyOnTargetUpdated=True 也不是必需的,除非您订阅了 Bindings 的 TargetUpdated 事件,而您显然没有这样做。
  • TestProperty 变成了OriginalValueProperty,谢谢。

标签: wpf xaml binding dependency-properties ivalueconverter


【解决方案1】:

这样的事情应该可以工作:

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"/>

【讨论】:

    【解决方案2】:

    这是我当前的代码:

    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 属性的情况下编写,那就太好了。在V3TextBox 本身的XAML 中看不到OriginalValue,也可以将One-way 绑定到Text

    【讨论】:

    • 除了完全不清楚您在 OriginalValue getter 中所做的事情之外,您应该知道在依赖项属性的 getter 和 setter 中不能调用 GetValue 和 SetValue 以外的任何东西。也就是说,SetResourceReference 似乎也没有意义。你真的不想从你的控制代码中访问一个固定的资源键,是吗?另请注意,使用 @ 表示法寻址另一个 StackOverflow 用户仅适用于 cmets。
    • OriginalValue getter 中有哪些不清楚的地方?我只是将OriginalValueProperty 的值分配给一个变量,如果前者为空,则返回Text。这样做是因为我不想两次调用GetValue()。对于资源 - 是的,我确实想更改 DynamicResource TextBox Background 属性指向,这是错误的方法吗?
    • 如前所述,您不能在依赖属性的 getter 和 setter 中调用 GetValue 和 SetValue 以外的任何内容。见这里:docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/…
    • 我通过更改 XAML 中的 Binding 顺序(其中使用了 TextBox),设法让它在不检查值是否为 null 的情况下工作。而不是:..Text="{Binding ..}" OriginalValue="{Binding ..}".. 现在被颠倒了。我更新了代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多