Встановіть фокус на TextBox у WPF від перегляду моделі


129

Я маю 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 є:

<igEditors:XamTextEditor Name="txtCompanyID" 
                         KeyDown="xamTextEditorAllowOnlyNumeric_KeyDown"
                         ValueChanged="txtCompanyID_ValueChanged"
                         Text="{Binding Company.CompanyId,
                                        Mode=TwoWay,
                                        UpdateSourceTrigger=PropertyChanged}"
                         Width="{Binding ActualWidth, ElementName=border}"
                         Grid.Column="1" Grid.Row="0"
                         VerticalAlignment="Top"
                         HorizontalAlignment="Stretch"
                         Margin="0,5,0,0"
                         IsEnabled="{Binding Path=IsEditable}"/>

<Button Template="{StaticResource buttonTemp1}"
        Command="{Binding ContactCommand}"
        CommandParameter="searchCompany"
        Content="Search"
        Width="80"
        Grid.Row="0" Grid.Column="2"
        VerticalAlignment="Top"
        Margin="0"
        HorizontalAlignment="Left"
        IsEnabled="{Binding Path=IsEditable}"/>

Якщо ви використовуєте caliburn.micro, це відмінне рішення.
matze8426

Відповіді:


264

Дозвольте відповісти на ваше запитання в трьох частинах.

  1. Мені цікаво, що у вашому прикладі "cs.txtCompanyID"? Це управління TextBox? Якщо так, то ви не в тому напрямку. Взагалі кажучи, це не дуже гарна ідея мати посилання на інтерфейс користувача у своєму ViewModel. Ви можете запитати "Чому?" але це ще одне питання, яке слід опублікувати на Stackoverflow :).

  2. Найкращий спосіб відстежити проблеми з Фокусом - це налагодження .Net вихідного коду. Без жартів. Це багато разів економило мене. Щоб увімкнути налагодження .net вихідного коду, зверніться до блогу Шона Брука .

  3. Нарешті, загальний підхід, який я використовую для встановлення фокусу з ViewModel, - «Вкладені властивості». Я написав дуже просту додану властивість, яку можна встановити на будь-якому 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:

    <TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />

Сподіваюся, це допомагає :). Якщо це не стосується відповіді №2.

Ура.


5
Класна ідея. Мені потрібно встановити IsUserNameFocused на істинний, а потім знову на помилковий, щоб це працювало, чи правильно це?
Сем

19
Ви також повинні зателефонувати Keyboard.Focus(uie);зі своєї OnIsFocusedPropertyChangedподії, якщо ви хочете, щоб ваш контроль отримав фокус на клавіатурі, а також логічний фокус
Рейчел

6
Як це слід використовувати? Якщо я встановив властивість на істинне, контроль буде зосереджено. Але це завжди буде зосереджено знову, коли я повернусь до цього погляду. Якщо скинути його з OnIsFocusedPropertyChanged, це не змінить. Скидання його безпосередньо після встановлення з ViewModel більше нічого не фокусує. Це не працює. Що саме зробили ці 70 учасників?
ygoe

4
Я також змінив зворотний виклик на це: ...if ((bool)e.NewValue && uie.Dispatcher != null) { uie.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => uie.Focus())); // invoke behaves nicer, if e.g. you have some additional handler attached to 'GotFocus' of UIE. uie.SetValue(IsFocusedProperty, false); // reset bound value if possible, to allow setting again ... Іноді мені навіть доводиться скидати "IsFocused" на false у ViewModel, якщо я хочу встановити фокус кілька разів. Але тоді це працює, де деякі інші методи провалилися.
Саймон Д.

3
після того, як ви встановите фокус і інший елемент отримує фокус, знову встановити фокус не буде працювати, оскільки IsFocused все ще відповідає дійсності. Потрібно примусити його до помилкового, а потім істинного. public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
walterhuang

75

Я знаю, що на це питання вже відповіли тисячу разів, але я внесла деякі зміни в внесок Анвака, що, на мою думку, допоможе іншим, у кого були подібні проблеми, як у мене.

По-перше, я змінив вищезазначене додане властивість так:

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);
    }
}

Моєю причиною додавання посилань на видимість були вкладки. Мабуть, якщо ви використовували додане властивість на будь-якій іншій вкладці поза спочатку видимою вкладкою, додане властивість не працювало, поки ви вручну не сфокусували елемент керування.

Іншою перешкодою було створення більш елегантного способу скидання базової властивості до хибного, коли воно втрачало фокус. Ось де і потрапили втрачені фокусні події.

<TextBox            
    Text="{Binding Description}"
    FocusExtension.IsFocused="{Binding IsFocused}"/>

Якщо є кращий спосіб вирішити питання про видимість, будь ласка, повідомте мене про це.

Примітка: Дякую Apfelkuacha за пропозицію розмістити BindsTwoWayByDefault у властивості DependencyProperty. Я це робив давно у власному коді, але ніколи не оновлював цю посаду. Режим = TwoWay більше не потрібен в коді WPF через цю зміну.


