集合依赖项属性



我有一个自定义控件,该控件具有绑定到observableCollection:的ObservableCollection类型的DependencyProperty

<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));

除了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()
{
    ...
}

下面是一个可能有所帮助的工作示例。

在本例中,当单击Add按钮时,会立即调用方法OnChanged。"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");
    }
}

最新更新