【问题标题】:readonly DependencyProperty derived from other DependencyProperty从其他 DependencyProperty 派生的只读 DependencyProperty
【发布时间】:2020-11-23 22:42:44
【问题描述】:

我的对象有一个真正的属性VideoDimension 和一个属性VideoRatio,这基本上是前者的“简化”版本。 我正在寻找一种以最优雅的方式将两者联系起来的方法。

public static readonly DependencyProperty VideoDimensionProperty = 
    DependencyProperty.Register(
        nameof(VideoDimension), 
        typeof(Point), 
        typeof(MyControl), 
        new PropertyMetadata(new Point(0, 0))
    );
public Point VideoDimension
{
    get { return (Point)GetValue(VideoDimensionProperty); }
    set { SetValue(VideoDimensionProperty, value); }
}


public static readonly DependencyProperty VideoRatioProperty = 
    MysteryFunction(VideoDimensionProperty, (value) =>
        {
            Point point = (Point)value;
            return point.X / point.Y;
        });
public double VideoRatio
{
    get { return (double)GetValue(VideoRatioProperty); }
}

上面的MysteryFunction 可能是什么? 我想以懒惰的方式计算VideoRatio。

目前我发现的解决方法是:

  • 将VideoRatioProperty 设为自己的DependencyProperty,并在VideoDimension 更改时手动更新它。这并不理想,因为:
    • VideoRatioProperty 如果没有人听,可能会一无所获。
    • 它创建了第二个事实来源。它使人们能够修改VideoRatio 而不是VideoDimension。这可以通过使用RegisterReadOnly 来保护它免受public 调用者的影响来缓解,但所有者对象仍然可以修改它。
  • 仅将VideoRatio 用作轻量级的getter,用于即时计算值。但是随后很难让其他元素绑定到它,因为它们应该监听VideoDimensionProperty 通知程序,而是从VideoRatio 获取值。从外部调用者那里知道的太多了。
  • 根本不要使用VideoRatio,而是让调用者通过绑定Converter 来监听VideoDimension,这将计算比率。这也是从外部调用者那里知道的太多,而且这绝对是不可扩展的。

【问题讨论】:

    标签: wpf data-binding dependency-properties


    【解决方案1】:

    “如果没有人听,就白白计算”

    源对象不应该关心是否有人“收听”它。无论如何,它都应该更新其状态,因此这不是问题。

    “但是之后就很难让其他元素绑定到它了……”

    您可以在您的类中实现INotifyPropertyChanged,并在您想要通知订阅者时为VideoDimension 引发PropertyChanged 事件。

    "但是所有者对象仍然可以修改它"

    不仅可以,而且应该。这是它的责任。是使用键显式设置只读依赖属性,还是为只读 CLR 属性引发 PropertyChanged 事件,这只是个人喜好问题。

    您不应强制外部调用者使用转换器来获取值。其他两个选项非常好,应该被视为解决方案而不是解决方法。

    【讨论】:

      【解决方案2】:

      使用属性可以这样做,使用 PropertyChangedCallback 和只读的 VideoRatio 属性:

      public Point VideoDimension
      {
          get { return (Point)GetValue(VideoDimensionProperty); }
          set { SetValue(VideoDimensionProperty, value); }
      }
      
      public static readonly DependencyProperty VideoDimensionProperty =
          DependencyProperty.Register(
              nameof(VideoDimension), 
              typeof(Point), 
              typeof(MainWindow), 
              new PropertyMetadata(new Point(0,0), VideoDimensionChangedCallback));
      
      private static void VideoDimensionChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
          Point p = (Point)e.NewValue;
          d.SetValue(VideoRatioPropertyKey, p.X / p.Y);
      }
      
      public double VideoRatio
      {
          get { return (double)GetValue(VideoRatioProperty); }
      }
      
      public static readonly DependencyProperty VideoRatioProperty = VideoRatioPropertyKey.DependencyProperty;
      
      private static readonly DependencyPropertyKey VideoRatioPropertyKey =
          DependencyProperty.RegisterReadOnly(
              nameof(VideoRatio), 
              typeof(double), 
              typeof(MainWindow), 
              new PropertyMetadata(0));
      

      【讨论】:

      • 谢谢。还应使用SetValue(VideoRatioPropertyKey, ...) 来获得修改条目的授权。
      猜你喜欢
      • 2012-06-06
      • 1970-01-01
      • 2013-04-04
      • 1970-01-01
      • 2011-01-04
      • 2015-01-11
      • 1970-01-01
      • 2016-03-22
      • 2014-12-17
      相关资源
      最近更新 更多