&tag(WPF/Undo);
&tag(WPF, Undo);
*目次 [#c76f3e45]
#contents
*参考情報 [#ke8ad5f6]
-[[Notify Changed » Blog Archive » Using the Viewmodel pattern to provide Undo / Redo in WPF:http://blog.notifychanged.com/2009/01/30/using-the-viewmodel-pattern-to-provide-undo-redo-in-wpf/]] 
-[[Notify Changed » Blog Archive » Using MVVM to provide undo/redo. Part 2: Viewmodelling lists:http://blog.notifychanged.com/2009/01/30/viewmodelling-lists/]]
-[[danice/MVVMUndoRedo - GitHub:https://github.com/danice/MVVMUndoRedo]]。上記blog記事のサンプルコード。blogには断片的なコードしか示されてないので実際にソースコードを参照したほうがよい。
-[[WPF Undo/Redo Framework:http://wpfundoredo.codeplex.com/]]…WPF用のUndo/Redoフレームワーク。

*[[WPF Undo/Redo Framework:http://wpfundoredo.codeplex.com/]]に関して [#u9ba2c1c]
-サンプルはソースコードのダウンロードから入手可能(ダウンロードはDLLのみ)。
-UndoableActionBaseを継承したUndoablePropertyとDelegateUndoableCommandを使う。
-MVVM風にViewModelのプロパティの変更をUndoしたい場合は、次のようにUndoablePropertyを使ってプロパティ定義する。
#pre{{
        private UndoableProperty<double> _sliderText;
        public double SliderText
        {
            get { return _sliderText.GetValue(); }
            set { _sliderText.SetValue(value); }
        }
}}
-プロパティの変更はPropertyChangedで通知されるが、Undoは以下の処理によりある程度の時間以内の変更は1つの処理として元に戻される。
#pre{{
        /// <summary>
        /// Tells the context that an action has occurred.
        /// </summary>
        /// <param name="action">The action that was executed.</param>
        /// <param name="data">The data associated with the action.</param>
        public void ActionExecuted(IUndoableAction action, object data)
        {
			object possible = null;

            if (action is IUndoableProperty && (this.UndoStack.Count > 0 && this.UndoStack.First().Item1 == action.Name))
            {
                if ((DateTime.Now - lastModified).TotalMilliseconds < (action as IUndoableProperty).BatchingTimeout)
                {
                    possible = this.UndoStack.Pop().Item2;
                }
                else
                {
                    this.lastModified = DateTime.Now;
                }
            }
            else
            {
                this.lastModified = DateTime.Now;
            }
		
			if (possible == null)
			{
				this.UndoStack.Push(new Tuple<string, object>(action.Name, data));
			}
			else
			{
				this.UndoStack.Push(new Tuple<string, object>(action.Name, possible));
			}

            this.RedoStack.Clear();
           
        }


}}

-プロパティ以外のコマンドをUndoしたい場合次のようにする。サンプルのボタンがおされたときの処理。
#pre{{
        public UndoableDelegateCommand<string, char> TypeCharacterCommand { get; set; }

        public char TypeCharacterCommand_Execute(string s)
        {
            var c = s.First();
            this.SomeText += c;
            return c;
        }

        public bool TypeCharacterCommand_CanExecute(string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                return false;
            }

            var c = s.First();
            if (char.IsDigit(c))
            {
                return true;
            }

            return false;
        }

}}

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS