wpf 如何在 MVVM 中实现 INotifyCollectionChanged 以重置、添加、删除、移动、替换 NotifyCollectionChangedAction

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18202333/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:25:34  来源:igfitidea点击:

How to implement INotifyCollectionChanged in MVVM for Reset, Add,Remove,Move,Replace of NotifyCollectionChangedAction

wpfsilverlightxamlmvvmobservablecollection

提问by Anindya

My ViewModelBase class is:

我的 ViewModelBase 类是:

public abstract class ViewModelBase:INotifyPropertyChanged, IDisposable, INotifyCollectionChanged
{
    #region Constructor

    protected ViewModelBase()
    {
    }

    #endregion // Constructor
    #region DisplayName

    /// <summary>
    /// Returns the user-friendly name of this object. 
    /// Child classes can set this property to a new value,
    /// or override it to determine the value on-demand.
    /// </summary>
    public virtual string DisplayName { get; protected set; }

    #endregion // DisplayName


    #region Debugging Aides

    /// <summary>
    /// Warns the developer if this object does not have
    /// a public property with the specified name. This 
    /// method does not exist in a Release build.
    /// </summary>
    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    public void VerifyPropertyName(string propertyName)
    {
        // Verify that the property name matches a real,  
        // public, instance property on this object.
        if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        {
            string msg = "Invalid property name: " + propertyName;

            if (this.ThrowOnInvalidPropertyName)
                throw new Exception(msg);
            else
                Debug.Fail(msg);
        }
    }

    /// <summary>
    /// Returns whether an exception is thrown, or if a Debug.Fail() is used
    /// when an invalid property name is passed to the VerifyPropertyName method.
    /// The default value is false, but subclasses used by unit tests might 
    /// override this property's getter to return true.
    /// </summary>
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

    #endregion // Debugging Aides
    #region INotifyPropertyChanged Members
    /// <summary>
    /// raised when property of this object has some new value  
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    #endregion

    #region IDisposable Members

    public void Dispose()
    {
        this.OnDispose();
    }

    /// <summary>
    /// child classes can override this method to perform cleanup logic,like removing eventhandlers and disposing objects
    /// Anindya
    /// </summary>
    protected virtual void OnDispose()
    {
        //no implementation has been done here 
        //intentionhally I have done so 
        //so that this method will be only used for the overriding of this method
        //by default nothing I have kept in this method
    }

    #endregion

    #region INotifyCollectionChanged Members
    /// <summary>
    /// Occurs when an item is added, removed, changed, moved, or the entire list is refreshed.
    /// </summary>
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    protected virtual void OnCollectionChanged(CollectionChangeEventArgs ccevent)
    {
        //NotifyCollectionChangedEventHandler handler = this.CollectionChanged;
        //if (handler != null)
        //{
        //    var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction 
        //}
    }

    #endregion

}

and my WorkSpaceViewModel is inheriting from ViewModelBase as followes:

我的 WorkSpaceViewModel 继承自 ViewModelBase 如下:

public abstract class WorkspaceViewModel:ViewModelBase
{
    #region Fields

    RelayCommand _closeCommand;


    #endregion // Fields

    #region Constructor

    protected WorkspaceViewModel()
    {
    }

    #endregion // Constructor

    #region CloseCommand

    /// <summary>
    /// Returns the command that, when invoked, attempts 
    /// to remove this workspace from the user interface. 
    /// </summary>
    public ICommand CloseCommand
    {
        get
        {
            if (_closeCommand == null)
                _closeCommand = new RelayCommand(param => this.OnRequestClose());

            return _closeCommand;
        }
    }       

    private void CanDoSomeImportantMethod()
    {
    }
    #endregion // CloseCommand

    #region RequestClose [event]

    /// <summary>
    /// Raised when this workspace should be removed from the UI.
    /// </summary>
    public event EventHandler RequestClose;

