1

TrulyObservableCollectionWPFDataGridのデータソースとしてを使用しています。私のクラスは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場合。これにより、とがnullになるため、その場合、変更されたアイテムを取得できません。データグリッドが追加アイテムで更新されているため、使用できません。変更されたアイテムを取得するためにも、仕事に取り掛かることができないようです。NotifyCollectionChangedEventArgsNotifyCollectionChangedAction.ResetOldItemsNewItems.Add.Replace

4

2 に答える 2

3

これはどう:

のをViewModel含むでは、ViewModel は のイベントをサブスクライブします。ObservableCollectionbretItemCollectionChangedObservableCollection

これにより、コレクション内のアイテムに結合された新しいクラスを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バインドすることを検討する必要があります。ViewView

于 2012-11-15T18:48:46.863 に答える
2

コレクション変更イベントをこのように使用することは適切ではありません。これは、コレクションからアイテムを追加/削除するときにのみ発生することを目的としているためです。それがあなたが壁にぶつかった理由です。また、このアプローチでは、リスコフの置換原則を破る危険があります。

INotifyPropertyChangedコレクションクラスにインターフェイスを実装し、アイテムの1つがプロパティ変更イベントを発生させたときにそのイベントを発生させる方がおそらく良いでしょう。

于 2012-11-15T16:13:00.200 に答える