.net 使 WinForms TextBox 表现得像浏览器的地址栏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/97459/
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
Making a WinForms TextBox behave like your browser's address bar
提问by Judah Gabriel Himango
When a C# WinForms textbox receives focus, I want it to behave like your browser's address bar.
当 C# WinForms 文本框获得焦点时,我希望它的行为类似于浏览器的地址栏。
To see what I mean, click in your web browser's address bar. You'll notice the following behavior:
要了解我的意思,请单击 Web 浏览器地址栏中的 。您会注意到以下行为:
- Clicking in the textbox should select all the text if the textbox wasn't previously focused.
- Mouse down and drag in the textbox should select only the text I've highlighted with the mouse.
- If the textbox is already focused, clicking does not select all text.
- Focusing the textbox programmatically or via keyboard tabbing should select all text.
- 如果文本框以前没有聚焦,则单击文本框应选择所有文本。
- 鼠标向下并在文本框中拖动应该只选择我用鼠标突出显示的文本。
- 如果文本框已经聚焦,单击不会选择所有文本。
- 以编程方式或通过键盘选项卡聚焦文本框应选择所有文本。
I want to do exactly this in WinForms.
我想在 WinForms 中做到这一点。
FASTEST GUN ALERT: please read the following before answering!Thanks guys. :-)
最快的枪支警报:请在回答之前阅读以下内容!谢谢你们。:-)
Calling .SelectAll() during the .Enter or .GotFocus events won't workbecause if the user clicked the textbox, the caret will be placed where he clicked, thus deselecting all text.
Calling .SelectAll() during the .Click event won't workbecause the user won't be able to select any text with the mouse; the .SelectAll() call will keep overwriting the user's text selection.
Calling BeginInvoke((Action)textbox.SelectAll) on focus/enter event enter doesn't workbecause it breaks rule #2 above, it will keep overriding the user's selection on focus.
在 .Enter 或 .GotFocus 事件期间调用 .SelectAll() 将不起作用,因为如果用户单击文本框,插入符号将放置在他单击的位置,从而取消选择所有文本。
在 .Click 事件期间调用 .SelectAll() 将不起作用,因为用户将无法使用鼠标选择任何文本;.SelectAll() 调用将继续覆盖用户的文本选择。
在焦点/输入事件输入上调用 BeginInvoke((Action)textbox.SelectAll) 不起作用,因为它违反了上面的规则 #2,它将继续覆盖用户对焦点的选择。
采纳答案by Judah Gabriel Himango
First of all, thanks for answers! 9 total answers. Thank you.
首先谢谢各位的解答!共有 9 个答案。谢谢你。
Bad news: all of the answers had some quirks or didn't work quite right (or at all). I've added a comment to each of your posts.
坏消息:所有答案都有一些怪癖或不太正确(或根本不正确)。我在你的每篇文章中都添加了评论。
Good news: I've found a way to make it work. This solution is pretty straightforward and seems to work in all the scenarios (mousing down, selecting text, tabbing focus, etc.)
好消息:我已经找到了让它发挥作用的方法。这个解决方案非常简单,似乎适用于所有场景(鼠标向下、选择文本、标签焦点等)
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();
}
}
As far as I can tell, this causes a textbox to behave exactly like a web browser's address bar.
据我所知,这会导致文本框的行为与 Web 浏览器的地址栏完全一样。
Hopefully this helps the next guy who tries to solve this deceptively simple problem.
希望这有助于下一个试图解决这个看似简单的问题的人。
Thanks again, guys, for all your answers that helped lead me towards the correct path.
再次感谢,伙计们,你们所有的答案都帮助我走向正确的道路。
回答by Duncan Smart
I found a simpler solution to this. It involves kicking off the SelectAll asynchronously using Control.BeginInvokeso that it occurs after the Enter and Click events have occurred:
我找到了一个更简单的解决方案。它涉及使用异步启动 SelectAll,Control.BeginInvoke以便在 Enter 和 Click 事件发生后发生:
In C#:
在 C# 中:
private void MyTextBox_Enter(object sender, EventArgs e)
{
// Kick off SelectAll asyncronously so that it occurs after Click
BeginInvoke((Action)delegate
{
MyTextBox.SelectAll();
});
}
In VB.NET (thanks to Krishanu Dey)
在 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
回答by nzhenry
Your solution is good, but fails in one specific case. If you give the TextBox focus by selecting a range of text instead of just clicking, the alreadyFocussed flag doesn't get set to true, so when you click in the TextBox a second time, all the text gets selected.
您的解决方案很好,但在一种特定情况下失败。如果您通过选择文本范围而不是单击来使 TextBox 获得焦点,则 alreadyFocussed 标志不会设置为 true,因此当您第二次单击 TextBox 时,所有文本都会被选中。
Here is my version of the solution. I've also put the code into a class which inherits TextBox, so the logic is nicely hidden away.
这是我的解决方案版本。我还将代码放入继承 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;
}
}
}
回答by Todd Benning
It's a bit kludgey, but in your click event, use SendKeys.Send( "{HOME}+{END}" );.
这有点笨拙,但在您的点击事件中,使用SendKeys.Send( "{HOME}+{END}" );.
回答by Jakub Kotrla
Click event of textbox? Or even MouseCaptureChanged event works for me. - OK. doesn't work.
文本框的点击事件?甚至 MouseCaptureChanged 事件对我有用。- 好的。不起作用。
So you have to do 2 things:
所以你必须做两件事:
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;
}
Works for tabbing (through textBoxes to the one) as well - call SelectAll() in Enter just in case...
也适用于制表符(通过文本框到一个) - 在 Enter 中调用 SelectAll() 以防万一......
回答by Jakub Kotrla
A one line answer that I use...you might be kicking yourself...
我使用的单行答案......你可能会踢自己......
In the Enter Event:
在输入事件中:
txtFilter.BeginInvoke(new MethodInvoker( txtFilter.SelectAll));
txtFilter.BeginInvoke(new MethodInvoker(txtFilter.SelectAll));
回答by MagicKat
'Inside the Enter event
TextBox1.SelectAll();
Ok, after trying it here is what you want:
好的,在这里尝试之后就是你想要的:
- On the Enter event start a flag that states that you have been in the enter event
- On the Click event, if you set the flag, call .SelectAll() and reset the flag.
- On the MouseMove event, set the entered flag to false, which will allow you to click highlight without having to enter the textbox first.
- 在 Enter 事件中启动一个标志,表明您已参加过 Enter 事件
- 在 Click 事件中,如果您设置了标志,则调用 .SelectAll() 并重置标志。
- 在 MouseMove 事件上,将输入标志设置为 false,这将允许您单击突出显示而无需先输入文本框。
This selected all the text on entry, but allowed me to highlight part of the text afterwards, or allow you to highlight on the first click.
这在输入时选择了所有文本,但允许我在之后突出显示部分文本,或者允许您在第一次点击时突出显示。
By request:
按要求:
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;
}
For me, the tabbing into the control selects all the text.
对我来说,进入控件的选项卡会选择所有文本。
回答by Ross K.
Here's a helper function taking the solution to the next level - reuse without 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();
}
});
}
To use this simply call the function passing a TextBox and it takes care of all the messy bits for you. I suggest wiring up all your text boxes in the Form_Load event. You can place this function in your form, or if your like me, somewhere in a utility class for even more reuse.
要使用它,只需调用传递 TextBox 的函数,它就会为您处理所有杂乱的部分。我建议在 Form_Load 事件中连接所有文本框。你可以把这个函数放在你的表单中,或者如果你像我一样,放在一个实用程序类的某个地方,以便更多地重用。
回答by Chris
This is similar to nzhenry's popular answer, but I find it easier to not have to subclass:
这类似于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
回答by slobs
This worked for a WPF/XAML TextBox.
这适用于 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;
}

