Как установить фокус на текстовое поле с помощью MVVM?
Как сфокусировать текстовое поле на ViewModel wpf?
<TextBox Name="PropertySearch"
Text="{Binding UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay, Path=PropertySearch,
ValidatesOnDataErrors=True}"
Width="110"
Height="25"
Margin="10" />
Ответы
Ответ 1
Вы можете сделать это, добавив свойство в ViewModel (или используя существующее свойство), которое указывает, когда произойдет SetFocus, но представление должно отвечать за фактическую настройку фокуса, поскольку это чисто связанное с View.
Вы можете сделать это с помощью DataTrigger.
Вид:
<Grid Name="LayoutRoot" DataContext="{StaticResource MyViewModelInstance}">
<Grid.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding UserShouldEditValueNow}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=PropertySearch}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<TextBox Name="PropertySearch" Text="{Binding UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Path=PropertySearch, ValidatesOnDataErrors=True}" Width="110" Height="25" Margin="10" />
</Grid>
ViewModel:
// When you think the view should set focus on a control
this.UserShouldEditValueNow = true;
Приведенный выше пример упрощается за счет использования только логического свойства ViewModel "UserShouldEditValueNow". Вы можете добавить свойство, подобное этому в ViewModel, или использовать другое свойство выделения, которое указывает это состояние.
Примечание. Итак, почему это делается в MVVM? Одна из причин: предположим, что автор View решил заменить TextBox на ComboBox или даже лучше, предположим, что ваше свойство было целочисленным значением, которое имело как TextBox для просмотра/редактирования номера, так и Slider как еще один способ редактирования одного и того же значения, оба элемента управления связаны с одним и тем же свойством... как бы ViewModel знал, какой элемент управления следует настроить? (когда он не должен даже знать, какие элементы управления или управления связаны с ним в первую очередь). Таким образом, представление может выбрать, какой элемент управления следует сфокусировать, изменив цель привязки ElementName в Setter DataTrigger.
Счастливое кодирование!
Ответ 2
Вопрос, который вы должны задать себе, - "почему мой ViewModel должен знать, какой элемент управления имеет фокус?"
Я бы сказал, что фокус является свойством только для представления; это свойство взаимодействия и не имеет ничего общего с концептуальным состоянием. Это похоже на фоновый цвет элемента управления: зачем вы представляете его в виртуальной машине? Если вам нужно управлять фокусом по-своему, возможно, лучше использовать объект уровня представления для выполнения задания.
Ответ 3
В своем родительском элементе добавьте следующее свойство:
FocusManager.FocusedElement="{Binding ElementName=PropertySearch}"
Ответ 4
В то время как пуристы могут утверждать, что это исключено из VM, бывают случаи, когда это может иметь смысл сделать это с виртуальной машины.
Мой подход состоял в том, чтобы заставить представление реализовать интерфейс, передать этот интерфейс в ViewModel, а затем позволить методам вызова VM на интерфейсе.
Пример:
public interface IFocusContainer
{
void SetFocus(string target);
}
Несколько вещей, которые нужно иметь в виду:
- VM может обслуживать более одного экземпляра представления, поэтому ваша виртуальная машина может захотеть иметь набор ссылок на экземпляры IFocusContainer, а не только один.
- Обозначьте виртуальную машину. Вы не знаете, прослушиваются ли 0, 1 или 20 просмотров.
- "Целевой" параметр SetFocus() должен, вероятно, быть "слабо" связан с виртуальной машиной. Вы не хотите, чтобы VM заботилась о точном имени управления в пользовательском интерфейсе. Скорее, виртуальная машина должна указывать имя, которое определяется исключительно для управления фокусом. В моем случае я создал некоторые прикрепленные свойства, которые позволили бы мне "пометить" элементы управления "именами фокуса".
Чтобы реализовать интерфейс, вы можете:
- Внедрите его в код
- Создайте некоторые поведения, которые знают, как подключиться к ViewModel, который присутствует в DataContext.
Нет ничего плохого в реализации этого кода в коде, но подход к поведению позволяет использовать только XAML, если это важно для вас.
В реализации интерфейса вы можете использовать визуальное дерево, чтобы найти элемент управления, или вы могли бы просто закодировать оператор switch для известного набора объектов с возможностью фокусировки.