C#で何か作る日記

C#初学者が何かを作るその過程を備忘録として書いていく日記。同じようなことで悩んでいる1人、2人の役に立てたら嬉しいな。プログラムの他にたまに3Dモデルも作ったり作らなかったり。

delegateを使ってRedoUndoを実装

しばらく悩まされていたdelegateが一応の解決をした、、、のかな。

前回の最後に

public delegate bool Redo();
public Redo redo;

って書いてたけどこれが正解っぽい。

public Action Redo;

って書くとデリゲートの定義?がいらなくなるのね。
だからそのまま使うことができた、と。

戻り値がある場合は

public Func<T, TReturn> Invoke;

とすれば定義を省略できる。らしいけど、『Func』って名前の付け方がなんかイヤだな

というわけで最初の方法で実装することに。

コマンドクラスを

namespace RedoUndoLib
{
    class Command
    {
        public delegate bool Invoke();
        public delegate void Redo();
        public delegate void Undo();

        public Invoke invoke;
        public Redo redo;
        public Undo undo;
    }
}

こんな風に。

で、管理クラスが

namespace RedoUndoLib
{
    class CommandManager
    {
        private Stack<Command> redoList = new Stack<Command>();
        private Stack<Command> undoList = new Stack<Command>();

        /// <summary> 呼び出し </summary>
        public bool Invoke(Command cmd)
        {
            if (cmd.invoke() == false)
            {
                return false;
            }

            redoList.Push(cmd);
            undoList.Clear();

            return true;
        }

        /// <summary> やり直し </summary>
        public bool Redo()
        {
            var cmd = redoList.Pop();
            cmd.redo();
            undoList.Push(cmd);

            return true;
        }

        /// <summary> 繰り返し </summary>
        public bool Undo()
        {
            var cmd = undoList.Pop();
            cmd.undo();
            redoList.Push(cmd);
            return true;
        }
    }
}

エラーのチェックは省いてるけど大体こんな感じに。
Redo、UndoがStackなのに○○Listになっているのは後でリストに変更する予定だから。

で、これで準備ができた。
実際に使うときは

private CommandManager manager = new CommandManager();
private int n = 0;

private void CreateCommand(){

    var cmd = new Command();

    // 通常呼び出し時の処理
    cmd.invoke = () =>
    {
        n++;
    };

    // Redo時の処理
    cmd.redo = () => {
        n--;
    };

    // Undo時の処理
    cmd.undo = () =>
    {
        n++;
    };

    // 管理クラスに追加
    manager.Invoke(cmd); 
}

処理の内容としては、呼び出すたびにnの値を+1して『戻る』で-1をする、という単純なもの。

今のところ、これでほとんどの場合に対応できそう。
うん、いいものが作れた。