有没有更简单的方法来更新 WPF 中的相关属性?

Posted

技术标签:

【中文标题】有没有更简单的方法来更新 WPF 中的相关属性?【英文标题】:Is there an easier way to update related properties in WPF? 【发布时间】:2021-11-08 16:03:45 【问题描述】:

我有一个将评分显示为星数的 UserControl。它通过将 TextBlock 的 Text 属性绑定到常规代码隐藏属性来实现此目的,该属性又使用整数 DependencyProperty Value

为了在 Value 发生变化时更新 TextBlock,我需要从 DependencyProperty 的 PropertyChangedCallback 手动触发 INotifyPropertyChanged.PropertyChanged 事件。

这感觉太过分了。有没有更简单的方法来做到这一点?

<TextBlock Text="Binding RatingDisplay, Mode=OneWay, RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type local:Rating" />
public partial class Rating : UserControl, INotifyPropertyChanged

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(int), typeof(Rating), new PropertyMetadata(0, (sender, e) =>
        
            ((Rating)sender).RaisePropertyChanged(nameof(RatingDisplay));
        ));

    public Rating()
    
        InitializeComponent();
    

    public event PropertyChangedEventHandler? PropertyChanged;

    public int Value
    
        get => (int)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    

    public string RatingDisplay => new string('*', Value);

    protected void RaisePropertyChanged(string? propertyName = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

【问题讨论】:

为什么不使用与 UserControl 连接的 ViewModel?这样你就不需要一个 Dependency 属性来让你的代码更容易阅读。 这是一个糟糕的建议。 UserControl - 与任何其他控件一样 - 不应该有自己的私有视图模型,这将与应用程序的视图模型结构断开连接。 【参考方案1】:

您不需要在公开依赖属性的类中实现 INotifyPropertyChanged。依赖属性提供自己的更改通知机制。

为了更新一个只读的依赖属性,这样的事情应该可以工作:

public partial class Rating : UserControl

    private static readonly DependencyPropertyKey RatingDisplayPropertyKey =
        DependencyProperty.RegisterReadOnly(
            nameof(RatingDisplay), typeof(string), typeof(Rating), null);

    public static readonly DependencyProperty RatingDisplayProperty =
        RatingDisplayPropertyKey.DependencyProperty;

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(
            nameof(Value), typeof(int), typeof(Rating),
            new PropertyMetadata(0, (o, e) => o.SetValue(
                RatingDisplayPropertyKey, new string('*', (int)e.NewValue))));

    public Rating()
    
        InitializeComponent();
    

    public int Value
    
        get => (int)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    

    public string RatingDisplay => (string)GetValue(RatingDisplayProperty);


或者,将 Value 属性与一个 Binding Converter 绑定,该转换器从 Rating Value 创建一个字符串。


或者,可能是最简单的,直接访问应该更新的 UI 元素:

<TextBlock x:Name="ratingDisplay"/>

后面有这段代码:

public partial class Rating : UserControl

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(
            nameof(Value), typeof(int), typeof(Rating),
            new PropertyMetadata(0, (o, e) =>
                ((Rating)o).ratingDisplay.Text = new string('*', (int)e.NewValue)));

    public Rating()
    
        InitializeComponent();
    

    public int Value
    
        get => (int)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    

【讨论】:

以上是关于有没有更简单的方法来更新 WPF 中的相关属性?的主要内容,如果未能解决你的问题,请参考以下文章

WPF DataGrid 单元格绑定到域对象中属性的属性未更新

在 JavaScript 中,是不是有更简单的方法来检查属性的属性是不是存在?

WPF UpdateSourceTrigger属性

自动更新 WPF 数据网格中的计算属性

更改文化时wpf更新验证错误

如何定位这个组件的 HTML 属性,有没有更简单的方法来获取这个元素?