使WinForms TextBox的行为与浏览器的地址栏类似

当一个C#WinForms文本框收到焦点时,我希望它的行为就像您的浏览器的地址栏。

看看我的意思,点击你的网页浏览器的地址栏。 你会注意到以下行为:

  1. 在文本框中单击应该select所有的文本,如果文本框以前没有集中。
  2. 在文本框中鼠标向下拖动,只应select我用鼠标突出显示的文本。
  3. 如果文本框已经聚焦,则单击不会select所有文本。
  4. 以编程方式或通过键盘选项卡聚焦文本框应select所有文本。

我想在WinForms中完全做到这一点。

最快的警报:请在回答之前阅读以下内容! 多谢你们。 🙂

在.Enter或.GotFocus事件期间调用.SelectAll()将不起作用,因为如果用户单击文本框,则将将光标放在他单击的位置,从而取消select所有文本。

在.Click事件中调用.SelectAll()将不起作用,因为用户将无法使用鼠标select任何文本。 .SelectAll()调用将保持覆盖用户的文本select。

调用BeginInvoke((Action)textbox.SelectAll)在焦点/input事件input不起作用,因为它违反了上面的规则#2,它将继续覆盖用户的焦点select。

首先,感谢您的回答! 共有9个答案。 谢谢。

坏消息:所有的答案都有些怪癖,或者说没有完全正确的工作。 我已为每个post添加了评论。

好消息:我find了一种方法来使其工作。 这个解决scheme非常简单,似乎适用于所有的场景(鼠标移动,select文本,选项卡焦点等)

