撤消WPF M-V-VM内部,它是如何适应的?

时间:2009-05-22 20:12:06

标签: c# wpf mvvm undo

在我以前的项目中,我已经在c ++中实现了undo系统,我知道它是如何工作的。我也知道Command模式。

我将实现一个C#/ WPF桌面应用程序,并希望将我的设计基于M-V-VM模式。

申请将:

  • 是一个相对较小的项目(2-3周估计工作为1 dev)
  • 有一个带持久性的简单数据模型(linq to XML)
  • 支持撤消/重做

我想知道是否有人在遵循M-V-VM模式时有实施撤销系统的经验。它怎么会适合它?它如何从INotifyPropertyChanged和INotifyCollectionChanged通知中受益,因此在实现模型(业务对象)时需要最少的工作。

我认为撤销系统会某种程度集成到ViewModel层中,因为它是一种UI状态。

有什么想法吗?

3 个答案:

答案 0 :(得分:13)

这是我用于项目的解决方案。证明该解决方案运行良好。

系统正在使用撤消事件对象,其中每个撤消事件都知道如何撤消和重做自己。

interface IUndoEvent
{
    void Undo();
    void Redo();
}

我能够通过仅实现2个撤消事件来构建系统:一个用于属性更改;一个用于收集更改。

这个想法是这些事件通过直接修改模型来实现撤销/重做。

class PropertyChangeUndoEvent : IUndoEvent
{
    private ModelBase _target;
    private string _propertyName;
    private object _oldValue;
    private object _newValue;

    public PropertyChangeUndoEvent(ModelBase target, string propertyName, object oldValue, object newValue)
    {
        _target = target;
        _propertyName = propertyName;
        _oldValue = oldValue;
        _newValue = newValue;
    }

    public void Undo()
    {
        SetValue(_oldValue);
    }

    public void Redo()
    {
        SetValue(_newValue);
    }

    private void SetValue(object value)
    {
        // Set Value on the _target using reflection (_propertyName)
    }
}

ViewModel通过调用ViewModelBase函数来处理创建撤消事件:

class MyViewModel : ViewModelBase
{
    public string Name
    {
        get { return _model.Name; }

        // The SetValue will create a undo event, and push it to the UndoManager
        set { SetValue(_model, "Name", value); }
    }
}

最后,还有一个UndoManager(项目单例),用于存储撤消堆栈和重做堆栈。

答案 1 :(得分:4)

您可能会发现Monitored Undo Framework非常有用。 http://muf.codeplex.com/。它不使用“自上而下”命令模式,而是在发生更改时监视更改,并允许您将委托放在撤消堆栈上以反转更改。

我将其创建为使用MVVM构建的WPF应用程序的一部分。大多数撤消操作都源自我们的底层域模型,但我们也迷上了ViewModel的某些区域以允许撤消/重做。

您可以在http://muf.codeplex.com/找到有关codeplex网站的更多信息和文档。

答案 2 :(得分:2)

我想你将Command模式与Memento结合在一起?

  

我认为撤销系统会某种程度集成到ViewModel层中,因为它是一种UI状态。

?通常,undo / redo作用于业务对象,UI反映业务层。

假设我们有一个带有“描述”字符串的产品类。 ProductVM公开了一个引发PropertyChanged的字符串属性。 在修改时,纪念品保留旧的模型实例。如果撤消,请使用ProductVM.Description =(memento as Product)恢复纪念品。描述:模型将更新,UI也会更新。

注意:避免(memento as Product),仅针对样本;)