コマンドオブジェクトを適切なレシーバーに関連付けるにはどうすればよいですか?


9

プロジェクトに元に戻すとやり直しを実装するためにコマンドパターンを使用しようとしました

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

におけるAddElementコマンドの実装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";
    }
 }
...

UndoそしてRedoスタックが中に保存されているFormMainクラスとエディタフォームに渡されます。

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;

新しいで場合FormEditやり直し又は元に戻すボタンをユーザがクリックは、の対応する機能がFormEdit実行され、私は確認のコマンドのこの受信機は、コマンドが最初に作成された形態であり、現在は破棄されていることができます。プログラムでエラーが発生することを期待していますが、Commandオブジェクトに古いフォームへの参照が格納されているようで、これが誤動作の原因になります。

したがって、メインフォームまたはwebBrowserコントロールのいずれかで、コマンド自体と同じ寿命を持つ、コマンドの一貫したレシーバーを見つける必要があると思います。しかし、それでも、コマンドに関連するいくつかのコントロールにアクセスできるはずです。

Commandオブジェクトのレシーバーとしてコマンド機能を実装するのに最適な場所はどこですか?または、スタックからポップされたコマンドに新しいフォームを関連付ける他の方法。


この決定はあなた次第だと思います。アプリケーションの仕様や機能要件がわからないため、お手伝いできません。
陶酔

8
Commandオブジェクトには、シリアル化可能なデータのみを含める必要があります(つまり、他のオブジェクトへの参照は含めないでください)。これらの一般的な用途には、シリアル化されたフォームをネットワーク経由で送信する、後でファイルに保存する、または別のレシーバーで再生する(必要な場合)たとえば、変更がリアルタイムで画面に表示されます)。つまり、Receiverを各コマンドメソッドに渡すか、ReceiverにexecuteCommand()/ undoCommand()メソッドを渡して、それ自体を渡したり、コードではなくメソッド名/引数のみを含むコマンドオブジェクトを使用したりすることができます。 。
Ixrec


@Ixrecアドバイスありがとうございます。Receiver各コマンドオブジェクトのを設定できるはずです。これを行うつもりです。
2015

代わりにmementoパターンの使用を検討してください。
P. Roe、2016

回答:


1

コマンド・パターンはに適用されるべきモデルではなく、UI。あなたの場合、それを作ります

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

UIを更新するには、Observerパターンを使用します。これにより、開いているすべてのフォームとそのコントロールが、基になるモデルの変更に対応できます。

Commandはドキュメントの変更のみを処理でき、UI のオブザーバーは変更内容に関係なくコントロールを更新するだけでよいので、コードはより明確になり、より分離されます。

フォームを閉じると、それ自体がオブザーバーとして登録解除され、フォームへの参照は保持されません。

ドキュメントに変更を加えた後に新しいフォームを開いた場合、元の変更が行われたときにフォームが存在していなかったとしても、取り消し後に通知されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.