Отмена ведения журнала: фокусировка на элементе управления отменяется - PullRequest
4 голосов
/ 12 мая 2009

Я пишу журнал отмен для моего экрана ввода данных WPF, который будет отслеживать изменения во всех элементах управления. Когда пользователь выбирает Отменить, я хочу не только отменить последнее изменение, но и вернуть фокус в элемент управления, значение которого возвращается. Я борюсь с лучшим способом вернуть этот фокус обратно.

Моя ViewModel будет частью, которая обрабатывает журналирование отмены: установщики свойств ViewModel перехватят некоторое состояние «до» перед обновлением DataModel. Так или иначе, это состояние «до» должно включать в себя достаточно информации, чтобы я мог сосредоточить внимание позже.

Для иллюстрации, скажем, есть два поля ввода данных: Адрес и Город. ViewModel имеет свойство для каждого, и View имеет TextBox для каждого, который связан с соответствующим свойством ViewModel.

Давайте рассмотрим пример, когда пользователь только что ввел значение в поле «Адрес», а затем щелкнул поле «Город». Я использую стандартное поведение UpdateSourceTrigger.LostFocus, поэтому изменение адреса сохраняется, когда текстовое поле адреса теряет фокус. У меня есть три разные идеи о том, как подойти к этому, но я не знаю достаточно деталей о WPF, чтобы знать, как заставить любую из них работать.

  1. Я мог бы забыть о привязке данных в стиле MVVM и перехватить события LostFocus элементов управления редактирования (или добавить прикрепленное поведение, или создать пользовательский элемент управления, оборачивающий TextBox, или ...). В обработчике событий LostFocus я мог бы создать кадр отмены, который включает ссылку на отправителя события. Позже, после отмены, я просто фокусирую элемент управления, чью ссылку я сохранил. Это, вероятно, то, что я бы сделал в WinForms, но в WPF я бы предпочел придерживаться шаблона ViewModel - я бы предпочел, чтобы логика журналирования работала в ViewModel, а не в View, для тестируемости, если ничего больше. Так что этот вариант не мой первый выбор.

  2. В установщиках свойств моего ViewModel я мог зафиксировать имя устанавливаемого свойства ViewModel (в данном примере «Address») и сохранить это имя в кадре отмены. Позже, в Undo, я мог бы перебрать все элементы управления в View, ища первый, который я могу найти, который имеет что-то связанное со свойством с именем Address. Как только я нахожу один такой элемент управления, я уделяю ему внимание. Это было бы достаточно для того, что мне нужно, так как я не ожидаю иметь более одного элемента управления, привязанного к одному и тому же свойству ViewModel. Проблема заключается в том, что для этого нужно копаться в связывающих выражениях, а я не знаю, как это сделать. (Это также привело бы к более позднему связыванию на основе имен, которое могло бы прерваться, если я произвожу рефакторинг.)

  3. Когда моя ViewModel добавляет изменение в стек отмены, он может попросить слой View (через интерфейс) создать Memento, который знает, какой элемент управления имеет фокус. После отмены журнал попросил бы View восстановить этот Memento. Проблема здесь в том, что к тому времени, когда свойство моего ViewModel устанавливается, и я добавляю кадр отмены, фокус клавиатуры уже переместился в City TextBox, поэтому «создание памятки» должно быть хитрее, чем просто «где» текущий фокус клавиатуры прямо сейчас ", и я не уверен, как этого добиться.

У кого-нибудь есть предложения по выполнению любой из вышеперечисленных работ или есть альтернативные подходы, которые могут работать лучше?

1 Ответ

1 голос
/ 17 мая 2009

Я бы начал с вашего второго подхода. Однако вместо того, чтобы копаться в списке привязок, я бы жестко закодировал свойство highlight элемента управления в свойство VM.

Например, это моя виртуальная машина:

public class VM
{
    public double Price { get; set; }
    public bool PriceHighlighted { get; set; }
}

Затем свяжите свойство Price с TextBox и фоном TextBox с PriceHighlighted (с помощью преобразователя значений). Теперь VM имеет полный контроль над тем, как должен реагировать вид. Когда пользователь делает «Отменить», ВМ может установить для всех xxxHightlighted значение false, кроме того, которое вы хотите выделить.

...