I'm writing an undo journal for my WPF data-entry screen, which will track changes across all the controls. When the user selects Undo, I want to not only revert the latest change, but put focus back in the control whose value is being reverted. I'm struggling with the best way to put that focus back.
My ViewModel will be the part that handles the undo journaling: the ViewModel's property setters will capture some "before" state before updating the DataModel. One way or another, that "before" state needs to include enough information for me to be able to put the focus back later.
For illustration, let's say there are two data-entry fields: Address and City. The ViewModel has a property for each, and the View has a TextBox for each that's bound to the corresponding ViewModel property.
Let's follow the example where the user has just typed a value into the Address field, and then clicked on the City field. I'm using the default UpdateSourceTrigger.LostFocus behavior, so the Address change gets saved when the Address TextBox loses focus. I've got three different ideas so far on how to approach this, but I don't know enough details about WPF to know how to make any of them work.
I could forget about MVVM-style databinding, and hook the edit controls' LostFocus events (or add an attached behavior, or make a custom control that wraps a TextBox, or...). In the LostFocus event handler, I could create an undo frame that includes a reference to the event's sender. Later, after Undo, I just focus the control whose reference I saved. This is probably what I would have done in WinForms, but in WPF I'd rather stick with the ViewModel pattern -- I'd rather have the journaling logic live in the ViewModel than the View, for testability if nothing else. So this option isn't my first choice.
In my ViewModel's property setters, I could capture the name of the ViewModel property that's being set ("Address" in this example), and store that name in the undo frame. Later, on Undo, I could iterate through all the controls in the View, looking for the first one I can find that has something bound to a property named Address. As soon as I find one such control, I give it focus. This would be good enough for what I need, since I don't expect to have more than one control bound to the same ViewModel property. The problem is that this would require digging into binding expressions, which is something I don't know how to do. (It would also introduce more name-based late binding that could break if I refactor.)
When my ViewModel adds the change to the undo stack, it could ask the View layer (via an interface) to create a Memento that knows which control has focus. On Undo, the journal would ask the View to restore that Memento. The problem here is that, by the time my ViewModel's property is getting set and I'm adding the undo frame, the keyboard focus has already moved to the City TextBox, so the "create memento" would need to be trickier than just "where's the current keyboard focus right now", and I'm not sure how to accomplish that trick.
Anyone have any suggestions on making any of the above work, or have alternate approaches that might work better?