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

时间:2013-08-13 06:43:53

标签: wpf silverlight xaml mvvm observablecollection

我的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

}

我的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]
}

我的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

现在我在UI中有一个DataGrid,我想要ObservableCollection的OnCollectionChanged。 NotifyCollectionChangedAction如何添加,移动,删除,替换,重置我的viewmodel应该触发。但我不知道如何在我的基类或我的viewmodel中实现或者我必须做什么。请提供一些有用的代码或网址或建议。

提前感谢你。

1 个答案:

答案 0 :(得分:5)

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

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

除非确定每个视图模型都具有特定类型的集合,否则这不能构建到基本视图模型中。即便如此,当您在视图模型中需要多个集合时,您会做什么?你必须添加一个集合属性和额外的处理程序,那你为什么不在你需要的时候那样做呢?