¿Cómo asocio los objetos de comando con el receptor correcto?

9

Traté de usar el Patrón de comando para implementar Deshacer y Rehacer en mi proyecto

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);
    }
}

Implementación del AddElementcomando en 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";
    }
 }
...

Las pilas Undoy Redose almacenan en la FormMainclase y se pasan al formulario del editor.

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;

Cuando en una nueva, FormEditel usuario hace clic en el botón Rehacer o Deshacer, FormEditse ejecuta la función correspondiente en el , pero como verifiqué, este receptor del comando es la forma en que el comando se creó por primera vez y ahora se ha eliminado. Espero que el programa genere un error, pero parece que el Commandobjeto almacena una referencia a la forma anterior y esto conduce a un mal comportamiento.

Por lo tanto, creo que debo encontrar un receptor consistente para los comandos, ya sea el formulario principal o el control webBrowser, que tiene el mismo tiempo de vida que los comandos en sí. Pero aún así debería tener acceso a algunos controles relacionados con los comandos.

¿Dónde está el mejor lugar para implementar las funciones de comando como receptor de Commandobjetos? O cualquier otra forma de asociar el nuevo formulario a un comando emergente de la pila.

Ahmad
fuente
Creo que esta decisión es tuya. No podemos ayudarlo porque no conocemos las especificaciones o los requisitos funcionales de su aplicación.
Eufórico
8
Creo que los objetos Command solo deben contener datos serializables (es decir, sin referencias a otros objetos) ya que los usos comunes para ellos incluyen enviar sus formularios serializados a través de redes, guardarlos en un archivo para más adelante o volver a reproducirlos en un receptor diferente (si lo desea sus cambios para que aparezcan en mi pantalla en tiempo real, por ejemplo). Eso puede significar que desea pasar el Receiver a cada método de comando, o tal vez darle al Receiver executeCommand () / undoCommand () métodos que le permiten pasar, o tal vez usar objetos de comando que solo contengan nombres / argumentos de métodos en lugar de código .
Ixrec
@ Ixrec Gracias por tu consejo, entonces quieres decir que debería poder establecer el Receiverde cada objeto de comando, voy a hacer esto.
Ahmad
Considere usar el patrón de recuerdo en su lugar.
P. Roe

Respuestas:

1

El patrón de comando debe aplicarse al modelo , y no a la interfaz de usuario. En tu caso, hazlo

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

Para actualizar la IU, use el patrón Observador , de modo que todos los formularios abiertos y sus controles puedan reaccionar a los cambios en el modelo subyacente.

Su código se volverá más claro y más desacoplado porque Command solo puede encargarse de cambiar el documento, y los observadores en la interfaz de usuario solo tienen que actualizar los controles sin tener en cuenta exactamente qué cambió.

Cuando se cierra un formulario, se anulará su registro como observador y no se mantendrá ninguna referencia a él.

Si se abre un nuevo formulario después de un cambio en el documento, se le notificará después de deshacer, incluso si no estaba presente cuando se realizó el cambio original.

Apalala
fuente