2017-06-01 110 views
0

我創建了一個自定義控件「CustomAutoCompleteBox」(它繼承AutoCompleteBox)與一個依賴項屬性「CurrentItem」。依賴屬性未設置ViewModel

public static readonly DependencyProperty CurrentItemProperty = 
     DependencyProperty.Register("CurrentItem", typeof(CityEntity), typeof(CustomAutoCompleteBox), 
      new FrameworkPropertyMetadata(
       null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 

    public CityEntity CurrentItem 
    { 
     get { return (CityEntity)GetValue(CurrentItemProperty); } 
     set { SetValue(CurrentItemProperty, value); } 
    } 

此自定義控件還有一個屬性「InternalCurrentItem」。

public CityEntity InternalCurrentItem 
    { 
     get { return _internalCurrentCity; } 

     set 
     { 
      if (_internalCurrentCity == value) return; 

      _internalCurrentCity = value; 
      OnPropertyChanged(); 

      CurrentItem = value; 
     } 
    } 

DataContext的是確定自己在構造函數中:

public VilleAutoCompleteBox() 
    { 
     DataContext = this; 

     ... 
    } 

並將該樣式設置的ItemsSource和的SelectedItem這樣的:

<Style TargetType="{x:Type infrastructure_controls:CustomAutoCompleteBox}" BasedOn="{StaticResource AutoCompleteBoxFormStyle}"> 
    <Setter Property="ItemsSource" Value="{Binding InternalItems, Mode=OneWay}" /> 
    <Setter Property="SelectedItem" Value="{Binding InternalCurrentItem, Mode=TwoWay}" /> 
    ... 
</Style> 

總之,ItemsSource時是結合內部屬性「InternalItems」和SelectedItem綁定到內部屬性「InternalCurrentItem」。

對於使用它,我宣佈這個CustomAutoCompleteBox這樣的:

<infrastructure_usercontrols:CustomAutoCompleteBox Width="200" CurrentItem="{Binding DataContext.VmCurrentItem, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay}" /> 

我已經綁定依賴屬性「CURRENTITEM」到視圖模型的財產「VmCurrentItem」。

一切工作正常,除了一件事。

當我在控件中鍵入文本時,InternalCurrentItem屬性正確更改。我的ViewModel中的CurrentItem屬性相同。

具體而言,InternalCurrentItem被正確修改(Set)。此屬性設置CurrentItem依賴項屬性,並且此依賴項屬性設置VmCurrentItem。

相反是不正確的。如果我直接更改ViewModel中VmCurrentItem屬性的值,則CurrentItem屬性不會更改。我不懂爲什麼。

+1

作爲一個說明,一般情況下不應設置控件的DataContext本身,因爲它可以防止,控制繼承的DataContext的其父控制或窗口。當您查看CurrentItem綁定的複雜性時,您可以輕鬆找到此規則的證明。最好只用RelativeSource編寫控件的「內部」綁定。見例如此答案:https://stackoverflow.com/a/28982771/1136211 – Clemens

+0

我已根據您的建議更新了我的代碼。這是更清潔,但不解決問題。 – StevenPF

回答

1

第一種情況會導致以下事件鏈:

  • SelectedItem改變
  • InternalCurrentItem更新框架由於綁定
  • 您手動更新CurrentItemInternalCurrentItem設定器
  • VmCurrentItem由框架由於結合

在此相反的方向上更新是會發生什麼:

  • VmCurrentItem改變
  • CurrentItem由框架由於更新綁定

...就是這樣。沒有約束力,也沒有任何代碼在CurrentItem更改時更新InternalCurrentItem。所以,你需要做的是註冊一個PropertyChangedCallbackCurrentItemProperty將更新InternalCurrentItem

public static readonly DependencyProperty CurrentItemProperty = 
    DependencyProperty.Register(
     "CurrentItem", 
     typeof(CityEntity), 
     typeof(CustomAutoCompleteBox), 
     new FrameworkPropertyMetadata 
     { 
      BindsTwoWayByDefault = true, 
      PropertyChangedCallback = CurrentItemPropertyChanged 
     }); 

private static void CurrentItemPropertyChanged(
    DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var control = (CustomAutoCompleteBox)d; 
    control.InternalCurrentItem = (CityEntity)e.NewValue; 
} 
+0

非常感謝您提供非常明確而準確的答案。 但我帶來了一些修正。在相反的方向,CurrentItem沒有更新:( 這是我不明白的地方。如果CurrentItem被正確修改,我將不得不手動更改InternalCurrentItem,如你的例子。 – StevenPF

+0

是的,我剛剛注意到了這一點。您的視圖模型是否會引發PropertyChanged?並且您是否在輸出窗口中獲得與綁定有關的消息?另外,如果您使用某種視圖模型注入,請確保您正在修改與您的控件相同的視圖模型實例,勢必 – Grx70

+0

是,視圖模型提高的PropertyChanged: 公共CityEntity VmCurrentItem { 得到{_vmCurrentItem;} 設置 { 如果(_vmCurrentItem ==值)回報; _vmCurrentItem = value; OnPropertyChanged(()=> VmCurrentItem); } } – StevenPF

0

您需要申報財產的方式相同,第一:

public static readonly DependencyProperty InternalCurrentItemProperty = 
     DependencyProperty.Register("InternalCurrentItem", typeof(CityEntity), typeof(CustomAutoCompleteBox), 
      new FrameworkPropertyMetadata(
       null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 

public CityEntity InternalCurrentItem 
{ 
    get{ return (CityEntity)GetValue(InternalCurrentItemProperty); } 

    set 
    { 
     SetValue(InternalCurrentItemProperty, value); 
    } 
} 
+0

小的附加精度:當我直接更改ViewModel中VmCurrentItem屬性的值時,CurrentItem屬性不會更改。 然而事實恰恰相反。當我修改CurrentItem時,VmCurrentItem被改變。 該問題不是來自InternalCurrentItem。 – StevenPF