WPF的TextBox获得焦点时自动全部选择已有内容的方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiuzaizuotian2014/article/details/81868842

TextBox元素获得焦点时,可以用SelectAll()来选择已有文字,但不能直接用SelectAll()就得到想要的效果。其中一种方式是通过PreviewMouseDown\GotFocus\LostFocus的多个事件来完成,逻辑有些繁琐。每次都写这些就造成代码重复,因此我写了一个附加属性类来解决这个问题。

本文利用创建的WPF附加属性来获得该功能:即在Text获得焦点的时候,全部选择textbox中已经存在的内容。

    /// <summary>
    /// 当 TextBoxBase获得焦点的时候,自动全部选择文字。附加属性为SelectAllWhenGotFocus,类型为bool.
    /// </summary>
    public class TextBoxAutoSelectHelper
    {
        public static readonly DependencyProperty SelectAllWhenGotFocusProperty =DependencyProperty.RegisterAttached("SelectAllWhenGotFocus", 
                            typeof(bool), typeof(TextBoxAutoSelectHelper),
                            new FrameworkPropertyMetadata((bool)false,new PropertyChangedCallback(OnSelectAllWhenGotFocusChanged)));

        public static bool GetSelectAllWhenGotFocus(TextBoxBase d)
        {
            return (bool)d.GetValue(SelectAllWhenGotFocusProperty);
        }
        public static void SetSelectAllWhenGotFocus(TextBoxBase d, bool value)
        {
            d.SetValue(SelectAllWhenGotFocusProperty, value);
        }

        private static void OnSelectAllWhenGotFocusChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs e)
        {
            if (dependency is TextBoxBase tBox)
            {
                var isSelectedAllWhenGotFocus = (bool)e.NewValue;
                if (isSelectedAllWhenGotFocus)
                {
                    tBox.PreviewMouseDown += TextBoxPreviewMouseDown;
                    tBox.GotFocus += TextBoxOnGotFocus;
                    tBox.LostFocus += TextBoxOnLostFocus;
                }
                else
                {
                    tBox.PreviewMouseDown -= TextBoxPreviewMouseDown;
                    tBox.GotFocus -= TextBoxOnGotFocus;
                    tBox.LostFocus -= TextBoxOnLostFocus;
                }
            }
        }
        private static void TextBoxOnGotFocus(object sender, RoutedEventArgs e)
        {
            if (sender is TextBoxBase tBox)
            {
                tBox.SelectAll();
                tBox.PreviewMouseDown -= TextBoxPreviewMouseDown;
            }

        }
        private static void TextBoxPreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (sender is TextBoxBase tBox)
            {
                tBox.Focus();
                e.Handled = true;
            }
        }

        private static void TextBoxOnLostFocus(object sender, RoutedEventArgs e)
        {
  
            if (sender is TextBoxBase tBox)
            {
                tBox.PreviewMouseDown += TextBoxPreviewMouseDown;
            }

        }
    }

使用方法如下:

(1)使用Style,以下是直接放在元素中的,更直接的放在窗口的资源中,或资源字典中

            <TextBox Text="{Binding xxx}">
               <TextBox.Style>
                   <Style TargetType = "TextBox" >
                      < Setter Property="local:TextBoxAutoSelectHelper.SelectAllWhenGotFocus" Value="True"/>
                  </Style>
               </TextBox.Style>
           </TextBox>

(2)或者直接使用元素的附加属性

 <TextBox local:TextBoxAutoSelectHelper.SelectAllWhenGotFocus="True"  Text="{Binding xxx}"/>

---->以上两种使用方法中的local都是代表命名空间的,具体根据实际情况即可。

补充:

(1)对于TextBox,如果之间没有获得焦点,然后要通过鼠标单击来获得焦点,其处理过程表现为:鼠标单击TextBox时,会首先产生PreviewMouseDown事件,处理完PreviewMouseDown事件后,TextBox会获得焦点并进一步产生GotFocus事件。如果在PreviewMouseDown中禁止掉事件进一步传播(e.Handle=true),那么TextBox就不会获得焦点,也不会激发GotFocus事件及其它后续事件。

(2)TextBox的先后产生的与鼠标点击有关的事件包括:PreviewMouseDown,GotFocus,PreviewMouseUp,MouseUp;对于我们想象中应该产生的MouseDown事件,测试过程中无论怎么做都没有激发MouseDown事件。建议尽量不使用PreviewMouseUp和MouseUp事件,其原因如下第(3)和第(4)条所示。

(3)对于TextBox的PreviewMouseUp事件,不建议使用,可能时BUG还是怎么回事。用了以后,整个界面点击任何位置,都只响应该TextBox的事件,其它事件都无法响应了。及时点击关闭窗口的按钮,也是仅仅响应该TextBox的事件,窗口都关闭不了。个人认为是Bug,不知道理解是否正确。

(4)对于TextBox的MouseUp事件,在测试过程中,有时是正常激发的,有时必须要点击TextBox的边框附近才会激发,而点击TextBox的内部不会激发。下图是官方文档中关于Mouse事件的说明:

(5)对于直接使用GotFocus事件来SelectAll()之所以不成功,个人理解是因为:在PreviewMouseDown事件传输过程中,TextBox先获得了焦点,并激发GotFocus事件。然后PreviewMouseDown会进一步向内传输,在此过程中TextBox还会进一步处理鼠标位置信息,并设置光标位置。正因为设置了光标的位置,这又会导致已经选择的文本被取消选择了。所以,为了获得自动选择文字的功能,就在PreviewMouseDown中主动SetFocus(注:这回激发GotFocus事件,在事件处理方法中SelectAll()),并禁止PreviewMouseDown事件进一步向TextBox的更深层次元素传播(e.Handled=true)。

(以上一些结论是根据现象推理的,由于水平有限,如有不准确,还请读者见谅)

猜你喜欢

转载自blog.csdn.net/jiuzaizuotian2014/article/details/81868842