9
Це добре працює для мене, за винятком того, що мені потрібно додати прапорець "if (e.Source == e.OriginalSource)" у GotFocus / LostFocus або інакше він stackoverflow (буквально) при використанні в моєму UserControl, який перенаправляє фокус на внутрішній компонент. Я видалив чеки Visible, прийнявши той факт, що він працює так само, як метод. Фокус (). Якщо. Фокус () не працює, прив'язка не повинна працювати - і це нормально для мого сценарію.
HelloSam

1
Я використовую це в WF 4.5. У IsFocusedChanged у мене є сценарій (активність перезавантажується), де e.NewValue є недійсним і видає виняток, тому перевірте це спочатку. З цією незначною зміною все працює добре.
Олару Мірча

1
Спасибі цьому wprks Чудово :) Я щойно додав "{BindsTwoWayByDefault = true}" у "FrameworkPropertyMetadata", щоб встановити режим за замовчуванням на TwoWayBinding, тому він потрібен не для кожного прив'язки
R00st3r

1
Я усвідомлюю, що це стара відповідь, але я стикаюся з ситуацією, коли властивість IsEnabled управління, на яку я хочу перенести фокус, прив’язане до багатозначного перетворювача. Мабуть, обробник подій GotFocus отримує виклик до того, як перетворювач багатозначного значення зробить ... а це означає, що керування в цій точці буде відключене, тож як тільки GotFocus завершується, LostFocus отримує виклик (я думаю, оскільки управління все ще вимкнено) . Будь-які думки, як з цим впоратися?
Марк Олберт

1
@MarkOlbert використовує fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);те, що він оновлюється після завантаження. Більше інформації тут: telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q
Apfelkuacha

32

Я думаю, що найкращим способом є збереження принципу MVVM в чистоті, тому в основному ви повинні використовувати клас Messenger, наданий світлом MVVM, і ось як його використовувати:

у своїй моделі перегляду (exampleViewModel.cs): напишіть наступне

 Messenger.Default.Send<string>("focus", "DoFocus");

тепер у свій View.cs (не XAML the view.xaml.cs) напишіть наступне в конструкторі

 public MyView()
        {
            InitializeComponent();

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

цей метод володіє просто чудово і з меншим кодом та підтриманням стандартів MVVM


9
Добре, якщо ви хочете зберегти принцип чистоти MVVM, ви б не писали код у своєму коді в першу чергу. Я вважаю, що підхідний майновий підхід набагато чистіший. Він також не вводить багато магічних рядків у вашу модель перегляду.
Ε Г І І І О

32
Ель Ніно: Звідки ви точно взяли ідею, що у коду зору не повинно бути нічого? Все, що стосується інтерфейсу користувача, повинно бути поза кодом представлення даних. Налаштування фокусу елементів інтерфейсу користувача, безумовно, повинно бути позаду коду подання. Нехай viewmodel розібрається, коли надсилати повідомлення; нехай перегляд визначить, що робити з повідомленням. Ось що робить MV-VM: розділяє проблеми моделі даних, ділової логіки та інтерфейсу користувача.
Кайл Хейл

На основі цієї пропозиції я реалізував власний ViewCommandManager, який обробляє виклики команд у підключених представленнях. Це в основному інший напрямок звичайних команд, для цих випадків, коли ViewModel повинен виконати певні дії у своїх переглядах. Для уникнення витоків пам’яті використовується відображення на зразок команд, пов'язаних з даними та WeakReferences. dev.unclassified.de/source/viewcommand (також у CodeProject)
ygoe

Я використовував цей метод для друку WPF FlowDocuments. Працювали чудово. Спасибі
Гордон Слайз

Я хочу його в Silverlight? Чи можемо ми ним скористатися?
Bigeyes

18

Жодне з них не працювало для мене точно, але на користь інших, це я закінчив писати на основі деякого коду, який уже надано тут.

Використання було б таким:

<TextBox ... h:FocusBehavior.IsFocused="True"/>

А реалізація була б така:

/// <summary>
/// Behavior allowing to put focus on element from the view model in a MVVM implementation.
/// </summary>
public static class FocusBehavior
{
    #region Dependency Properties
    /// <summary>
    /// <c>IsFocused</c> dependency property.
    /// </summary>
    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
            typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged));
    /// <summary>
    /// Gets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <returns>Value of the <c>IsFocused</c> property or <c>null</c> if not set.</returns>
    public static bool? GetIsFocused(DependencyObject element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        return (bool?)element.GetValue(IsFocusedProperty);
    }
    /// <summary>
    /// Sets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <param name="value">The value.</param>
    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
    /// <summary>
    /// Determines whether the value of the dependency property <c>IsFocused</c> has change.
    /// </summary>
    /// <param name="d">The dependency object.</param>
    /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    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;
        }
    }
    /// <summary>
    /// Sets the focus when the framework element is loaded and ready to receive input.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
    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
}

11

