Установите фокус на текстовое поле в WPF из модели просмотра (C #)

У меня есть TextBox и Button на мой взгляд.

Теперь я проверяю условие при нажатии кнопки, и если условие оказывается ложным, отображает сообщение пользователю, а затем я должен установить курсор в элемент управления TextBox .

 if (companyref == null) { var cs = new Lipper.Nelson.AdminClient.Main.Views.ContactPanels.CompanyAssociation(); MessageBox.Show("Company does not exist.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation); cs.txtCompanyID.Focusable = true; System.Windows.Input.Keyboard.Focus(cs.txtCompanyID); } 

Вышеприведенный код находится в ViewModel.

CompanyAssociation – это имя вида.

Но курсор не устанавливается в TextBox .

Xaml:

  

Позвольте мне ответить на ваш вопрос в трех частях.

  1. Мне интересно, что такое «cs.txtCompanyID» в вашем примере? Это элемент управления TextBox? Если да, то вы ошибаетесь. Вообще говоря, неплохо иметь ссылку на пользовательский интерфейс в ViewModel. Вы можете спросить: «Почему?» но это еще один вопрос для публикации в Stackoverflow :).

  2. Лучший способ отслеживать проблемы с Focus – это … отладка исходного кода .Net. Без шуток. Это много раз меня спасало. Чтобы включить отладку исходного кода .net, см. Блог Shawn Bruke .

  3. Наконец, общий подход, который я использую для установки фокуса из ViewModel, – это Attached Properties. Я написал очень простое прикрепленное свойство, которое можно установить на любом UIElement. И это может быть связано с свойством ViewModel «IsFocused», например. Вот:

     public static class FocusExtension { public static bool GetIsFocused(DependencyObject obj) { return (bool) obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof (bool), typeof (FocusExtension), new UIPropertyMetadata(false, OnIsFocusedPropertyChanged)); private static void OnIsFocusedPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var uie = (UIElement) d; if ((bool) e.NewValue) { uie.Focus(); // Don't care about false values. } } } 

    Теперь в вашем представлении (в XAML) вы можете связать это свойство с ViewModel:

      

Надеюсь это поможет :). Если это не относится к ответу # 2.

Приветствия.

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

Во-первых, я изменил вышеупомянутое Attached Property следующим образом:

 public static class FocusExtension { public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusExtension), new FrameworkPropertyMetadata(IsFocusedChanged){BindsTwoWayByDefault = true}); public static bool? GetIsFocused(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (bool?)element.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject element, bool? value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(IsFocusedProperty, value); } private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var fe = (FrameworkElement)d; if (e.OldValue == null) { fe.GotFocus += FrameworkElement_GotFocus; fe.LostFocus += FrameworkElement_LostFocus; } if (!fe.IsVisible) { fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged); } if ((bool)e.NewValue) { fe.Focus(); } } private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { var fe = (FrameworkElement)sender; if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty)) { fe.IsVisibleChanged -= fe_IsVisibleChanged; fe.Focus(); } } private static void FrameworkElement_GotFocus(object sender, RoutedEventArgs e) { ((FrameworkElement)sender).SetValue(IsFocusedProperty, true); } private static void FrameworkElement_LostFocus(object sender, RoutedEventArgs e) { ((FrameworkElement)sender).SetValue(IsFocusedProperty, false); } } 

Моей причиной добавления ссылок на видимость были вкладки. Очевидно, если вы использовали прикрепленное свойство на любой другой вкладке вне первоначально видимой вкладки, прикрепленное свойство не сработало, пока вы вручную не сфокусировали элемент управления.

Другим препятствием было создание более элегантного способа сброса базового свойства на false, когда он потерял фокус. Вот тут-то и начались утраченные фокус-события.

  

Если есть лучший способ справиться с проблемой видимости, пожалуйста, дайте мне знать.

