Comment associer des objets de commande au bon récepteur?

9

J'ai essayé d'utiliser le modèle de commande pour implémenter Annuler et Rétablir dans mon projet

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

Implémentation du AddElementcommandement 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";
    }
 }
...

les piles Undoet Redosont stockées dans la FormMainclasse et transmises au formulaire de l'éditeur.

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;

Quand dans un nouveau FormEditl'utilisateur clique sur le bouton Rétablir ou Annuler, la fonction correspondante dans le FormEditest exécutée, mais comme j'ai vérifié ce récepteur de la commande est la forme sous laquelle la commande a été créée pour la première fois et peut maintenant être supprimée. Je m'attends à ce que le programme génère une erreur, mais il semble que l' Commandobjet stocke une référence à l'ancien formulaire et cela conduit à un mauvais comportement.

Par conséquent, je pense que je dois trouver un récepteur cohérent pour les commandes, soit le formulaire principal, soit le contrôle webBrowser, qui a la même durée de vie que les commandes elles-mêmes. Mais pourtant, je devrais avoir accès à certains contrôles liés aux commandes.

Où est le meilleur endroit pour implémenter les fonctions de commande en tant que récepteur d' Commandobjets? Ou toute autre façon d'associer le nouveau formulaire à une commande sortie de la pile.

Ahmad
la source
Je pense que cette décision vous appartient. Nous ne pouvons pas vous aider car nous ne connaissons pas les spécifications ou les exigences fonctionnelles de votre application.
Euphoric
8
Je pense que les objets Command ne doivent contenir que des données sérialisables (c'est-à-dire, aucune référence à d'autres objets), car leur utilisation courante consiste à envoyer leurs formulaires sérialisés sur des réseaux, à les enregistrer dans un fichier pour plus tard ou à les rejouer sur un autre récepteur (si vous le souhaitez vos modifications pour apparaître sur mon écran en temps réel, par exemple). Cela peut signifier que vous souhaitez transmettre le récepteur à chaque méthode de commande, ou peut-être donner au récepteur les méthodes executeCommand () / undoCommand () qui le laissent passer lui-même, ou utiliser des objets de commande qui ne contiennent que des noms / arguments de méthode au lieu de code .
Ixrec
@Ixrec Merci pour vos conseils, alors vous voulez dire que je devrais pouvoir définir le Receiverde chaque objet de commande, je vais le faire.
Ahmad
Envisagez plutôt d'utiliser le modèle de souvenir.
P. Roe

Réponses:

1

Le modèle de commande doit s'appliquer au modèle et non à l'interface utilisateur. Dans votre cas, faites-le

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

Pour mettre à jour l'interface utilisateur, utilisez le modèle Observer , afin que tous les formulaires ouverts et leurs contrôles puissent réagir aux modifications du modèle sous-jacent.

Votre code deviendra plus clair et plus découplé car Command ne peut prendre en charge que la modification du document, et les observateurs dans l'interface utilisateur n'ont qu'à mettre à jour les contrôles sans tenir compte exactement de ce qui a changé.

Lorsqu'un formulaire se ferme, il se désenregistrera en tant qu'observateur et aucune référence ne sera conservée.

Si un nouveau formulaire est ouvert après une modification du document, il sera notifié après une annulation même s'il n'était pas présent lors de la modification d'origine.

Apalala
la source