bool alreadyFocused; ... textBox1.GotFocus += textBox1_GotFocus; textBox1.MouseUp += textBox1_MouseUp; textBox1.Leave += textBox1_Leave; ... void textBox1_Leave(object sender, EventArgs e) { alreadyFocused = false; } void textBox1_GotFocus(object sender, EventArgs e) { // Select all text only if the mouse isn't down. // This makes tabbing to the textbox give focus. if (MouseButtons == MouseButtons.None) { this.textBox1.SelectAll(); alreadyFocused = true; } } void textBox1_MouseUp(object sender, MouseEventArgs e) { // Web browsers like Google Chrome select the text on mouse up. // They only do it if the textbox isn't already focused, // and if the user hasn't selected all text. if (!alreadyFocused && this.textBox1.SelectionLength == 0) { alreadyFocused = true; this.textBox1.SelectAll(); } } 

据我所知,这导致文本框的行为完全像一个Web浏览器的地址栏。

希望这有助于下一个试图解决这个看似简单的问题的人。

再次感谢,伙计们,为你所有的答案,帮助我走向正确的道路。

我find了一个更简单的解决scheme。 它包括使用Control.BeginInvokeasynchronous启动SelectAll,以便在发生Enter和Click事件后发生:

在C#中:

 private void MyTextBox_Enter(object sender, EventArgs e) { // Kick off SelectAll asyncronously so that it occurs after Click BeginInvoke((Action)delegate { MyTextBox.SelectAll(); }); } 

在VB.NET中(感谢Krishanu Dey )

 Private Sub MyTextBox_Enter(sender As Object, e As EventArgs) Handles MyTextBox.Enter BeginInvoke(DirectCast(Sub() MyTextBox.SelectAll(), Action)) End Sub 

你的解决scheme是好的,但在一个特定的情况下失败。 如果通过select文本范围而不是仅仅单击文本框来提供文本框焦点,则alreadyFocussed标志不会设置为true,因此当您再次单击文本框时,所有文本都会被选中。

这是我的解决scheme的版本。 我也把代码放到inheritanceTextBox的类中,所以逻辑很好地隐藏起来。

 public class MyTextBox : System.Windows.Forms.TextBox { private bool _focused; protected override void OnEnter(EventArgs e) { base.OnEnter(e); if (MouseButtons == MouseButtons.None) { SelectAll(); _focused = true; } } protected override void OnLeave(EventArgs e) { base.OnLeave(e); _focused = false; } protected override void OnMouseUp(MouseEventArgs mevent) { base.OnMouseUp(mevent); if (!_focused) { if (SelectionLength == 0) SelectAll(); _focused = true; } } } 

这是有点kludgey,但在您的点击事件,使用SendKeys.Send( "{HOME}+{END}" );

点击文本框的事件? 或者甚至MouseCaptureChanged事件为我工作。 – 好。 不起作用。

所以你必须做两件事情:

 private bool f = false; private void textBox_MouseClick(object sender, MouseEventArgs e) { if (this.f) { this.textBox.SelectAll(); } this.f = false; } private void textBox_Enter(object sender, EventArgs e) { this.f = true; this.textBox.SelectAll(); } private void textBox_MouseMove(object sender, MouseEventArgs e) // idea from the other answer { this.f = false; } 

用于TabBbing(通过文本框到一个)以及 – 在Enter中调用SelectAll()以防万一…

我使用的一个答案,你可能会踢你自己…

在input事件中:

txtFilter.BeginInvoke(new MethodInvoker(txtFilter.SelectAll));

 'Inside the Enter event TextBox1.SelectAll(); 

好吧,尝试之后,这是你想要的:

  • 在input事件启动一个标志,说明你已经在进入事件
  • 在Click事件中,如果您设置了该标志,则调用.SelectAll()并重置该标志。
  • 在MouseMove事件中,将input的标志设置为false,这将允许您单击高亮而不必先input文本框。

这select了所有的文字,但允许我以后突出显示部分文字,或者让您突出显示第一次点击。

按要求:

  bool entered = false; private void textBox1_Enter(object sender, EventArgs e) { entered = true; textBox1.SelectAll(); //From Jakub's answer. } private void textBox1_Click(object sender, EventArgs e) { if (entered) textBox1.SelectAll(); entered = false; } private void textBox1_MouseMove(object sender, MouseEventArgs e) { if (entered) entered = false; } 

对我来说,在控制中select所有文本。

这里有一个帮助函数,将解决scheme提升到下一个层次 – 重用而不inheritance。

  public static void WireSelectAllOnFocus( TextBox aTextBox ) { bool lActive = false; aTextBox.GotFocus += new EventHandler( ( sender, e ) => { if ( System.Windows.Forms.Control.MouseButtons == MouseButtons.None ) { aTextBox.SelectAll(); lActive = true; } } ); aTextBox.Leave += new EventHandler( (sender, e ) => { lActive = false; } ); aTextBox.MouseUp += new MouseEventHandler( (sender, e ) => { if ( !lActive ) { lActive = true; if ( aTextBox.SelectionLength == 0 ) aTextBox.SelectAll(); } }); } 

要使用这个,只需调用传递一个TextBox的函数,它将为您处理所有的混乱位。 我build议在Form_Load事件中连接所有的文本框。 你可以把这个函数放在你的表单中,或者如果你喜欢我,在一个实用工具类中的某个地方进行更多的重用。

这与nzhenry的stream行答案类似,但我觉得不必子类化就更容易:

  Private LastFocused As Control = Nothing Private Sub TextBox1_Enter(sender As Object, e As System.EventArgs) Handles TextBox1.Enter, TextBox2.Enter, TextBox3.Enter If MouseButtons = Windows.Forms.MouseButtons.None Then LastFocused = sender End Sub Private Sub TextBox1_Leave(sender As Object, e As System.EventArgs) Handles TextBox1.Leave, TextBox2.Leave, TextBox3.Leave LastFocused = Nothing End Sub Private Sub TextBox1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseUp, TextBox2.MouseUp, TextBox3.MouseUp With CType(sender, TextBox) If LastFocused IsNot sender AndAlso .SelectionLength = 0 Then .SelectAll() End With LastFocused = sender End Sub 

这适用于WPF / XAML文本框。

  private bool initialEntry = true; private void TextBox_SelectionChanged(object sender, RoutedEventArgs e) { if (initialEntry) { e.Handled = true; initialEntry = false; TextBox.SelectAll(); } } private void TextBox_GotFocus(object sender, RoutedEventArgs e) { TextBox.SelectAll(); initialEntry = true; } 

SelectAll从来没有为我工作。

这工作。

 ActiveControl = textBox1; textBox1->SelectionStart = 0; textBox1->SelectionLength = textBox1->Text->Length; 

我发现了一个更简单的解决scheme:

要确保单击文本框时所有文本被选中,请确保Click处理程序调用input处理程序。 不需要额外的variables!

例:

 private void textBox1_Click(object sender, EventArgs e){ textBox1_Enter(sender, e); } private void textBox1_Enter(object sender, EventArgs e){ TextBox tb = ((TextBox)sender); tb.SelectAll(); } 
 private bool _isSelected = false; private void textBox_Validated(object sender, EventArgs e) { _isSelected = false; } private void textBox_MouseClick(object sender, MouseEventArgs e) { SelectAllText(textBox); } private void textBox_Enter(object sender, EventArgs e) { SelectAllText(textBox); } private void SelectAllText(TextBox text) { if (!_isSelected) { _isSelected = true; textBox.SelectAll(); } } 

有趣的是,一个DropDownStyle = Simple的ComboBox几乎完全是你正在寻找的行为,我想。

(如果您将控件的高度降低到不显示列表 – 然后再增加几个像素 – ComboBox和TextBox之间没有有效的区别。)

为什么不简单地使用文本框的MouseDown事件? 它适用于我,并不需要额外的布尔值。 非常干净和简单,例如:

 private void textbox_MouseDown(object sender, MouseEventArgs e) { if (textbox != null && !string.IsNullOrEmpty(textbox.Text)) { textbox.SelectAll(); } } 

我在MouseUp事件中调用了SelectAll,它对我来说工作的很好。

  private bool _tailTextBoxFirstClick = false; private void textBox1_MouseUp(object sender, MouseEventArgs e) { if(_textBoxFirstClick) textBox1.SelectAll(); _textBoxFirstClick = false; } private void textBox1_Leave(object sender, EventArgs e) { _textBoxFirstClick = true; textBox1.Select(0, 0); } 

从TextBox或MaskedTextBox中派生一个类:

 public class SMaskedTextBox : MaskedTextBox { protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); this.SelectAll(); } } 

并在你的表格上使用它。

你有没有尝试过MSDN论坛“Windows窗体常规” ,它仅仅是TextBox的子类build议的解决scheme ?

实际上,GotFocus是您感兴趣的正确事件(真正的讯息),因为无论您如何控制,您甚至可以获得最终的结果。 问题是你什么时候调用SelectAll()。

尝试这个:

 public partial class Form1 : Form { public Form1() { InitializeComponent(); this.textBox1.GotFocus += new EventHandler(textBox1_GotFocus); } private delegate void SelectAllDelegate(); private IAsyncResult _selectAllar = null; //So we can clean up afterwards. //Catch the input focus event void textBox1_GotFocus(object sender, EventArgs e) { //We could have gotten here many ways (including mouse click) //so there could be other messages queued up already that might change the selection. //Don't call SelectAll here, since it might get undone by things such as positioning the cursor. //Instead use BeginInvoke on the form to queue up a message //to select all the text after everything caused by the current event is processed. this._selectAllar = this.BeginInvoke(new SelectAllDelegate(this._SelectAll)); } private void _SelectAll() { //Clean-up the BeginInvoke if (this._selectAllar != null) { this.EndInvoke(this._selectAllar); } //Now select everything. this.textBox1.SelectAll(); } } 

对于一组表单中的文本框:

 private System.Windows.Forms.TextBox lastFocus; private void textBox_GotFocus(object sender, System.Windows.Forms.MouseEventArgs e) { TextBox senderTextBox = sender as TextBox; if (lastFocus!=senderTextBox){ senderTextBox.SelectAll(); } lastFocus = senderTextBox; } 

下面似乎工作。 enter事件处理控件的标签,并且MouseDown在单击控件时工作。

  private ########### void textBox1_Enter(object sender, EventArgs e) { textBox1.SelectAll(); } private void textBox1_MouseDown(object sender, MouseEventArgs e) { if (textBox1.Focused) textBox1.SelectAll(); } 

我知道这已经解决了,但我有一个build议,我觉得其实很简单。

在鼠标向上的事件中,你所要做的就是放置

 if(textBox.SelectionLength = 0) { textBox.SelectAll(); } 

这似乎在VB.NET中工作(我知道这是一个C#问题…可悲的是我被迫使用VB在我的工作..我有这个问题,这是什么把我带到这里… )

我还没有发现它的任何问题,除了它不立即select点击,但我有问题的事实….

以下解决scheme适用于我。 我添加了OnKeyDownOnKeyUp事件覆盖,以保持TextBox文本始终处于选中状态。

  public class NumericTextBox : TextBox { private bool _focused; protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); if (MouseButtons == MouseButtons.None) { this.SelectAll(); _focused = true; } } protected override void OnEnter(EventArgs e) { base.OnEnter(e); if (MouseButtons == MouseButtons.None) { SelectAll(); _focused = true; } } protected override void OnLeave(EventArgs e) { base.OnLeave(e); _focused = false; } protected override void OnMouseUp(MouseEventArgs mevent) { base.OnMouseUp(mevent); if (!_focused) { if (SelectionLength == 0) SelectAll(); _focused = true; } } protected override void OnKeyUp(KeyEventArgs e) { base.OnKeyUp(e); if (SelectionLength == 0) SelectAll(); _focused = true; } protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (SelectionLength == 0) SelectAll(); _focused = true; } } 