Примечание. Спасибо Apfelkuacha за предложение поместить BindsTwoWayByDefault в DependencyProperty. Я давно это сделал в своем собственном коде, но никогда не обновлял этот пост. Из-за этого изменения режим = TwoWay больше не нужен в коде WPF.

Я думаю, что лучший способ – сохранить принцип MVVM чистым, поэтому в основном вы должны использовать class Messenger, предоставляемый с MVVM Light, и вот как его использовать:

в вашей viewmodel (exampleViewModel.cs): напишите следующее

  Messenger.Default.Send("focus", "DoFocus"); 

теперь в вашем View.cs (а не XAML view.xaml.cs) напишите в конструкторе следующее:

  public MyView() { InitializeComponent(); Messenger.Default.Register(this, "DoFocus", doFocus); } public void doFocus(string msg) { if (msg == "focus") this.txtcode.Focus(); } 

этот метод отлично работает и с меньшим количеством кода и поддержкой стандартов MVVM

Ни одно из них не работало для меня точно, но на благо других, это то, что я закончил писать, основываясь на некотором коде, уже представленном здесь.

Использование было бы следующим:

  

И реализация будет следующей:

 ///  /// Behavior allowing to put focus on element from the view model in a MVVM implementation. ///  public static class FocusBehavior { #region Dependency Properties ///  /// IsFocused dependency property. ///  public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged)); ///  /// Gets the IsFocused property value. ///  /// The element. /// Value of the IsFocused property or null if not set. public static bool? GetIsFocused(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (bool?)element.GetValue(IsFocusedProperty); } ///  /// Sets the IsFocused property value. ///  /// The element. /// The value. public static void SetIsFocused(DependencyObject element, bool? value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(IsFocusedProperty, value); } #endregion Dependency Properties #region Event Handlers ///  /// Determines whether the value of the dependency property IsFocused has change. ///  /// The dependency object. /// The  instance containing the event data. private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Ensure it is a FrameworkElement instance. var fe = d as FrameworkElement; if (fe != null && e.OldValue == null && e.NewValue != null && (bool)e.NewValue) { // Attach to the Loaded event to set the focus there. If we do it here it will // be overridden by the view rendering the framework element. fe.Loaded += FrameworkElementLoaded; } } ///  /// Sets the focus when the framework element is loaded and ready to receive input. ///  /// The sender. /// The  instance containing the event data. private static void FrameworkElementLoaded(object sender, RoutedEventArgs e) { // Ensure it is a FrameworkElement instance. var fe = sender as FrameworkElement; if (fe != null) { // Remove the event handler registration. fe.Loaded -= FrameworkElementLoaded; // Set the focus to the given framework element. fe.Focus(); // Determine if it is a text box like element. var tb = fe as TextBoxBase; if (tb != null) { // Select all text to be ready for replacement. tb.SelectAll(); } } } #endregion Event Handlers } 

Это старый stream, но, похоже, нет ответа с кодом, который решает проблемы с принятым ответом Анаванки: он не работает, если вы установили свойство в viewmodel в false или если вы установили свое свойство в true, пользователь вручную нажимает на что-то еще, а затем снова устанавливает значение true. Я не мог заставить решение Zamotic надежно работать и в этих случаях.

Объясняя некоторые из приведенных выше обсуждений, я даю код ниже, который затрагивает эти проблемы, я думаю:

 public static class FocusExtension { public static bool GetIsFocused(DependencyObject obj) { return (bool)obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof(bool), typeof(FocusExtension), new UIPropertyMetadata(false, null, OnCoerceValue)); private static object OnCoerceValue(DependencyObject d, object baseValue) { if ((bool)baseValue) ((UIElement)d).Focus(); else if (((UIElement) d).IsFocused) Keyboard.ClearFocus(); return ((bool)baseValue); } } 

Сказав это, это все еще сложно для чего-то, что можно сделать в одной строке в коде, и CoerceValue на самом деле не предназначен для использования таким образом, поэтому, возможно, codebehind – это путь.

