简体   繁体   English

绑定到用户控件中的Observable Collection并从中获取通知

[英]binding to an Observable Collection in a usercontrol and getting notifications from it

I've been looking through some other questions here that look similar to my issue, but none have the answer. 我在这里浏览了一些其他问题,这些问题看起来与我的问题相似,但没有答案。 So, here goes... 所以,这里...

I'm developing a C# application using WPF and the MVVM pattern. 我正在使用WPF和MVVM模式开发C#应用程序。 I have a UserControl (called GroupTree) that contains a dependency property: 我有一个包含依赖项属性的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
        }
    }

Its of type ChartGroupCollection which is defined so: 其类型为ChartGroupCollection,其定义如下:

public class ChartGroupCollection : ObservableCollection<ChartGroup>
{
}

The ChartGroup contains properties that use INotifyProperty and I've independently verified that all the change events that should fire for the main collection do so properly. ChartGroup包含使用INotifyProperty的属性,并且我已经独立验证了应为主集合触发的所有更改事件都可以正确执行。

The MainWindow.Xaml that uses the control: 使用控件的MainWindow.Xaml:

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

I have another control that binds to the ChartGroups Value in the GroupTree Control: 我还有另一个控件绑定到GroupTree控件中的ChartGroups值:

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

What I want to happen is when the GroupTree ChartGroups Value changes, for this to notify the ChartsControl dynamically of those changes and update accordingly. 我想发生的事情是当GroupTree ChartGroups值更改时,此操作将这些更改动态通知ChartsControl并进行相应更新。 But at the moment, no joy. 但是此刻,没有喜悦。 The data is there, because if force a refresh of the ChartsControl manually the changes show. 数据在那里,因为如果强制手动刷新ChartsControl,则会显示更改。 I've tried binding to the MainGroups property hoping that would work, but that doesn't either. 我试图绑定到MainGroups属性,希望能起作用,但是那也不行。

I've probably missed something blindingly obvious, but I'm not sure what. 我可能错过了令人眼花obvious乱的明显事物,但我不确定是什么。 Any ideas? 有任何想法吗?

Rob

ObservableCollection only listens to the changes occur in the collection like items being added or removed and it does not notify about any changes happened in the individual items of its collection. ObservableCollection仅侦听集合中发生的更改(例如添加或删除的项目),并且不会通知其集合中单个项目发生的任何更改。

The following class enhances the funtionality of ObservableCollection by registering itself to the INofityPropertyChanged event of the items being added and raises the CollectionChanged event of the ObservableCollection when a property of an item of the collection changes. 下列类通过将自身注册到要添加的项的INofityPropertyChanged事件来增强ObservableCollection的功能,并在集合的项的属性发生更改时引发ObservableCollection的CollectionChanged事件。

Calling the ClearItems at the end releases all event handlers. 最后调用ClearItems将释放所有事件处理程序。

More details can be found from the below link. 可以从下面的链接中找到更多详细信息。

How to Listen to Property Changes of Items of an ObservableCollection 如何收听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));
        }
    }
}

Unfortunately, the PropertyChanged callback is only invoked when PropertyChanged is raised against the bound property (thus causing the binding to evalutate). 不幸的是,仅当针对绑定的属性引发PropertyChanged时才调用PropertyChanged回调(因此使绑定无效)。

You need the CollectionChanged event provided by INotifyCollectionChanged . 您需要INotifyCollectionChanged提供的CollectionChanged事件。 So you have two options: 因此,您有两种选择:

  1. Register for that event in OnChartGroupsChanged and handle it yourself (make sure to de-register for the old one, so you don't leak the handle!) OnChartGroupsChanged注册该事件并自己处理(请确保取消注册旧事件,以免泄漏该句柄!)

  2. Derive from something like ItemsControl and use its Items property. 从类似ItemsControl派生并使用其Items属性。 This removes your dependency property and allows ItemsControl to handle all the collection changed stuff for you. 这将删除您的依赖项属性,并允许ItemsControl为您处理所有更改了集合的东西。

If its feasable, I would go with the second one. 如果可行,我会选择第二个。 If not, utilizing the CollectionChanged event shouldn't be too bad. 如果不是,利用CollectionChanged事件应该不会糟糕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM