- 追加された行はこの色です。
- 削除された行はこの色です。
&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;
}
}}