В моем случае FocusExtension не работал, пока не изменил метод OnIsFocusedPropertyChanged. Первоначальный работал только в отладке, когда точка останова остановила процесс. Во время выполнения процесс слишком быстрый, и ничего не происходит. Благодаря этой небольшой модификации и помощи нашей дружной задачи это прекрасно работает в обоих сценариях.

 private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var uie = (UIElement)d; if ((bool)e.NewValue) { var action = new Action(() => uie.Dispatcher.BeginInvoke((Action)(() => uie.Focus()))); Task.Factory.StartNew(action); } } 

Яркий код Anvakas предназначен для приложений Windows Desktop. Если вы похожи на меня и нуждаетесь в том же решении для приложений Windows Store, этот код может быть удобным:

 public static class FocusExtension { public static bool GetIsFocused(DependencyObject obj) { return (bool)obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof(bool), typeof(FocusExtension), new PropertyMetadata(false, OnIsFocusedPropertyChanged)); private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue) { var uie = d as Windows.UI.Xaml.Controls.Control; if( uie != null ) { uie.Focus(FocusState.Programmatic); } } } } 

Проблема в том, что как только значение IsUserNameFocused установлено равным true, оно никогда не будет ложным. Это решает его, обращаясь к GotFocus и LostFocus для элемента FrameworkElement.

У меня возникли проблемы с форматированием исходного кода, так что вот ссылка

Для тех, кто пытается использовать решение Anvaka выше, у меня были проблемы с привязкой, работающие только в первый раз, так как lostfocus не обновлял свойство до false. Вы можете вручную установить свойство в false, а затем true каждый раз, но лучшим решением может быть сделать что-то подобное в вашем свойстве:

 bool _isFocused = false; public bool IsFocused { get { return _isFocused ; } set { _isFocused = false; _isFocused = value; base.OnPropertyChanged("IsFocused "); } } 

Таким образом, вам только нужно установить его в true, и он будет сосредоточен.

Я использую WPF / Caliburn Micro a, что «dfaivre» сделал общее и работоспособное решение здесь: http://caliburnmicro.codeplex.com/discussions/222892

Я нашел решение Crucial для проблемы IsVisible очень полезным. Это не полностью решило мою проблему, но какой-то дополнительный код, следующий за тем же шаблоном для шаблона IsEnabled.

Для метода IsFocusedChanged я добавил:

  if (!fe.IsEnabled) { fe.IsEnabledChanged += fe_IsEnabledChanged; } 

И вот обработчик:

 private static void fe_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { var fe = (FrameworkElement)sender; if (fe.IsEnabled && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty)) { fe.IsEnabledChanged -= fe_IsEnabledChanged; fe.Focus(); } } 

Для Silverlight:

 using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; namespace MyProject.Behaviors { public class FocusBehavior : Behavior { protected override void OnAttached() { this.AssociatedObject.Loaded += AssociatedObject_Loaded; base.OnAttached(); } private void AssociatedObject_Loaded(object sender, RoutedEventArgs e) { this.AssociatedObject.Loaded -= AssociatedObject_Loaded; if (this.HasInitialFocus || this.IsFocused) { this.GotFocus(); } } private void GotFocus() { this.AssociatedObject.Focus(); if (this.IsSelectAll) { if (this.AssociatedObject is TextBox) { (this.AssociatedObject as TextBox).SelectAll(); } else if (this.AssociatedObject is PasswordBox) { (this.AssociatedObject as PasswordBox).SelectAll(); } else if (this.AssociatedObject is RichTextBox) { (this.AssociatedObject as RichTextBox).SelectAll(); } } } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.Register( "IsFocused", typeof(bool), typeof(FocusBehavior), new PropertyMetadata(false, (d, e) => { if ((bool)e.NewValue) { ((FocusBehavior)d).GotFocus(); } })); public bool IsFocused { get { return (bool)GetValue(IsFocusedProperty); } set { SetValue(IsFocusedProperty, value); } } public static readonly DependencyProperty HasInitialFocusProperty = DependencyProperty.Register( "HasInitialFocus", typeof(bool), typeof(FocusBehavior), new PropertyMetadata(false, null)); public bool HasInitialFocus { get { return (bool)GetValue(HasInitialFocusProperty); } set { SetValue(HasInitialFocusProperty, value); } } public static readonly DependencyProperty IsSelectAllProperty = DependencyProperty.Register( "IsSelectAll", typeof(bool), typeof(FocusBehavior), new PropertyMetadata(false, null)); public bool IsSelectAll { get { return (bool)GetValue(IsSelectAllProperty); } set { SetValue(IsSelectAllProperty, value); } } } } 

