Set focus on TextBox in WPF from view model

后端 未结 21 2237
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 06:21

I have a TextBox and a Button in my view.

Now I am checking a condition upon button click and if the condition turns out to be false, displ

相关标签:
21条回答
  • 2020-11-22 06:51

    I know this question has been answered a thousand times over by now, but I made some edits to Anvaka's contribution that I think will help others that had similar issues that I had.

    Firstly, I changed the above Attached Property like so:

    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 (e.NewValue != null && (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);
        }
    }
    

    My reason for adding the visibility references were tabs. Apparently if you used the attached property on any other tab outside of the initially visible tab, the attached property didn't work until you manually focused the control.

    The other obstacle was creating a more elegant way of resetting the underlying property to false when it lost focus. That's where the lost focus events came in.

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

    If there's a better way to handle the visibility issue, please let me know.

    Note: Thanks to Apfelkuacha for the suggestion of putting the BindsTwoWayByDefault in the DependencyProperty. I had done that long ago in my own code, but never updated this post. The Mode=TwoWay is no longer necessary in the WPF code due to this change.

    0 讨论(0)
  • 2020-11-22 06:51

    None of these worked for me exactly, but for the benefit of others, this is what I ended up writing based on some of the code already provided here.

    Usage would be as follows:

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

    And the implementation would be as follows:

    /// <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
    }
    
    0 讨论(0)
  • 2020-11-22 06:52

    The problem is that once the IsUserNameFocused is set to true, it will never be false. This solves it by handling the GotFocus and LostFocus for the FrameworkElement.

    I was having trouble with the source code formatting so here is a link

    0 讨论(0)
  • 2020-11-22 06:54

    For 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>
    

    OR

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

    To set the focus should just do it in code:

    EmailFocus = true;
    

    Remember that this plugin is part of an html page, so other controls in the page might have the focus

    if (!Application.Current.IsRunningOutOfBrowser)
    {
        System.Windows.Browser.HtmlPage.Plugin.Focus();
    }
    
    0 讨论(0)
  • 2020-11-22 06:54

    First off i would like to thank Avanka for helping me solve my focus problem. There is however a bug in the code he posted, namely in the line: if (e.OldValue == null)

    The problem I had was that if you first click in your view and focus the control, e.oldValue is no longer null. Then when you set the variable to focus the control for the first time, this results in the lostfocus and gotfocus handlers not being set. My solution to this was as follows:

    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 讨论(0)
  • 2020-11-22 06:54
    System.Windows.Forms.Application.DoEvents();
    Keyboard.Focus(tbxLastName);
    
    0 讨论(0)
提交回复
热议问题