我尝试使用命令模式在项目中实现撤消和重做
public abstract class Command
{
protected Form Receiver { set; get; }
protected HtmlElement Element { set; get; }
abstract public void ReDo();
abstract public void UnDo();
public Command(Form receiver)
{
this.Receiver = receiver;
}
}
class AddElementCmd : Command
{
public AddElementCmd(HtmlElement elem, Form receiver)
: base(receiver)
{
Element = elem;
}
public override void ReDo()
{
((FormEdit)Receiver).AddElement(Element,false);
}
public override void UnDo()
{
((FormEdit)Receiver).DelElement(Element, false);
}
}
class DelElementCmd : Command
{
public DelElementCmd(HtmlElement elem, Form receiver)
: base(receiver)
{
Element = elem;
}
public override void ReDo()
{
((FormEdit)Receiver).DelElement(Element, false);
}
public override void UnDo()
{
((FormEdit)Receiver).AddElement(Element, false);
}
}
在Windows中执行AddElement
命令FormEdit
。
public void AddElement(HtmlElement elem, bool isNew = true)
{
IHTMLElement2 dom = elem.DomElement as IHTMLElement2;
if (isNew)
{
Command cmd = new AddElementCmd(elem, this);
Undo.Push(cmd);
Redo.Clear();
}
// some codes here....
if (showAlltoolStripButton.Checked)
{
dom.runtimeStyle.visibility = "hidden";
}
else if (showSelectionToolStripButton.Checked)
{
dom.runtimeStyle.visibility = "visible";
}
}
...
在Undo
和Redo
堆栈都存储在FormMain
阶级和被传递到编辑器的形式。
public Stack<Command> Undo = new Stack<Command>();
public Stack<Command> Redo = new Stack<Command>();
....
FormEdit editor = new FormEdit ();
editor.Browser = webBrowser1;
editor.addedElements = addedElements;
editor.restoreElements = restoreElements;
editor.Undo = Undo;
editor.Redo = Redo;
当FormEdit
用户再次单击“重做”或“撤消”按钮时,将FormEdit
执行中的相应功能,但是当我检查该命令的接收方时,该命令的形式是首次创建该命令的形式,现在可能已将其丢弃。我希望程序会引发错误,但似乎该Command
对象存储了对旧表格的引用,这会导致行为异常。
因此,我认为我必须为命令找到一个一致的接收者,无论是主窗体还是webBrowser控件,其寿命与命令本身相同。但是我应该可以访问一些与命令有关的控件。
将命令功能实现为Command
对象的接收者的最佳位置在哪里?或将新表单与从堆栈弹出的命令相关联的任何其他方法。
我认为这个决定由您决定。我们无法为您提供帮助,因为我们不了解您的应用程序的规格或功能要求。
—
欣快感,2015年
我相信Command对象应该只包含可序列化的数据(即,不引用其他对象),因为它们的常见用法包括跨网络发送其序列化表格,将其保存到文件中以备后用或在其他接收器上重播它们(如果需要)您所做的更改以实时显示在我的屏幕上)。这可能意味着您想将Receiver传递给每个命令方法,或者给Receiver赋予它自己传递的executeCommand()/ undoCommand()方法,或者也许使用仅包含方法名称/参数而不是代码的命令对象。 。
—
Ixrec 2015年
@Ixrec谢谢您的建议,那么您的意思是我应该能够设置
—
艾哈迈德(Ahmad)
Receiver
每个命令对象的,我将这样做。
考虑改用记忆模式。
—
P. Roe