Jak powiązać obiekty poleceń z właściwym odbiornikiem?

9

Próbowałem użyć Wzorca poleceń do implementacji Cofnij i Ponów w moim projekcie

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

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

Undoi Redostosy są przechowywane w FormMainklasie i są przekazywane do formularza edytora.

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;

Gdy w nowym FormEditużytkownik kliknie przycisk Ponów lub Cofnij, odpowiednia funkcja w FormEditjest wykonywana, ale jak sprawdziłem, odbiornik polecenia jest formą, w której polecenie zostało utworzone po raz pierwszy, a teraz mogło zostać usunięte. Oczekuję, że program zgłosi błąd, ale wygląda na to, że Commandobiekt przechowuje odniesienie do starej formy, co prowadzi do złego zachowania.

Dlatego myślę, że muszę znaleźć spójny odbiornik dla poleceń, zarówno głównej, jak i kontrolki webBrowser, która ma taki sam czas życia jak same polecenia. Ale powinienem mieć dostęp do niektórych elementów sterujących związanych z poleceniami.

Gdzie jest najlepsze miejsce na wdrożenie funkcji poleceń jako odbiornika Commandobiektów? Lub w jakikolwiek inny sposób powiązania nowego formularza z poleceniem wyskakującym ze stosu.

Ahmad
źródło
Myślę, że ta decyzja należy do ciebie. Nie możemy ci pomóc, ponieważ nie znamy specyfikacji ani wymagań funkcjonalnych twojej aplikacji.
Euforia
8
Wierzę, że obiekty poleceń powinny zawierać tylko dane, które można serializować (tj. Bez odwołań do innych obiektów), ponieważ typowe zastosowania dla nich obejmują wysyłanie ich serializowanych formularzy przez sieci, zapisywanie ich do pliku na później lub odtwarzanie ich na innym odbiorniku (jeśli chcesz na przykład zmiany, które pojawią się na moim ekranie). Może to oznaczać, że chcesz przekazać w Odbiorniku do każdej metody polecenia, lub może dać odbiornikowi metody executeCommand () / undoCommand (), które pozwalają mu się przepuścić, lub może użyć obiektów poleceń zawierających tylko nazwy metod / argumenty zamiast kodu .
Ixrec,
@Ixrec Dziękuję za radę, to znaczy, że powinienem być w stanie ustawić Receiverkażdy obiekt polecenia, zamierzam to zrobić.
Ahmad
Zastanów się nad użyciem wzorca pamiątkowego.
P. Roe

Odpowiedzi:

1

Poleceń wzór powinno stosować się do modelu , a nie UI. W twoim przypadku, zrób to

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

Aby zaktualizować interfejs użytkownika, użyj wzorca obserwatora , aby wszystkie otwarte formularze i ich kontrolki mogły reagować na zmiany w modelu bazowym.

Twój kod stanie się bardziej przejrzysty i oddzielony, ponieważ Command może zająć się tylko zmianą dokumentu, a obserwatorzy w interfejsie użytkownika muszą tylko aktualizować formanty bez względu na to, co się zmieniło.

Kiedy formularz zostanie zamknięty, wyrejestruje się jako obserwator i nie zostaną zachowane żadne odniesienia do niego.

Jeśli nowy formularz zostanie otwarty po zmianie dokumentu, zostanie o nim powiadomiony po cofnięciu, nawet jeśli nie był obecny w momencie dokonania pierwotnej zmiany.

Apalala
źródło