2016-12-05 114 views
0

这里是一个问题的延续:Trying to setup a custom DependencyObject. Clearly missing something。编辑原始问题并不实际;变化太大了。所以我开始一个新鲜的问题。设置自定义DependencyObjects的绑定

我想在我的UWP应用程序中的自定义DependencyObjects之间设置绑定。相关代码如下。我看到对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); 
    } 
} 

回答

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); 
    } 
} 
+0

参见[**自定义依赖属性**](https://msdn.microsoft.com/en -us/windows/uwp/xaml-platform/custom-dependency-properties),部分**实现包装器**:*除了特殊情况外,包装器实现只应执行GetValue和SetValue操作。否则,当通过XAML设置属性时,与通过代码设置属性时,会得到不同的行为。为了提高效率,XAML解析器在设置依赖项属性时绕过包装器;并通过SetValue *与后台商店交谈。 – Clemens

+0

因此(如有必要)引发PropertyChanged事件应该在PropertyChangedCallback中完成。 – Clemens

+1

@Clemens你是对的。在包装器中调用PropertyChanged不是一个好习惯。我已更新我的回覆。这个问题应该是一个特例。它需要实现INotifyPropertyChanged接口。 –

0

不知道为什么在UWP单向从一个依赖属性绑定到另一个(因为它在WPF做)不会自动更新目标属性。

但是,你可以简单地恢复绑定的方向,使其双向的:

var b = new Binding 
{ 
    Source = we1, 
    Path = new PropertyPath("Width"), 
    Mode = BindingMode.TwoWay 
}; 

BindingOperations.SetBinding(we2, WindowsElement.ActualWidthProperty, b); 
we2.ActualWidth = 13; 
+0

仍然没有回调到WidthPropertyChanged。 。 。 –

+0

它适合我。而且你不能在PropertyChangedCallbacks中调用'element.Width = width;'和'element.ActualWidth = width;'。该物业已更改,无需再次设置。 – Clemens