我目前正在寻找使用ICommand将撤消/重做(基于this文章)与命令模式相结合。阅读CanExecute和CanExecuteChanged的想法,我找到了CommandManager,它将已更改的状态传播到所有已注册的UIElements。 但是,如果命令存储已更改的数据本身,则很难将这两者结合起来。这里是当前情况的一个例子:
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-state。这似乎打破了这个想法,所以它是如何运作的?
当然,我可以将重做/撤消所需的状态从命令移动到模型,并准确注册一个(静态)命令实例,该实例将全部使用。但实际上我喜欢在命令中训练状态的想法。
如果我省略了ICommand用法,那么wpftutorial.net的例子就可以了 - 虽然我还没有完全理解那里的动作/撤消动作。
如何组合这些方法,undo / redo + CommandManager?是实现在模型中保存状态的唯一解决方案(将MVVM视为基础)还是有其他机会?
编辑:
是否可以使用CommandManager在命令中保存状态? ICommand-Interface提供了跟踪CanExecute-State的功能,这是个不错的主意。但是,我没有看到在命令中保存状态时保留这个想法的可能性(因此需要几个不同的实例)。
答案 0 :(得分:1)
对于其他每一个绊脚石的人:
我现在使用分层ViewModels解决了这个问题。每个命令现在都有自己的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()
{
}
}