1

TrulyObservableCollection在 WPF DataGrid 中使用 a 作为数据源。我的班级PropertyChange正确地实现了事件(属性更改时我会收到通知)。该CollectionChanged事件也被触发。但是,我的问题在于PropertyChanged事件与CollectionChanged事件之间的联系。我可以在PropertyChanged事件中看到哪个项目被更改(在这种情况下是sender对象),但是我似乎无法找到一种方法来查看在CollectionChanged事件中更改了哪个项目。sender对象是整个集合。查看活动中哪个项目发生变化的最佳方式是什么CollectionChanged?相关的代码片段如下。感谢您的帮助,如果需要澄清,请告诉我。

设置集合的代码:

    private void populateBret()
    {
        bretList = new TrulyObservableCollection<BestServiceLibrary.bretItem>(BestClass.BestService.getBretList().ToList());
        bretList.CollectionChanged += bretList_CollectionChanged;
        dgBretList.ItemsSource = bretList;
        dgBretList.Items.Refresh();
    }

    void bretList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        //Do stuff here with the specific item that has changed
    }

集合中使用的类:

public class bretItem : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int _blID;
    public string _blGroup;

    [DataMember]
    public int blID
    {
        get { return _blID; }
        set
        {
            _blID = value;
            OnPropertyChanged("blID");
        }
    }

    [DataMember]
    public string blGroup
    {
        get { return _blGroup; }
        set
        {
            _blGroup = value;
            OnPropertyChanged("blGroup");
        }
    }

    protected void OnPropertyChanged (String name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

TrulyObservableCollection 类

public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
    {
        public TrulyObservableCollection()
            : base()
        {
            CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
        }
        public TrulyObservableCollection(List<T> list)
            : base(list)
        {
            foreach (var item in list)
            {
                item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
            }
            CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
        }

        void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Object item in e.NewItems)
                {
                    (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                }
            }
            if (e.OldItems != null)
            {
                foreach (Object item in e.OldItems)
                {
                    (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                }
            }
        }

        void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            OnCollectionChanged(a);
        }
    }

编辑:

如果设置item_PropertyChanged为. 这导致and为空,因此在这种情况下我无法获得更改的项目。我不能使用,因为 Datagrid 已使用附加项目进行了更新。我似乎也无法开始工作以获取更改的项目。NotifyCollectionChangedEventArgsNotifyCollectionChangedAction.ResetOldItemsNewItems.Add.Replace

4

2 回答 2

3

这个怎么样:

ViewModel包含 的ObservableCollectionbretItem,ViewModel 订阅了 的CollectionChanged事件ObservableCollection

TrulyObservableCollection这将防止需要派生的新类ObservableCollection与其集合中的项目耦合。

在您的处理程序中,您可以像现在一样ViewModel添加和删除事件处理程序。PropertyChanged由于您现在ViewModel被告知集合中对象的更改,因此您可以采取适当的措施。

public class BretListViewModel
{

    private void populateBret()
    {
        bretList = new ObservableCollection<BestServiceLibrary.bretItem>(BestClass.BestService.getBretList().ToList());
        bretList.CollectionChanged += bretList_CollectionChanged;              
    }

    void bretList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
         if (e.NewItems != null)
        {
            foreach (Object item in e.NewItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
        if (e.OldItems != null)
        {
            foreach (Object item in e.OldItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
    }


    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var bret = sender as bretItem;

        //Update the database now!

        //One note:
        //The ObservableCollection raises its change event as each item changes.
        //You should consider a method of batching the changes (probably using an ICommand)
    }

}

注意事项:

顺便说一句,您似乎正在打破MVVM基于此代码段的模式:

dgBretList.ItemsSource = bretList;
dgBretList.Items.Refresh();

您可能应该考虑加载您的ViewModel并将您绑定View到它,而不是在View.

于 2012-11-15T18:48:46.863 回答
2

以这种方式使用集合更改事件是不合适的,因为它仅在从集合中添加/删除项目时被触发。这就是你撞墙的原因。你也有可能用这种方法打破 Liskov 替换原则。

在您的集合类上实现INotifyPropertyChanged接口并在您的项目之一触发其属性更改事件时触发该事件可能会更好。

于 2012-11-15T16:13:00.200 回答