LoginViewModel.cs:

  public class LoginModel : ViewModelBase { .... private bool _EmailFocus = false; public bool EmailFocus { get { return _EmailFocus; } set { if (value) { _EmailFocus = false; RaisePropertyChanged("EmailFocus"); } _EmailFocus = value; RaisePropertyChanged("EmailFocus"); } } ... } 

Login.xaml:

 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:beh="clr-namespace:MyProject.Behaviors"      

ИЛИ

      

Чтобы установить фокус, нужно просто сделать это в коде:

 EmailFocus = true; 

Помните, что этот плагин является частью html-страницы, поэтому другие элементы управления на странице могут иметь фокус

 if (!Application.Current.IsRunningOutOfBrowser) { System.Windows.Browser.HtmlPage.Plugin.Focus(); } 

Вы можете использовать шаблон проектирования ViewCommand . Он описывает метод для шаблона проектирования MVVM для управления представлением ViewModel с помощью команд.

Я реализовал его на основе предложения короля А. Маджида использовать class MVVM Light Messenger. Класс ViewCommandManager обрабатывает вызовы команд в подключенных представлениях. Это в основном другое направление регулярных команд, для таких случаев, когда ViewModel должен выполнять некоторые действия в своем представлении. Он использует reflection, подобное командам, связанным с данными, и WeakReferences, чтобы избежать утечек памяти.

http://dev.unclassified.de/source/viewcommand (также опубликовано в CodeProject)

