I have a need to implement a memento undo-redo pattern. My application has multiple tabs and in these tabs there are multiple controls which all implement Orc.Memento. The trouble I am having is calling undo with the menu button on MainWindow and in the button action call undo on the last active control.
Edit: this project is unfortunately does not follow MVVM.
I chose Orc.Memento because it is super easy to implement without modifying objects. What I have now is working great only with keyboard commands Ctrl+X & Ctrl+Y. Calling undo only does undo on the active control. However, when I click the undo/redo buttons on the MainWindow menu my code does not know the last active control to call undo/redo on.
Option one is to keep track of the last active control by setting a global property on GotFocus()
of each control. I feel like there has to be a better way.
That is why I am here :-).
public class MyControl : IMemento
{
private MementoService mementoService = new MementoService();
public void RegisterAll()
{
mementoService.RegisterObject(myObject);
mementoService.RegisterCollection(myCollection);
}
public void Undo()
{
mementoService.Undo();
}
public void Redo()
{
mementoService.Redo();
}
}
Ctrl+Z & Ctrl+Y is mapped here. The undo/redo methods find the currently active control and call undo/redo at that control.
public MainWindow
{
/// <summary>
/// Call undo on the currently active control
/// </summary>
public void Undo()
{
/*
* get current focused control.
* find the parent that is an IMemento. And call Redo on that control
*/
var focusedControl = FocusManager.GetFocusedElement(this);
var mementoControl = UIHelper.TryFindParentThatIsIMemento<Control>(focusedControl as DependencyObject);
/*
* Call Undo on the control that is currently active
*/
if (mementoControl != null && mementoControl is IMemento)
{
var mem = (mementoControl as IMemento);
mem.Undo();
}
}
}
Note: If I could program this how Excel works by auto navigating to the control where the undo/redo happens that would be great. It is not necessary, but if you have an idea my ears are open.
Here are a few recommendations:
Try to implement undo/redo against models (e.g. using Orc.ProjectManagement), not against views (since views are short-living
Try to use the TabControl from Orc.Controls, which allows you to keep all the tabs active and thus allowable for redo/undo).