Я пишу журнал отмен для моего экрана ввода данных WPF, который будет отслеживать изменения во всех элементах управления. Когда пользователь выбирает Отменить, я хочу не только отменить последнее изменение, но и вернуть фокус в элемент управления, значение которого возвращается. Я борюсь с лучшим способом вернуть этот фокус обратно.
Моя ViewModel будет частью, которая обрабатывает журналирование отмены: установщики свойств ViewModel перехватят некоторое состояние «до» перед обновлением DataModel. Так или иначе, это состояние «до» должно включать в себя достаточно информации, чтобы я мог сосредоточить внимание позже.
Для иллюстрации, скажем, есть два поля ввода данных: Адрес и Город. ViewModel имеет свойство для каждого, и View имеет TextBox для каждого, который связан с соответствующим свойством ViewModel.
Давайте рассмотрим пример, когда пользователь только что ввел значение в поле «Адрес», а затем щелкнул поле «Город». Я использую стандартное поведение UpdateSourceTrigger.LostFocus, поэтому изменение адреса сохраняется, когда текстовое поле адреса теряет фокус. У меня есть три разные идеи о том, как подойти к этому, но я не знаю достаточно деталей о WPF, чтобы знать, как заставить любую из них работать.
Я мог бы забыть о привязке данных в стиле MVVM и перехватить события LostFocus элементов управления редактирования (или добавить прикрепленное поведение, или создать пользовательский элемент управления, оборачивающий TextBox, или ...). В обработчике событий LostFocus я мог бы создать кадр отмены, который включает ссылку на отправителя события. Позже, после отмены, я просто фокусирую элемент управления, чью ссылку я сохранил. Это, вероятно, то, что я бы сделал в WinForms, но в WPF я бы предпочел придерживаться шаблона ViewModel - я бы предпочел, чтобы логика журналирования работала в ViewModel, а не в View, для тестируемости, если ничего больше. Так что этот вариант не мой первый выбор.
В установщиках свойств моего ViewModel я мог зафиксировать имя устанавливаемого свойства ViewModel (в данном примере «Address») и сохранить это имя в кадре отмены. Позже, в Undo, я мог бы перебрать все элементы управления в View, ища первый, который я могу найти, который имеет что-то связанное со свойством с именем Address. Как только я нахожу один такой элемент управления, я уделяю ему внимание. Это было бы достаточно для того, что мне нужно, так как я не ожидаю иметь более одного элемента управления, привязанного к одному и тому же свойству ViewModel. Проблема заключается в том, что для этого нужно копаться в связывающих выражениях, а я не знаю, как это сделать. (Это также привело бы к более позднему связыванию на основе имен, которое могло бы прерваться, если я произвожу рефакторинг.)
Когда моя ViewModel добавляет изменение в стек отмены, он может попросить слой View (через интерфейс) создать Memento, который знает, какой элемент управления имеет фокус. После отмены журнал попросил бы View восстановить этот Memento. Проблема здесь в том, что к тому времени, когда свойство моего ViewModel устанавливается, и я добавляю кадр отмены, фокус клавиатуры уже переместился в City TextBox, поэтому «создание памятки» должно быть хитрее, чем просто «где» текущий фокус клавиатуры прямо сейчас ", и я не уверен, как этого добиться.
У кого-нибудь есть предложения по выполнению любой из вышеперечисленных работ или есть альтернативные подходы, которые могут работать лучше?