【问题标题】:collection dependency properties集合依赖属性
【发布时间】:2013-02-07 13:00:15
【问题描述】:

我有一个自定义控件,它的 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));

【问题讨论】:

  • 你会发布你的依赖属性的定义吗?里面可能有什么东西……
  • 您的“MyControl”是否在监控 PropertyChanged 或 CollectionChanged,您是否在监控可观察集合中的对象的 PropertyChanged?
  • 是的,CollectionChanged 的​​定义和处理程序中存在回调,永远不会被触发。由于我们正在讨论添加,因此我看不出在哪些地方监听项目的 PropertyChanged 是相关的。
  • 你能发布 OnChanged 方法吗?顺便说一句,为您的 dp 提供默认值不是一个好主意。默认情况下,控件的每个实例都将引用相同的集合实例。
  • 啊..关于默认值的好点。我可以发布处理程序,但它有点无关紧要,因为它永远不会被调用。

标签: c# wpf data-binding observablecollection dependency-properties


【解决方案1】:

除了grantz 回答的内容之外,我建议使用IEnumerable&lt;string&gt; 类型声明属性,并在运行时检查集合对象是否实现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()
{
    ...
}

【讨论】:

    【解决方案2】:

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

    在这个例子中,方法 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");
        }
    }
    

    【讨论】:

    • 你不应该在注册依赖属性时使用代码new PropertyMetadata(new ObservableCollection&lt;string&gt;()。解释见here
    • 这不会导致底层集合被 MyControl 的所有实例共享的问题吗?根据此链接,您必须在 MyControl 的构造函数中手动设置一个新集合以避免这种情况。 msdn.microsoft.com/en-us/library/vstudio/…
    猜你喜欢
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多