【问题标题】:Set bindings for custom DependencyObjects为自定义 DependencyObjects 设置绑定
【发布时间】:2017-04-19 23:37:02
【问题描述】:

这是一个问题的延续:Trying to setup a custom DependencyObject. Clearly missing something。编辑原始问题是不切实际的;变化太大。所以我开始一个新的问题。

我正在尝试在我的 UWP 应用中设置自定义 DependencyObject 之间的绑定。相关代码如下。我看到对 ActualWidthPropertyChanged 的​​调用,但它们没有触发对 WidthPropertyChanged 的​​任何调用。我错过了什么?

class WindowsElement: DependencyObject
{
    public WindowsElement()
    {
    }
    public double Width
    {
        get
        {
          return (double)GetValue(WidthProperty);
        }
        set
        {
          SetValue(WidthProperty, value);
        }
    }

    private static void WidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
      WindowsElement element = (WindowsElement)o;
      double width = (double)e.NewValue;
      CommonDebug.LogLine("WPC", element, o, width);
      element.Width = width;
    }

   private static void ActualWidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
     {
       WindowsElement element = (WindowsElement)o;
       double width = (double)e.NewValue;
       CommonDebug.LogLine("AWPC", o, e, width, element.Width);
       element.ActualWidth = width;
     }
     public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
        "Width",
        typeof(double),
        typeof(WindowsElement),
       new PropertyMetadata((double)0, WidthPropertyChanged));

      public double ActualWidth {
        get
          {
            return (double)GetValue(ActualWidthProperty);
          }
        set
            {
              SetValue(ActualWidthProperty, value);
            }
        }


    public static readonly DependencyProperty ActualWidthProperty =  
      DependencyProperty.Register(
        "ActualWidth",
        typeof(double),
        typeof(WindowsElement),
        new PropertyMetadata((double)0, ActualWidthPropertyChanged));


    public static void MessWithBindings()
    {
        WindowsElement we1 = new WindowsElement();
        WindowsElement we2 = new WindowsElement();
        var b = new Binding
          {
            Source = we2,
            Path = new PropertyPath("ActualWidth")
          };

        BindingOperations.SetBinding(we1, WindowsElement.WidthProperty, b);
        we2.ActualWidth = 13;
        CommonDebug.LogLine(we1, we1.Width,  we1.ActualWidth, we2, we2.Width, we2.ActualWidth);
    }
}

【问题讨论】:

    标签: binding uwp dependencyobject


    【解决方案1】:

    我看到对 ActualWidthPropertyChanged 的​​调用,但它们没有触发对 WidthPropertyChanged 的​​任何调用。我错过了什么?

    要解决这个问题,您需要在源对象上实现 INotifyPropertyChanged 接口,以便源可以报告更改。

    请看以下代码:

    class WindowsElement : DependencyObject, INotifyPropertyChanged
    {
        public WindowsElement()
        {
        }
    
        public double Width
        {
            get
            {
                return (double)GetValue(WidthProperty);
            }
            set
            {
                SetValue(WidthProperty, value);
            }
        }
    
        private static void WidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            WindowsElement element = (WindowsElement)o;
            double width = (double)e.NewValue;
            CommonDebug.LogLine("WPC", element, o, width);
            //element.Width = width;
            element.RaisedPropertyChanged("Width");
        }
    
        private static void ActualWidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            WindowsElement element = (WindowsElement)o;
            double width = (double)e.NewValue;
            CommonDebug.LogLine("AWPC", o, e, width, element.Width);
            //element.ActualWidth = width;
            element.RaisedPropertyChanged("ActualWidth");
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void RaisedPropertyChanged(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }
    
        public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
            "Width",
            typeof(double),
            typeof(WindowsElement),
            new PropertyMetadata((double)0, WidthPropertyChanged));
    
        public double ActualWidth
        {
            get
            {
                return (double)GetValue(ActualWidthProperty);
            }
            set
            {
                SetValue(ActualWidthProperty, value);
            }
        }
    
        public static readonly DependencyProperty ActualWidthProperty = DependencyProperty.Register(
            "ActualWidth",
            typeof(double),
            typeof(WindowsElement),
            new PropertyMetadata((double)0, ActualWidthPropertyChanged));
    
        public static void MessWithBindings()
        {
            WindowsElement we1 = new WindowsElement();
            WindowsElement we2 = new WindowsElement();
            var b = new Binding
            {
                Source = we2,
                Path = new PropertyPath("ActualWidth")
            };
    
            BindingOperations.SetBinding(we1, WindowsElement.WidthProperty, b);
            we2.ActualWidth = 13;
            CommonDebug.LogLine(we1, we1.Width, we1.ActualWidth, we2, we2.Width, we2.ActualWidth);
        }
    }
    

    【讨论】:

    • 参见Custom dependency properties实现包装器部分:除特殊情况外,您的包装器实现应仅执行 GetValue 和 SetValue 操作。否则,通过 XAML 设置属性与通过代码设置属性时,您将获得不同的行为。为了提高效率,XAML 解析器在设置依赖属性时会绕过包装器;并通过 SetValue 与后备存储通信
    • 因此(如果有必要)引发 PropertyChanged 事件应该在 PropertyChangedCallback 中完成。
    • @Clemens 你是对的。在包装器中调用 PropertyChanged 不是一个好习惯。我已经更新了我的回复。这个问题应该是个特例。它需要实现 INotifyPropertyChanged 接口。
    【解决方案2】:

    不知道为什么在 UWP 中,从一个依赖属性到另一个的单向绑定不会自动更新目标属性(就像在 WPF 中那样)。

    但是,您可以简单地反转 Binding 的方向并使其成为双向:

    var b = new Binding
    {
        Source = we1,
        Path = new PropertyPath("Width"),
        Mode = BindingMode.TwoWay
    };
    
    BindingOperations.SetBinding(we2, WindowsElement.ActualWidthProperty, b);
    we2.ActualWidth = 13;
    

    【讨论】:

    • 仍然没有回调 WidthPropertyChanged 。 . .
    • 它对我有用。并且您不得在 PropertyChangedCallbacks 中调用 element.Width = width;element.ActualWidth = width;。该属性已更改,无需再次设置。
    猜你喜欢
    • 2014-07-04
    • 2011-07-26
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    相关资源
    最近更新 更多