Skip to main content
 首页 » 编程设计

c#之绑定(bind)到用户控件中的 Observable 集合并从中获取通知

2024年01月26日28开发

我一直在这里查看其他一些看起来与我的问题相似的问题,但没有一个有答案。所以,这里...

我正在使用 WPF 和 MVVM 模式开发 C# 应用程序。我有一个包含依赖属性的 UserControl(称为 GroupTree):

  public static DependencyProperty ChartGroupsProperty = DependencyProperty.Register("ChartGroups", typeof(ChartGroupCollection), typeof(GroupTree), 
                                                      new FrameworkPropertyMetadata() { DefaultValue=new ChartGroupCollection(),  PropertyChangedCallback = OnChartGroupsChanged, BindsTwoWayByDefault = true }); 
    public ChartGroupCollection ChartGroups 
    { 
        get { return (ChartGroupCollection)GetValue(ChartGroupsProperty); } 
        set 
        { 
            SetValue(ChartGroupsProperty, value); 
        } 
    } 
 
    private static void OnChartGroupsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
        if (e.OldValue != e.NewValue) 
        { 
            // Nothing at the moment 
        } 
    } 

它的 ChartGroupCollection 类型定义如下:

public class ChartGroupCollection : ObservableCollection<ChartGroup> 
{ 
} 

ChartGroup 包含使用 INotifyProperty 的属性,我已经独立验证了应该为主集合触发的所有更改事件都正确执行。

使用控件的MainWindow.Xaml:

   <Controls:GroupTree x:Name="Groups" ChartGroups="{Binding MainGroups}" /> 

我有另一个控件绑定(bind)到 GroupTree 控件中的 ChartGroups 值:

   <Controls:ChartsControl x:Name="Charts1_1" Tree="{Binding ElementName=Groups, Path=ChartGroups}" /> 

我想要发生的是当 GroupTree ChartGroups 值发生变化时,动态地通知 ChartsControl 这些变化并相应地更新。但此刻,没有喜悦。数据在那里,因为如果手动强制刷新 ChartsControl,则会显示更改。我已经尝试绑定(bind)到 MainGroups 属性,希望它能起作用,但那也不起作用。

我可能错过了一些非常明显的东西,但我不确定是什么。有什么想法吗?

罗布

请您参考如下方法:

ObservableCollection 仅监听集合中发生的更改,例如添加或删除的项目,它不会通知其集合中单个项目发生的任何更改。

以下类通过将自身注册到正在添加的项目的 INofityPropertyChanged 事件来增强 ObservableCollection 的功能,并在集合的项目的属性发生变化时引发 ObservableCollection 的 CollectionChanged 事件。

最后调用 ClearItems 会释放所有事件处理程序。

可以从下面的链接中找到更多详细信息。

How to Listen to Property Changes of Items of an ObservableCollection

using System.ComponentModel; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 
using System.Collections; 
 
namespace VJCollections 
{ 
    /// <summary> 
    ///     This class adds the ability to refresh the list when any property of 
    ///     the objects changes in the list which implements the INotifyPropertyChanged.  
    /// </summary> 
    /// <typeparam name="T"> 
    public class ItemsChangeObservableCollection<T> : 
           ObservableCollection<T> where T : INotifyPropertyChanged 
    { 
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
        { 
            if (e.Action == NotifyCollectionChangedAction.Add) 
            { 
                RegisterPropertyChanged(e.NewItems); 
            } 
            else if (e.Action == NotifyCollectionChangedAction.Remove) 
            { 
                UnRegisterPropertyChanged(e.OldItems); 
            } 
            else if (e.Action == NotifyCollectionChangedAction.Replace) 
            { 
                UnRegisterPropertyChanged(e.OldItems); 
                RegisterPropertyChanged(e.NewItems); 
            } 
 
            base.OnCollectionChanged(e); 
        } 
 
        protected override void ClearItems() 
        { 
            UnRegisterPropertyChanged(this); 
            base.ClearItems(); 
        } 
 
        private void RegisterPropertyChanged(IList items) 
        { 
            foreach (INotifyPropertyChanged item in items) 
            { 
                if (item != null) 
                { 
                    item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged); 
                } 
            } 
        } 
 
        private void UnRegisterPropertyChanged(IList items) 
        { 
            foreach (INotifyPropertyChanged item in items) 
            { 
                if (item != null) 
                { 
                    item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged); 
                } 
            } 
        } 
 
        private void item_PropertyChanged(object sender, PropertyChangedEventArgs e) 
        { 
            base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
        } 
    } 
}