2

我目前正在寻找将撤消/重做(基于本文)与使用 ICommand 的命令模式结合起来。阅读有关 CanExecute 和 CanExecuteChanged 的​​想法后,我发现了将更改的状态传播到所有已注册 UIElement 的 CommandManager。但是,如果命令本身存储更改的数据,则似乎很难将这两者结合起来。这是当前情况的示例:

interface IUndoCommand : ICommand
{
    void Undo();
}

和实施:

public class SampleCommand : IUndoCommand
{
    private Point oldPosition;
    private Shape shape;

    // Gets the currently moved shape object
    public MoveCommand(Shape shape, Point oldPosition)
    {
        this.oldPosition = oldPosition;
        this.newPosition = new Point(Cavas.GetLeft(shape),Canvas.GetTop(shape));
        this.shape = shape;
    }

    public void Execute(object parameter)
    {
        Model.PersistChanges(shape, newPosition);
    }

    public void Undo()
    {
        Model.PersistChanges(shape, oldPosition);
    }

    public bool CanExecute(object parameter)
    {
    }

    public event EventHandler CanExecuteChanged;
}

冲突

在此实现中,命令存储更改,因此每次执行时都需要创建一个新实例。然而,CommandManager 会跟踪状态并通知 UIElements。如果我在那里注册命令的每个实例,一个 UIElement 就会有几个相等的命令竞争 CanExecute 状态。这似乎打破了这个想法,那么它是如何工作的呢?

当然,我可以将重做/撤消所需的状态从命令移动到模型,并准确注册一个(静态)命令实例,该实例将被全面使用。但实际上我喜欢在命令中存储状态的想法。

如果我省略 ICommand 用法,wpftutorial.net的示例将起作用 - 尽管我还没有完全了解那里的操作/撤消操作的想法。

问题

您如何结合这些方法,撤消/重做 + CommandManager?是实现在模型中保存状态的唯一解决方案(以 MVVM 为基础)还是有其他机会?

编辑:

是否可以在仍然使用 CommandManager 的命令中保存状态?ICommand-Interface 提供了跟踪 CanExecute-State 的功能,这是一个好主意。但是,我看不到在保存命令中的状态的同时保留这个想法的可能性(因此需要几个不同的实例)。

4

1 回答 1

1

对于其他每个绊倒这个的人:

我现在使用分层视图模型解决了这个问题。现在每个命令都有自己的 ViewModel。

public class ViewModel 
{

    public ViewModel()
    {
        MoveCommand = new MoveCommand(this);
    }

    public Shape Shape {get;set;}
    public Point CurrentPosition {get;set;}
    public ICommand MoveCommand {get; private set;}
}


public class MoveCommand
{
    ViewModel viewModel;
    Point shiftVector;

    public MoveCommand(ViewModel viewModel, Point shiftVector)
    {
        this.viewModel = viewModel;
        this.shiftVector = shiftVector;
    }

    public void Execute(object parameter)
    {
        shapeVM.CurrentPosition.X += shiftVector.X;
        shapeVM.CurrentPosition.Y += shiftVector.Y;
    }

    public void Undo()
    {
        shapeVM.CurrentPosition.X -= shiftVector.X;
        shapeVM.CurrentPosition.Y -= shiftVector.Y;
    }

    public bool CanExecute(object parameter)
    {
    }

    // Notice here: the events should be passed to the command manager to take care about it
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove {CommandManager.RequerySuggested -= value;}
    }

分层部分的作用如下:

public class BaseViewModel
{
    ObservableCollection<ViewModels> ViewModels;

    // pass the command from the child's viewModel.
    public ICommand MoveCommand
    {
        get
        {
            return SelectedItem.MoveCommand;
        }
    }

    public SelectedItem ViewModel {get;set;}

    public BaseViewModel()
    {

    }

}
于 2013-04-19T15:11:46.937 回答