.net 如何在 WPF TextBox 中自动选择焦点上的所有文本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/660554/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to automatically select all text on focus in WPF TextBox?
提问by Sergey Aldoukhov
If I call SelectAllfrom a GotFocusevent handler, it doesn't work with the mouse - the selection disappears as soon as mouse is released.
如果我SelectAll从GotFocus事件处理程序调用,它不适用于鼠标 - 一旦释放鼠标,选择就会消失。
EDIT: People are liking Donnelle's answer, I'll try to explain why I did not like it as much as the accepted answer.
编辑:人们喜欢 Donnelle 的回答,我将尝试解释为什么我不像接受的答案那样喜欢它。
- It is more complex, while the accepted answer does the same thing in a simpler way.
- The usability of accepted answer is better. When you click in the middle of the text, text gets unselected when you release the mouse allowing you to start editing instantly, and if you still want to select all, just press the button again and this time it will not unselect on release. Following Donelle's recipe, if I click in the middle of text, I have to click second time to be able to edit. If I click somewhere within the text versus outside of the text, this most probably means I want to start editing instead of overwriting everything.
- 它更复杂,而接受的答案以更简单的方式做同样的事情。
- 接受的答案的可用性更好。当您单击文本中间时,当您松开鼠标时文本将被取消选择,允许您立即开始编辑,如果您仍想全选,只需再次按下按钮,这次它不会在松开时取消选择。按照 Donelle 的食谱,如果我单击文本中间,则必须第二次单击才能进行编辑。如果我单击文本内的某处而不是文本外的某处,这很可能意味着我想开始编辑而不是覆盖所有内容。
采纳答案by gcores
Don't know why it loses the selection in the GotFocusevent.
不知道为什么它在GotFocus事件中失去了选择。
But one solution is to do the selection on the GotKeyboardFocusand the GotMouseCaptureevents. That way it will always work.
但一种解决方案是对GotKeyboardFocus和GotMouseCapture事件进行选择。这样它就会一直有效。
回答by Donnelle
We have it so the first click selects all, and another click goes to cursor (our application is designed for use on tablets with pens).
我们有它,所以第一次点击选择全部,另一次点击转到光标(我们的应用程序是为在带笔的平板电脑上使用而设计的)。
You might find it useful.
你可能会发现它很有用。
public class ClickSelectTextBox : TextBox
{
public ClickSelectTextBox()
{
AddHandler(PreviewMouseLeftButtonDownEvent,
new MouseButtonEventHandler(SelectivelyIgnoreMouseButton), true);
AddHandler(GotKeyboardFocusEvent,
new RoutedEventHandler(SelectAllText), true);
AddHandler(MouseDoubleClickEvent,
new RoutedEventHandler(SelectAllText), true);
}
private static void SelectivelyIgnoreMouseButton(object sender,
MouseButtonEventArgs e)
{
// Find the TextBox
DependencyObject parent = e.OriginalSource as UIElement;
while (parent != null && !(parent is TextBox))
parent = VisualTreeHelper.GetParent(parent);
if (parent != null)
{
var textBox = (TextBox)parent;
if (!textBox.IsKeyboardFocusWithin)
{
// If the text box is not yet focussed, give it the focus and
// stop further processing of this click event.
textBox.Focus();
e.Handled = true;
}
}
}
private static void SelectAllText(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox != null)
textBox.SelectAll();
}
}
回答by Grokys
Donnelle's answer works the best, but having to derive a new class to use it is a pain.
Donnelle 的答案效果最好,但必须派生一个新类来使用它是一种痛苦。
Instead of doing that I register handlers the handlers in App.xaml.cs for all TextBoxes in the application. This allows me to use a Donnelle's answer with standard TextBox control.
我没有这样做,而是在 App.xaml.cs 中为应用程序中的所有文本框注册处理程序。这使我可以将 Donnelle 的答案与标准 TextBox 控件一起使用。
Add the following methods to your App.xaml.cs:
将以下方法添加到您的 App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// Select the text in a TextBox when it receives focus.
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseLeftButtonDownEvent,
new MouseButtonEventHandler(SelectivelyIgnoreMouseButton));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotKeyboardFocusEvent,
new RoutedEventHandler(SelectAllText));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.MouseDoubleClickEvent,
new RoutedEventHandler(SelectAllText));
base.OnStartup(e);
}
void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
{
// Find the TextBox
DependencyObject parent = e.OriginalSource as UIElement;
while (parent != null && !(parent is TextBox))
parent = VisualTreeHelper.GetParent(parent);
if (parent != null)
{
var textBox = (TextBox)parent;
if (!textBox.IsKeyboardFocusWithin)
{
// If the text box is not yet focused, give it the focus and
// stop further processing of this click event.
textBox.Focus();
e.Handled = true;
}
}
}
void SelectAllText(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox != null)
textBox.SelectAll();
}
}
回答by Nils
This is rather old, but I'll display my answer anyway.
这是相当古老的,但无论如何我都会显示我的答案。
I have chosen part of Donnelle's answer(skipped the double-click) for I think this a more natural. However, like gcores I dislike the need to create a derived class. But I also don't like gcores OnStartupmethod. And I need this on a "generally but not always" basis.
我选择了Donnelle 的部分答案(跳过了双击),因为我认为这更自然。但是,像 gcores 一样,我不喜欢创建派生类的需要。但我也不喜欢 gcoresOnStartup方法。我在“一般但不总是”的基础上需要这个。
I have Implemented this as an attached DependencyPropertyso I can set local:SelectTextOnFocus.Active = "True"in xaml. I find this way the most pleasing.
我已将此作为附件实现,DependencyProperty因此我可以local:SelectTextOnFocus.Active = "True"在 xaml 中进行设置。我觉得这种方式最令人愉快。
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
public class SelectTextOnFocus : DependencyObject
{
public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
"Active",
typeof(bool),
typeof(SelectTextOnFocus),
new PropertyMetadata(false, ActivePropertyChanged));
private static void ActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBox)
{
TextBox textBox = d as TextBox;
if ((e.NewValue as bool?).GetValueOrDefault(false))
{
textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
}
else
{
textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
}
}
}
private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DependencyObject dependencyObject = GetParentFromVisualTree(e.OriginalSource);
if (dependencyObject == null)
{
return;
}
var textBox = (TextBox)dependencyObject;
if (!textBox.IsKeyboardFocusWithin)
{
textBox.Focus();
e.Handled = true;
}
}
private static DependencyObject GetParentFromVisualTree(object source)
{
DependencyObject parent = source as UIElement;
while (parent != null && !(parent is TextBox))
{
parent = VisualTreeHelper.GetParent(parent);
}
return parent;
}
private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox textBox = e.OriginalSource as TextBox;
if (textBox != null)
{
textBox.SelectAll();
}
}
[AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetActive(DependencyObject @object)
{
return (bool) @object.GetValue(ActiveProperty);
}
public static void SetActive(DependencyObject @object, bool value)
{
@object.SetValue(ActiveProperty, value);
}
}
For my "general but not always" feature I set this Attache Property to Truein a (global) TextBoxStyle. This way "selecting the Text" is always "on", but I can disable it on a per-textbox-basis.
对于我的“一般但不总是”功能,我将此附加属性设置True为 (global) TextBoxStyle。这样“选择文本”总是“打开”,但我可以在每个文本框的基础上禁用它。
回答by Sergey Aldoukhov
Here are the Blend behaviors implementing the answer solution for your convenience:
为方便起见,以下是实现答案解决方案的 Blend 行为:
One for attaching to a single TextBox:
一种用于附加到单个 TextBox:
public class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
}
private void AssociatedObjectGotKeyboardFocus(object sender,
System.Windows.Input.KeyboardFocusChangedEventArgs e)
{
AssociatedObject.SelectAll();
}
private void AssociatedObjectGotMouseCapture(object sender,
System.Windows.Input.MouseEventArgs e)
{
AssociatedObject.SelectAll();
}
private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if(!AssociatedObject.IsKeyboardFocusWithin)
{
AssociatedObject.Focus();
e.Handled = true;
}
}
}
And one for attaching to the root of a container containing multiple TextBox'es:
还有一个用于附加到包含多个 TextBox 的容器的根目录:
public class SelectAllTextOnFocusMultiBehavior : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotKeyboardFocus += HandleKeyboardFocus;
AssociatedObject.GotMouseCapture += HandleMouseCapture;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotKeyboardFocus -= HandleKeyboardFocus;
AssociatedObject.GotMouseCapture -= HandleMouseCapture;
}
private static void HandleKeyboardFocus(object sender,
System.Windows.Input.KeyboardFocusChangedEventArgs e)
{
var txt = e.NewFocus as TextBox;
if (txt != null)
txt.SelectAll();
}
private static void HandleMouseCapture(object sender,
System.Windows.Input.MouseEventArgs e)
{
var txt = e.OriginalSource as TextBox;
if (txt != null)
txt.SelectAll();
}
}
回答by Dutts
Although this is an old question, I have just had this problem but solved it using an Attached Behavior, rather than an Expression Behavior as in Sergey's answer. This means I don't need a dependency on System.Windows.Interactivityin the Blend SDK:
虽然这是一个老问题,但我刚刚遇到了这个问题,但使用附加行为解决了它,而不是像 Sergey 的回答那样使用表达式行为。这意味着我不需要依赖System.Windows.InteractivityBlend SDK:
public class TextBoxBehavior
{
public static bool GetSelectAllTextOnFocus(TextBox textBox)
{
return (bool)textBox.GetValue(SelectAllTextOnFocusProperty);
}
public static void SetSelectAllTextOnFocus(TextBox textBox, bool value)
{
textBox.SetValue(SelectAllTextOnFocusProperty, value);
}
public static readonly DependencyProperty SelectAllTextOnFocusProperty =
DependencyProperty.RegisterAttached(
"SelectAllTextOnFocus",
typeof (bool),
typeof (TextBoxBehavior),
new UIPropertyMetadata(false, OnSelectAllTextOnFocusChanged));
private static void OnSelectAllTextOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = d as TextBox;
if (textBox == null) return;
if (e.NewValue is bool == false) return;
if ((bool) e.NewValue)
{
textBox.GotFocus += SelectAll;
textBox.PreviewMouseDown += IgnoreMouseButton;
}
else
{
textBox.GotFocus -= SelectAll;
textBox.PreviewMouseDown -= IgnoreMouseButton;
}
}
private static void SelectAll(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox == null) return;
textBox.SelectAll();
}
private static void IgnoreMouseButton(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null || (!textBox.IsReadOnly && textBox.IsKeyboardFocusWithin)) return;
e.Handled = true;
textBox.Focus();
}
}
You can then use it in your XAML like this:
然后,您可以像这样在 XAML 中使用它:
<TextBox Text="Some Text" behaviors:TextBoxBehavior.SelectAllTextOnFocus="True"/>
I blogged about it here.
我在这里写了关于它的博客。
回答by BillBR
Here's a very good very simple solution on MSDN:
这是MSDN上一个非常好的非常简单的解决方案:
<TextBox
MouseDoubleClick="SelectAddress"
GotKeyboardFocus="SelectAddress"
PreviewMouseLeftButtonDown="SelectivelyIgnoreMouseButton" />
Here's the code behind:
这是后面的代码:
private void SelectAddress(object sender, RoutedEventArgs e)
{
TextBox tb = (sender as TextBox);
if (tb != null)
{
tb.SelectAll();
}
}
private void SelectivelyIgnoreMouseButton(object sender,
MouseButtonEventArgs e)
{
TextBox tb = (sender as TextBox);
if (tb != null)
{
if (!tb.IsKeyboardFocusWithin)
{
e.Handled = true;
tb.Focus();
}
}
}
回答by Sam
I think this works well:
我认为这很有效:
private void ValueText_GotFocus(object sender, RoutedEventArgs e)
{
TextBox tb = (TextBox)e.OriginalSource;
tb.Dispatcher.BeginInvoke(
new Action(delegate
{
tb.SelectAll();
}), System.Windows.Threading.DispatcherPriority.Input);
}
If you would like to implement it as an extension method:
如果您想将其实现为扩展方法:
public static void SelectAllText(this System.Windows.Controls.TextBox tb)
{
tb.Dispatcher.BeginInvoke(
new Action(delegate
{
tb.SelectAll();
}), System.Windows.Threading.DispatcherPriority.Input);
}
And in your GotFocusevent:
在您的GotFocus活动中:
private void ValueText_GotFocus(object sender, RoutedEventArgs e)
{
TextBox tb = (TextBox)e.OriginalSource;
tb.SelectAllText();
}
I discovered the solution above because several months ago I was looking for a way to set focus to a given UIElement. I discovered the the code below somewhere (credit is hereby given) and it works well. I post it even though it is not directly related to the OP's question because it demonstrates the same pattern of using Dispatcherto work with a UIElement.
我发现了上面的解决方案,因为几个月前我正在寻找一种方法来将焦点设置为给定的UIElement. 我在某处发现了下面的代码(特此给出信用)并且它运行良好。我上传它,即使因为它表明使用相同的模式它不直接关系到OP的问题Dispatcher,以工作带UIElement。
// Sets focus to uiElement
public static void DelayedFocus(this UIElement uiElement)
{
uiElement.Dispatcher.BeginInvoke(
new Action(delegate
{
uiElement.Focusable = true;
uiElement.Focus();
Keyboard.Focus(uiElement);
}),
DispatcherPriority.Render);
}
回答by Danny Beckett
This simple implementation works perfectly for me:
这个简单的实现非常适合我:
void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
((TextBox) sender).SelectAll();
}
void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var TextBox = (TextBox) sender;
if (!TextBox.IsKeyboardFocusWithin)
{
TextBox.Focus();
e.Handled = true;
}
}
To apply it to all TextBox's, put the following code after InitializeComponent();
要将其应用于 all TextBox,请将以下代码放在InitializeComponent();
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_GotFocus));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseDownEvent, new MouseButtonEventHandler(TextBox_PreviewMouseDown));
回答by Kristof Verbiest
I've found none of the answers presented here mimic a standard Windows textbox. For instance, try to click in the white space between the last character of the textbox and the right side of the textbox. Most of the solutions here will always select the whole content, which makes it very difficult to append text to a textbox.
我发现这里提供的答案都没有模仿标准的 Windows 文本框。例如,尝试单击文本框最后一个字符和文本框右侧之间的空白区域。这里的大多数解决方案将始终选择整个内容,这使得将文本附加到文本框变得非常困难。
The answer that I present here behaves better in this respect. It is a behavior (so it requires the System.Windows.Interactivityassembly from the Blend SDK). It could be rewritten using attached properties as well.
我在这里提出的答案在这方面表现得更好。这是一种行为(因此它需要来自Blend SDK的System.Windows.Interactivity程序集)。它也可以使用附加属性重写。
public sealed class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
}
void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Find the textbox
DependencyObject parent = e.OriginalSource as UIElement;
while (parent != null && !(parent is TextBox))
parent = VisualTreeHelper.GetParent(parent);
var textBox = parent as TextBox;
Debug.Assert(textBox != null);
if (textBox.IsFocused) return;
textBox.SelectAll();
Keyboard.Focus(textBox);
e.Handled = true;
}
}
This is based on code I've found here.
这是基于我在这里找到的代码。