当你离开控制时设置select。 当你回来的时候,它会在那里。 在窗体周围标签,当你返回到控件时,所有的文本将被选中。

如果你用鼠标进入,那么插入符号将被正确放置在你点击的位置。

 private void maskedTextBox1_Leave(object sender, CancelEventArgs e) { maskedTextBox1.SelectAll(); } 

例如(WPF中),答案实际上可能比以上所有内容都要简单得多:

 public void YourTextBox_MouseEnter(object sender, MouseEventArgs e) { YourTextBox.Focus(); YourTextBox.SelectAll(); } 

当然我不能知道你想如何使用这段代码,但主要看这里的一部分是:先调用.Focus(),然后调用.SelectAll();

很简单的解决scheme

  private bool _focusing = false; protected override void OnEnter( EventArgs e ) { _focusing = true; base.OnEnter( e ); } protected override void OnMouseUp( MouseEventArgs mevent ) { base.OnMouseUp( mevent ); if( _focusing ) { this.SelectAll(); _focusing = false; } } 

编辑:原来的OP特别关注鼠标向下/文本select/鼠标向上序列,在这种情况下,上述简单的解决scheme将最终与文本被部分选定。

这应该解决*问题(在实践中我拦截WM_SETCURSOR):

  protected override void WndProc( ref Message m ) { if( m.Msg == 32 ) //WM_SETCURSOR=0x20 { this.SelectAll(); // or your custom logic here } base.WndProc( ref m ); } 

*实际上,下面的序列以部分文本select结束,但如果将鼠标移动到文本框上,所有文本将被再次选中:

鼠标向下/文本select/鼠标移出文本框/鼠标移动

只需使用selectall()input并单击事件即可

 private void textBox1_Enter(object sender, EventArgs e) { textBox1.SelectAll(); } private void textBox1_Click(object sender, EventArgs e) { textBox1.SelectAll(); } 

我发现这个工作最好,当鼠标点击并不立即释放:

  private bool SearchBoxInFocusAlready = false; private void SearchBox_LostFocus(object sender, RoutedEventArgs e) { SearchBoxInFocusAlready = false; } private void SearchBox_PreviewMouseUp(object sender, MouseButtonEventArgs e) { if (e.ButtonState == MouseButtonState.Released && e.ChangedButton == MouseButton.Left && SearchBox.SelectionLength == 0 && SearchBoxInFocusAlready == false) { SearchBox.SelectAll(); } SearchBoxInFocusAlready = true; } 

我的解决scheme是相当原始的,但为我的目的正常工作

 private async void TextBox_GotFocus(object sender, RoutedEventArgs e) { if (sender is TextBox) { await Task.Delay(100); (sender as TextBox).SelectAll(); } } 

这是在.NET 2005中为我工作 –

  ' * if the mouse button is down, do not run the select all. If MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub End If ' * OTHERWISE INVOKE THE SELECT ALL AS DISCUSSED.