Це стара тема, але, схоже, немає відповіді з кодом, який вирішує проблеми з прийнятою відповіддю Анаванки: вона не працює, якщо ви встановите властивість у вигляд-моделі на хибну чи якщо ви встановите для власності правда, користувач вручну клацає щось інше, а потім ви знову встановлюєте це значення 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, 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 насправді не призначений для використання таким чином, тому, можливо, кодекс позаду - це шлях.


1
Це працює послідовно, тоді як прийнята відповідь ні. Дякую!
NathanAldenSr

4

У моєму випадку 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);
  }
}

3

Проблема полягає в тому, що як тільки IsUserNameFocused буде встановлено на true, воно ніколи не буде помилковим. Це вирішує це, обробляючи GotFocus та LostFocus для FrameworkElement.

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


1
Я змінив "об'єкт fe = (FrameworkElement) d;" до "FrameworkElement fe = (FrameworkElement) d;" тож intellisense працює

Досі проблема не вирішує. Елемент залишається зосередженим кожен раз, коли я повертаюся до нього.
ygoe

3

Блискучий код 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);
            }
        }
    }
}

1

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

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

Таким чином, вам потрібно коли-небудь встановити його як істинне, і воно отримає фокус.


Чому ви маєте заяву if? _isFocused, коли встановлено значення false, буде просто змінено на значення в наступному рядку.
Демієн Макгіверн

1
@Tyrsius Ви можете вирішити цю проблему, отримавши властивість залежності до Coerce, дивіться тут- social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
RichardOD


1

Я знайшов рішення шляхом редагування коду, як описано нижче. Не потрібно встановлювати властивість 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);
        }
    }
}

0

Для Silverlight:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace MyProject.Behaviors
{
    public class FocusBehavior : Behavior<Control>
    {
        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"

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior IsFocused="{Binding EmailFocus}" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

АБО

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior HasInitialFocus="True" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

Щоб встановити фокус, слід просто зробити це в коді:

EmailFocus = true;

Пам'ятайте, що цей плагін є частиною html-сторінки, тому інші елементи керування на цій сторінці можуть бути зосереджені

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

0

Ви можете використовувати шаблон дизайну ViewCommand . Він описує метод для схеми дизайну MVVM для управління видом з ViewModel за допомогою команд.

Я реалізував його на основі пропозиції короля А.Маджида використовувати клас MVVM Light Messenger. Клас ViewCommandManager обробляє виклики команд у підключених представленнях. Це в основному інший напрямок звичайних команд, для цих випадків, коли ViewModel повинен виконати певні дії у своєму представленні. Для уникнення витоків пам’яті використовується відображення на зразок команд, пов'язаних з даними та WeakReferences.

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


0

Здається, ніхто не включив останній крок, щоб полегшити оновлення атрибутів через прив'язані змінні. Ось що я придумав. Дайте мені знати, чи є кращий спосіб зробити це.

XAML

    <TextBox x:Name="txtLabel"
      Text="{Binding Label}"
      local:FocusExtension.IsFocused="{Binding txtLabel_IsFocused, Mode=TwoWay}" 
     />

    <Button x:Name="butEdit" Content="Edit"
        Height="40"  
        IsEnabled="{Binding butEdit_IsEnabled}"                        
        Command="{Binding cmdCapsuleEdit.Command}"                            
     />   

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");        
    }

    }

0

По-перше, я хотів би подякувати Аванці за те, що він допомагає мені вирішити свою проблему з фокусом. Однак у коді, який він опублікував, є помилка, а саме в рядку: if (e.OldValue == null)

Проблема в мене полягала в тому, що якщо ви вперше натисніть на свій погляд і сфокусуєте елемент керування, e.oldValue вже не буде нульовим. Потім, коли ви встановлюєте змінну для фокусування керування вперше, це призводить до того, що обробники Lostfocus та gotfocus не будуть встановлені. Моє рішення для цього було таким:

public static class ExtensionFocus
    {
    static ExtensionFocus()
        {
        BoundElements = new List<string>();
        }

    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
        typeof(ExtensionFocus), new FrameworkPropertyMetadata(false, IsFocusedChanged));

    private static List<string> 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);
            }
        }
    }

0

Просто зробіть це:

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...

Мені подобається це. Це добре працює, якщо ви хочете встановити початковий фокус.
користувач2430797

0

Після втілення прийнятої відповіді я зіткнувся з проблемою, яка під час навігації в поглядах за допомогою призми TextBox все ще не буде зосереджена. Незначна зміна обробника PropertyChanged вирішила це

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

0

Альтернативний підхід, заснований на @Sheridan відповіді тут

 <TextBox Text="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <TextBox.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SomeTextIsFocused, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
                        <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>

У моделі перегляду налаштуйте прив’язку звичайним способом, а потім встановіть SomeTextIsFocused на істинний, щоб встановити фокус на текстовому полі


-1

я знайшов вирішальне для вирішення проблеми 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();
    }
}

-1
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }

-7
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);

1
ОП використовує WPF. Код фокусування для WinForms не допоможе.
Джош Г
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.