2

我有了ObservableCollection類型的DependencyProperty綁定到一個observableCollection自定義控制:集合依賴屬性

<MyControl MyCollectionProperty = {Binding MyObservableCollection} ... 

問題是增加了MyObservableCollection不更新MyCollectionProperty

我需要完全取代MyObservableCollection才能使其工作,例如,

MyObservableCollection = null; 
MyObservableCollection = new ObservableCollection(){...} 

有沒有更好的方法來處理這個問題?

編輯:

public ObservableCollection<string> Columns 
    { 
     get { return (ObservableCollection<string>)GetValue(ColumnsProperty); } 
     set { SetValue(ColumnsProperty, value); } 
    } 

    public static readonly DependencyProperty ColumnsProperty = 
     DependencyProperty.Register("Columns", typeof(ObservableCollection<string>), typeof(MyControl), 
            new PropertyMetadata(new ObservableCollection<string>(), OnChanged)); 
+0

你會發布你的依賴屬性的定義嗎?可能是在那裏的東西... – 2013-02-22 01:13:02

+0

是你的「MyControl」監視PropertyChanged或CollectionChanged,並且你監視你的可觀察集合中的對象的PropertyChanged? – grantnz 2013-02-22 01:15:04

+0

是的,在定義和處理程序中有一個回調CollectionChanged永遠不會被解僱。由於我們正在討論添加,我沒有看到在項目上監聽PropertyChanged的位置是相關的。 – user1604008 2013-02-22 01:34:34

回答

5

下面是一個工作示例,可以幫助。

在這個例子中,OnChanged方法立即被調用,當單擊Add按鈕時,「Changed」被寫入控制檯。

控制

public class MyControl : Control 
{ 

    public ObservableCollection<string> ExtraColumns 
    { 
     get { return (ObservableCollection<string>)GetValue(ExtraColumnsProperty); } 
     set { SetValue(ExtraColumnsProperty, value); } 
    } 

    public static readonly DependencyProperty ExtraColumnsProperty = 
     DependencyProperty.Register("ExtraColumns", typeof(ObservableCollection<string>), typeof(MyControl), 
            new PropertyMetadata(new ObservableCollection<string>(), OnChanged)); 

    static void OnChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     (sender as MyControl).OnChanged(); 

    } 

    void OnChanged() 
    { 
     if (ExtraColumns != null) 
      ExtraColumns.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ExtraColumns_CollectionChanged); 
    } 

    void ExtraColumns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     Console.WriteLine("Changed");  
    } 
} 

的窗口

<Window x:Class="WpfApplication18.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfApplication18" 
    Title="MainWindow" Height="350" Width="525"> 
    <StackPanel> 
    <local:MyControl ExtraColumns="{Binding Extras}"/> 
    <Button Click="Button_Click">Add</Button> 
    </StackPanel> 
</Window> 

窗口代碼隱藏

public partial class MainWindow : Window 
{ 
    private ObservableCollection<string> _extras = new ObservableCollection<string>(); 
    public ObservableCollection<string> Extras 
    { 
     get { return _extras; } 
     set 
     { 
      if (value != _extras) 
      { 
       _extras = value; 
      } 
     } 
    } 


    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = this; 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     Extras.Add("Additional"); 
    } 
} 
+4

你不應該使用代碼'new PropertyMetadata(new ObservableCollection ()'在註冊依賴屬性。請參閱[這裏](https://msdn.microsoft.com/en-us/library/vstudio/aa970563%28v=vs.100%29.aspx)的解釋 – ghord 2015-06-26 15:24:19

11

除了什麼grantz已經回答了,我建議用IEnumerable<string>類型申報財產並在運行時檢查集合對象是否實現了INotifyCollectionChanged接口。這提供了更大的靈活性,可以將哪個具體收集實現用作屬性值。用戶可能決定擁有自己的可觀察集合的專門實現。

還要注意的是,在ColumnsPropertyChanged回調中,CollectionChanged事件處理程序附加到新集合,但也從舊集合中刪除。

public static readonly DependencyProperty ColumnsProperty = 
    DependencyProperty.Register(
     "Columns", typeof(IEnumerable<string>), typeof(MyControl), 
     new PropertyMetadata(null, ColumnsPropertyChanged)); 

public IEnumerable<string> Columns 
{ 
    get { return (IEnumerable<string>)GetValue(ColumnsProperty); } 
    set { SetValue(ColumnsProperty, value); } 
} 

private static void ColumnsPropertyChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    var control= (MyControl)obj; 
    var oldCollection = e.OldValue as INotifyCollectionChanged; 
    var newCollection = e.NewValue as INotifyCollectionChanged; 

    if (oldCollection != null) 
    { 
     oldCollection.CollectionChanged -= control.ColumnsCollectionChanged; 
    } 

    if (newCollection != null) 
    { 
     newCollection.CollectionChanged += control.ColumnsCollectionChanged; 
    } 

    control.UpdateColumns(); 
} 

private void ColumnsCollectionChanged(
    object sender, NotifyCollectionChangedEventArgs e) 
{ 
    // optionally take e.Action into account 
    UpdateColumns(); 
} 

private void UpdateColumns() 
{ 
    ... 
}