Ich habe versucht, Command Pattern zum Implementieren von Undo und Redo in meinem Projekt zu verwenden
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);
}
}
Implementierung des AddElement
Befehls in 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";
}
}
...
Die Stapel Undo
und Redo
werden in der FormMain
Klasse gespeichert und an das Editorformular übergeben.
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;
Wenn FormEdit
der Benutzer in einem neuen Modus auf die Schaltfläche Wiederherstellen oder Rückgängig klickt, wird die entsprechende Funktion in FormEdit
ausgeführt. Wenn ich diesen Empfänger des Befehls überprüft habe, ist dies die Form, in der der Befehl zuerst erstellt wurde und jetzt möglicherweise entsorgt wurde. Ich erwarte, dass das Programm einen Fehler auslöst, aber es scheint, dass das Command
Objekt einen Verweis auf die alte Form speichert und dies zu Fehlverhalten führt.
Daher denke ich, dass ich einen konsistenten Empfänger für die Befehle finden muss, entweder das Hauptformular oder das webBrowser-Steuerelement, das die gleiche Lebensdauer wie die Befehle selbst hat. Trotzdem sollte ich Zugriff auf einige Steuerelemente haben, die sich auf die Befehle beziehen.
Wo kann man die Befehlsfunktionen als Empfänger von Command
Objekten am besten implementieren ? Oder eine andere Möglichkeit, das neue Formular einem vom Stapel abgelegten Befehl zuzuordnen.
quelle
Receiver
von jedem Befehlsobjekt festzulegen , ich werde dies tun.Antworten:
Das Befehlsmuster auf das gelten sollte Modell und nicht der UI. In deinem Fall mach es
Verwenden Sie zum Aktualisieren der Benutzeroberfläche das Observer- Muster, damit alle geöffneten Formulare und ihre Steuerelemente auf Änderungen im zugrunde liegenden Modell reagieren können.
Ihr Code wird klarer und entkoppelter, da Command nur das Dokument ändern kann und die Beobachter in der Benutzeroberfläche nur die Steuerelemente aktualisieren müssen, ohne genau zu berücksichtigen , was geändert wurde.
Wenn ein Formular geschlossen wird, hebt es die Registrierung als Beobachter auf und es werden keine Verweise darauf aufbewahrt.
Wenn ein neues Formular nach einer Änderung des Dokuments geöffnet wird, wird es nach einem Rückgängigmachen benachrichtigt, auch wenn es zum Zeitpunkt der ursprünglichen Änderung nicht vorhanden war.
quelle