5

我有一个自定义控件,它DependencyProperty的类型ObservableCollection绑定到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));
4

2 回答 2

18

除了 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()
{
    ...
}
于 2013-02-22T11:56:43.143 回答
6

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

在这个例子中,方法 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");
    }
}
于 2013-02-22T03:55:35.037 回答