使 WinFormsTextBox 的行为类似于浏览器的地址栏

当 C # WinForms 文本框接收到焦点时,我希望它像浏览器的地址栏一样工作。

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

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

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

最快的枪支警报: 请在回答之前阅读以下内容

期间调用. SelectAll () 输入或者 GotFocus 事件不会 工作 ,因为如果用户单击 文本框中,插入符号将被放置 在那里他点击,因此取消选择所有 短信。

呼叫。过程中选择 All ()。单击事件不会工作 ,因为用户不能用鼠标选择任何文本;。SelectAll ()调用将不断覆盖用户的文本选择。

调用 BeginInvoke ((Action)文本框。SelectAll)在 focus/enter 事件输入上无法工作 ,因为它违反了上面的规则 # 2,它将继续覆盖用户在 focus 上的选择。

122914 次浏览

点击文本框的事件? 或者甚至鼠标捕捉改变的事件为我工作。-确定。不工作。

所以你必须做两件事:

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

可以在 Enter 中调用 SelectAll () ,以防万一..。

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

'Inside the Enter event
TextBox1.SelectAll();

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

  • 在 Enter 事件上启动一个标志,指出您已经处于 Enter 事件中
  • 在 Click 事件上,如果设置了标志,则调用.SelectAll ()并重置标志。
  • 在 MouseMove 事件上,将输入的标志设置为 false,这将允许您单击高亮显示,而不必首先输入文本框。

这选择了所有的文本条目,但允许我突出显示部分文本后,或允许您突出显示在第一次单击。

应要求:

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

对于我来说,控件中的选项卡选择所有的文本。

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

下面的方法似乎行得通。 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();
}

有趣的是,我认为,一个具有 DropDownStyle = Simple 的 ComboBox 几乎具有你想要的行为。

(如果您降低控件的高度以不显示列表——然后再降低几个像素——那么 ComboBox 和 TextBox 之间就没有有效的区别了。)

实际上 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();
}
}

首先,谢谢你的回答! 总共9个答案。谢谢。

坏消息是: 所有的答案都有一些怪癖,或者根本就不对。我已经在你们的帖子里添加了一条评论。

好消息,我找到办法了。这个解决方案非常简单,似乎可以在所有场景(鼠标下移、选择文本、选项卡式焦点等)中工作

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

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

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

再次感谢,伙计们,感谢你们的回答,帮助我走上正确的道路。

为什么不简单地使用文本框的 MouseDown-Event?它对我来说工作得很好,不需要额外的布尔值。非常干净和简单,例如:

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

你有没有试过简单的子类文本框的 MSDN 论坛“ Windows 窗体通用”提出的解决方案

我的回答只有一句话,你可能会后悔。

在回车事件中:

BeginInvoke (new MethodInvoker (txtFilter.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();
}
}

用在你们的表格上。

我创建了一个新的 VB.Net Wpf 项目,我创建了一个 TextBox,并使用了以下代码:

Class MainWindow


Sub New()


' This call is required by the designer.
InitializeComponent()


' Add any initialization after the InitializeComponent() call.
AddHandler PreviewMouseLeftButtonDown, New MouseButtonEventHandler(AddressOf SelectivelyIgnoreMouseButton)
AddHandler GotKeyboardFocus, New KeyboardFocusChangedEventHandler(AddressOf SelectAllText)
AddHandler MouseDoubleClick, New MouseButtonEventHandler(AddressOf SelectAllText)
End Sub


Private Shared Sub SelectivelyIgnoreMouseButton(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
' Find the TextBox
Dim parent As DependencyObject = TryCast(e.OriginalSource, UIElement)
While parent IsNot Nothing AndAlso Not (TypeOf parent Is TextBox)
parent = VisualTreeHelper.GetParent(parent)
End While


If parent IsNot Nothing Then
Dim textBox As Object = DirectCast(parent, TextBox)
If Not textBox.IsKeyboardFocusWithin Then
' 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
End If
End If
End Sub


Private Shared Sub SelectAllText(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim textBox As Object = TryCast(e.OriginalSource, TextBox)
If textBox IsNot Nothing Then
textBox.SelectAll()
End If
End Sub


End Class

您的解决方案是好的,但是在一个特定的情况下失败了。如果您通过选择一个文本范围而不仅仅是单击来赋予 TextBox 焦点,那么 alreadyFocussed 标志不会被设置为 true,所以当您第二次单击 TextBox 时,所有的文本都会被选中。

这是我的解决方案。我还将代码放入了一个继承 TextBox 的类中,这样就很好地隐藏了逻辑。

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

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

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

我找到了一个更简单的解决办法。它涉及使用 Control.BeginInvoke异步启动 SelectAll,以便在 Enter 和 Click 事件发生之后启动:

C # :

private void MyTextBox_Enter(object sender, EventArgs e)
{
// Kick off SelectAll asynchronously 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

下面是一个助手函数,它将解决方案提升到下一个级别——不带继承的重用。

    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 的函数,它就会为您处理所有凌乱的位。我建议在 Form _ Load 事件中连接所有文本框。您可以将此函数放在表单中,或者如果您喜欢我,可以放在实用程序类中的某个地方,以便进行更多的重用。

我知道这个问题已经解决了,但我有一个建议,我认为实际上相当简单。

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

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

它似乎对我在 VB.NET 工作(我知道这是一个 C # 问题... 遗憾的是,我被迫使用 VB 在我的工作。.我遇到了这个问题,所以我来到了这里...)

我还没发现任何问题。.除了它不会立即点击选择,但是我在这方面有问题。

这类似于 Nzhenry的流行答案,但是我发现不需要子类化更容易:

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

SelectAll 从来都不适合我。

这个管用。

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

下面的解决方案适合我。我添加了 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;
}
}

这适用于 WPF/XAML TextBox。

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

离开控件时设置选定内容。你回来的时候还在。选项卡,当您返回到控件时,所有文本都将被选中。

如果你用鼠标进入,插入符号将正确地放置在你点击的地方。

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

答案实际上可以比上述所有问题更简单,例如(在 WPF 中) :

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

当然,我不知道您想如何使用这个代码,但是这里要看的主要部分是: 第一次调用。集中注意力,然后打电话。SelectAll () ;

非常简单的解决办法:

    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 特别关注鼠标向下/文本选择/鼠标向上序列,在这种情况下,上述简单的解决方案最终将部分选择文本。

这应该可以解决 * 问题(实际上我拦截了 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 );
}

* 实际上,以下顺序最终会选择部分文本,但如果将鼠标移动到文本框上方,所有文本将再次被选中:

鼠标向下/文本选择/鼠标移出/文本框/鼠标向上

我找到了一个更简单的解决办法:

要确保在单击 textBox 时选中所有文本,请确保 Click 处理程序调用 Enter 处理程序。不需要额外的变量!

例如:

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

只需在输入和单击事件时使用 selecall ()即可

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

我的解决方案相当原始,但对我的目的很有效

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.