Eu tentei usar o Command Pattern para implementar Desfazer e Refazer no meu projeto
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);
}
}
Implementação de AddElement
comando em 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";
}
}
...
as pilhas Undo
e Redo
são armazenadas na FormMain
classe e passadas para o formulário do 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;
Quando em um novo, FormEdit
o usuário clica no botão Refazer ou Desfazer, a função correspondente no FormEdit
é executada, mas, como verifiquei, este receptor do comando é a forma na qual o comando foi criado pela primeira vez e agora pode ter sido descartado. Espero que o programa gere um erro, mas parece que o Command
objeto armazena uma referência à forma antiga e isso leva ao mau comportamento.
Portanto, acho que preciso encontrar um receptor consistente para os comandos, tanto o formulário principal quanto o controle webBrowser, que tem o mesmo tempo de vida útil dos comandos. Mas ainda assim eu deveria ter acesso a alguns controles relacionados aos comandos.
Onde é o melhor lugar para implementar as funções de comando como receptor de Command
objetos? Ou qualquer outra maneira de associar o novo formulário a um comando retirado da pilha.
fonte
Receiver
objeto de cada comando, eu vou fazer isso.Respostas:
O padrão de comando deve se aplicar ao modelo , e não à interface do usuário. No seu caso, faça
Para atualizar a interface do usuário, use o padrão Observador , para que todos os formulários abertos e seus controles possam reagir a alterações no modelo subjacente.
Seu código se tornará mais claro e dissociado, pois o Command pode cuidar apenas de alterar o documento, e os observadores na interface do usuário precisam atualizar os controles apenas sem considerar exatamente o que mudou.
Quando um formulário é fechado, ele se registrará como observador e nenhuma referência a ele será mantida.
Se um novo formulário for aberto após uma alteração no documento, ele será notificado após um desfazer, mesmo que não estivesse presente quando a alteração original foi feita.
fonte