    void OnRequestClose()
    {
        EventHandler handler = this.RequestClose;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

    #endregion // RequestClose [event]
}

My ViewModel is inheriting from WorkSpaceViewModel as followes:

我的 ViewModel 继承自 WorkSpaceViewModel 如下:

public class MainWindowViewModel:WorkspaceViewModel,INotifyCollectionChanged
{
    //
    RelayCommand _loadCommand;
    MatchBLL matchBLL = new MatchBLL();
    EfesBetServiceReference.EfesBetClient proxy = new EfesBetClient();
    public MainWindowViewModel()
    {
        _matchObsCollection = new ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC>();
        Load();

        _matchObsCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(_matchObsCollection_CollectionChanged);
    }

    /// <summary>
    /// This will get called when the collection is changed(for reference see http://stackoverflow.com/questions/1427471/observablecollection-not-noticing-when-item-in-it-changes-even-with-inotifyprop)
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void _matchObsCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {

    }

    protected override void OnPropertyChanged(string propertyName)
    {
        base.OnPropertyChanged(propertyName);
    }
    public ICommand LoadCommand
    {
        get
        {
            if (_loadCommand == null)
            {
                _loadCommand = new RelayCommand(
                    param => this.Load(),
                    param => this.CanLoad
                    );
            }
            return _loadCommand; 
        }
    }

    List<EfesBet.DataContract.GetMatchDetailsDC> matchList;
    ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> _matchObsCollection;

    public ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> MatchObsCollection
    {
        get { return _matchObsCollection; }
        set
        {
            _matchObsCollection = value;
            OnPropertyChanged("MatchObsCollection");
        }
    }

    public void Load()
    {
        matchList = new List<GetMatchDetailsDC>();
        matchList = proxy.GetMatch().ToList();
        foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList)
        {
            _matchObsCollection.Add(match);
        }
        //ajebaje code
        PopulateSahibiKonuk();
    }

    bool CanLoad
    {
        get { return true; }
    }


    #region INotifyCollectionChanged Members

    public event NotifyCollectionChangedEventHandler CollectionChanged;       

    #endregion

Now I am having a DataGridin UI and I want OnCollectionChanged of my ObservableCollection. How NotifyCollectionChangedAction like add, move, remove, replace, reset my viewmodel should fire. But I do not know how to implement or what I have to do in my base classes or in my viewmodel. Please provide me some useful code or urls or suggestion regarding this.

现在我有一个DataGridin UI 并且我想要 OnCollectionChanged 我的ObservableCollection. NotifyCollectionChangedAction 像添加、移动、删除、替换、重置我的视图模型应该如何触发。但是我不知道如何在我的基类或视图模型中实现或我必须做什么。请向我提供一些有用的代码或网址或有关此的建议。

Thanking you in advance.

提前谢谢你。

回答by Sheridan

Typically, a view model would notimplement the INotifyCollectionChangedinterface... that is for collection classes to implement. I have a massive WPF project and I haven't needed to implement that interface once.

通常,视图模型不会实现INotifyCollectionChanged接口......这是集合类要实现的。我有一个庞大的 WPF 项目,我不需要实现一次该接口。

I generally use custom collection classes that extend ObservableCollection<T>and these collections already implement the INotifyCollectionChangedinterface. Therefore, when I need to display collections, I just add properties for these collections in my view model classes. If I then need to monitor changes in the collection, I would add a handler for the CollectionChangedevent.

我通常使用扩展的自定义集合类,ObservableCollection<T>这些集合已经实现了INotifyCollectionChanged接口。因此,当我需要显示集合时,我只需在我的视图模型类中为这些集合添加属性。如果然后我需要监视集合中的更改,我将为该CollectionChanged事件添加一个处理程序。

This is not something that can be built into the base view model unlessyou are certain that everyview model will have a collection of a particular type. Even then, what would you do when you need more than one collection in a view model? You'd have to add a collection property and extra handlers, so why don't you just do that whenever you need to?

这不是可以内置到基本视图模型中的东西,除非您确定每个视图模型都有一个特定类型的集合。即便如此,当您在一个视图模型中需要多个集合时,您会怎么做?您必须添加一个集合属性和额外的处理程序,那么为什么不在需要时才这样做呢?