Я нашел решение, отредактировав код в соответствии со следующим. Нет необходимости устанавливать свойство Binding сначала False, затем True.

 public static class FocusExtension { public static bool GetIsFocused(DependencyObject obj) { return (bool)obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof(bool), typeof(FocusExtension), new UIPropertyMetadata(false, OnIsFocusedPropertyChanged)); private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d != null && d is Control) { var _Control = d as Control; if ((bool)e.NewValue) { // To set false value to get focus on control. if we don't set value to False then we have to set all binding //property to first False then True to set focus on control. OnLostFocus(_Control, null); _Control.Focus(); // Don't care about false values. } } } private static void OnLostFocus(object sender, RoutedEventArgs e) { if (sender != null && sender is Control) { (sender as Control).SetValue(IsFocusedProperty, false); } } } 

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

XAML

    

ViewModel

  public class LoginModel : ViewModelBase { public string txtLabel_IsFocused { get; set; } public string butEdit_IsEnabled { get; set; } public void SetProperty(string PropertyName, string value) { System.Reflection.PropertyInfo propertyInfo = this.GetType().GetProperty(PropertyName); propertyInfo.SetValue(this, Convert.ChangeType(value, propertyInfo.PropertyType), null); OnPropertyChanged(PropertyName); } private void Example_function(){ SetProperty("butEdit_IsEnabled", "False"); SetProperty("txtLabel_IsFocused", "True"); } } 

Прежде всего, я хотел бы поблагодарить Avanka за помощь в решении моей проблемы с фокусом. Тем не менее, есть ошибка в коде, который он опубликовал, а именно в строке: if (e.OldValue == null)

Проблема была в том, что если вы сначала нажмете на свое мнение и сфокусируете элемент управления, e.oldValue больше не является нулевым. Затем, когда вы устанавливаете переменную, чтобы сфокусировать управление в первый раз, это приводит к тому, что обработчики lostfocus и gotfocus не устанавливаются. Мое решение было следующим:

 public static class ExtensionFocus { static ExtensionFocus() { BoundElements = new List(); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(ExtensionFocus), new FrameworkPropertyMetadata(false, IsFocusedChanged)); private static List BoundElements; public static bool? GetIsFocused(DependencyObject element) { if (element == null) { throw new ArgumentNullException("ExtensionFocus GetIsFocused called with null element"); } return (bool?)element.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject element, bool? value) { if (element == null) { throw new ArgumentNullException("ExtensionFocus SetIsFocused called with null element"); } element.SetValue(IsFocusedProperty, value); } private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var fe = (FrameworkElement)d; // OLD LINE: // if (e.OldValue == null) // TWO NEW LINES: if (BoundElements.Contains(fe.Name) == false) { BoundElements.Add(fe.Name); fe.LostFocus += OnLostFocus; fe.GotFocus += OnGotFocus; } if (!fe.IsVisible) { fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged); } if ((bool)e.NewValue) { fe.Focus(); } } private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { var fe = (FrameworkElement)sender; if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty)) { fe.IsVisibleChanged -= fe_IsVisibleChanged; fe.Focus(); } } private static void OnLostFocus(object sender, RoutedEventArgs e) { if (sender != null && sender is Control s) { s.SetValue(IsFocusedProperty, false); } } private static void OnGotFocus(object sender, RoutedEventArgs e) { if (sender != null && sender is Control s) { s.SetValue(IsFocusedProperty, true); } } } 

Просто сделайте это:

    ... 
 public class DummyViewModel : ViewModelBase { private bool isfocused= false; public bool IsFocused { get { return isfocused; } set { isfocused= value; OnPropertyChanged("IsFocused"); } } } 
 System.Windows.Forms.Application.DoEvents(); Keyboard.Focus(tbxLastName); 
  • Использование диспетчера C #
  • Как я могу привязать данные строк к ListBox в WPF / WP7?
  • WPF - Как создать меню и подменю, используя привязку
  • Могут ли привязки создавать утечки памяти в WPF?
  • Использование MediaElement для воспроизведения видео из Stream
  • Что означает эта ошибка WCF: «Предупреждение о настраиваемом инструменте: невозможно импортировать wsdl: portType»
  • Почему я не могу ссылаться на System.ComponentModel.DataAnnotations?
  • Как я могу использовать RelayCommand в wpf?
  • Можно ли реализовать гладкую прокрутку в виде списка WPF?
  • WPF: слайдер с событием, которое запускается после того, как пользователь перетаскивает
  • Как разместить содержимое WPF в приложениях MFC?
  • Interesting Posts

    Как я могу форматировать номер строки, чтобы иметь запятые и круглые?

    Могу ли я заставить свой ноутбук использовать NVIDIA вместо Intel?

    Конвертировать несколько валют в usd без использования vlookup

    IOS 9 Error Domain = kCLErrorDomain Code = 0 “(null)”

    Закрыть диалог при нажатии (в любом месте)

    jQuery mobile – для каждого события прямого трансляционного события должно существовать эквивалентное событие click?

    Как вставить изображение в Excel в указанной ячейке с помощью VBA

    Регулярные выражения и GWT

    Найти повторяющиеся значения в R

    Можно ли использовать ShowDialog без блокировки всех форм?

    Любые известные «gotchas» с Vista & eSATA?

    Как открыть консольное приложение с заданным размером окна?

    Являются ли выражения Java Lambda выражения «скрытыми» или локальными пакетами?

    Могу ли я служить .html-файлами с помощью Razor, как если бы они были .cshtml-файлами без изменения расширения всех моих страниц?

    Есть ли в .NET математический оценщик строк?

    Давайте будем гением компьютера.