WPF M-V-VM中的撤销操作,如何适配?

12

在我之前的项目中,我已经在C++中实现了撤销系统,并且我知道它是如何工作的。我也了解命令模式。

我将要实现一个基于M-V-VM模式的C#/WPF桌面应用程序。

该应用程序将会:

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

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

我认为撤销系统应该与ViewModel层集成,因为它是UI状态。

有什么想法吗?

3个回答

14

这是我在项目中使用的解决方案。这个方案被证明完美运行。

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

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(项目单例)存储撤消堆栈和重做堆栈。


4
你可能会发现被监控的撤销框架对你很有用。http://muf.codeplex.com/。它不使用“自上而下”的命令模式,而是在更改发生时监视并允许您将委托放入撤消堆栈中以反转更改。
我将其创建为使用MVVM构建的WPF应用程序的一部分。大多数撤销操作源于我们底层的域模型,但我们还连接到了某些ViewModel的领域,以允许在那里进行撤销/重做。
您可以在codeplex网站上找到有关更多信息和文档http://muf.codeplex.com/

2
我猜您是将命令模式与备忘录相结合使用?
我认为撤消系统应该集成到 ViewModel 层中,因为它是 UI 状态。
通常,撤消/重做作用于业务对象,而 UI 反映了业务层。
假设我们有一个 Product 类,其中包含“Description”字符串。ProductVM 公开一个字符串属性,该属性引发 PropertyChanged 事件。在修改时,备忘录会保留旧的模型实例。如果您撤消,则使用 ProductVM.Description =(memento as Product)。Description 恢复备忘录:模型和 UI 都将更新。
注意:避免使用 (memento as Product) ,这只是一个示例;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接