如何将命令对象与正确的接收者关联?


9

我尝试使用命令模式在项目中实现撤消和重做

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";
    }
 }
...

UndoRedo堆栈都存储在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年

8
我相信Command对象应该只包含可序列化的数据(即,不引用其他对象),因为它们的常见用法包括跨网络发送其序列化表格,将其保存到文件中以备后用或在其他接收器上重播它们(如果需要)您所做的更改以实时显示在我的屏幕上)。这可能意味着您想将Receiver传递给每个命令方法,或者给Receiver赋予它自己传递的executeCommand()/ undoCommand()方法,或者也许使用仅包含方法名称/参数而不是代码的命令对象。 。
Ixrec 2015年


@Ixrec谢谢您的建议,那么您的意思是我应该能够设置Receiver每个命令对象的,我将这样做。
艾哈迈德(Ahmad)

考虑改用记忆模式。
P. Roe

Answers:


1

指令模式应该适用于模型,而不是UI。根据您的情况

protected HtmlDocument Receiver { set; get; }
protected HtmlElement Element { set; get; }

要更新UI,请使用Observer模式,以便所有打开的窗体及其控件都可以对基础模型中的更改做出反应。

您的代码将变得更加清晰和解耦,因为Command只能处理文档的更改,并且UI中的观察者只需更新控件即可,而不必考虑更改的确切内容。

窗体关闭时,它将注销自己作为观察者的位置,并且不会保留对其的引用。

如果在文档更改后打开了新表单,则即使在原始更改时不存在该撤消操作,也会在撤消后通知该表单。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.