163

当 C# WinForms 文本框获得焦点时,我希望它的行为类似于浏览器的地址栏。

要了解我的意思,请单击 Web 浏览器的地址栏。您会注意到以下行为:

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

我想在 WinForms 中做到这一点。

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

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

在 .Click 事件期间调用 .SelectAll() 将不起作用,因为用户将无法用鼠标选择任何文本;.SelectAll() 调用将继续覆盖用户的文本选择。

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

4

31 回答 31

112

首先,感谢您的回答!共 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();
    }
}

据我所知,这会导致文本框的行为与 Web 浏览器的地址栏完全相同。

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

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

于 2008-09-19T14:08:30.040 回答
83

我找到了一个更简单的解决方案。它涉及使用异步启动 SelectAllControl.BeginInvoke以便它在 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
于 2011-07-28T10:12:58.473 回答
30

您的解决方案很好,但在一种特定情况下失败。如果您通过选择文本范围而不是单击来为 TextBox 提供焦点,则 alreadyFocused 标志不会设置为 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;
        }
    }
}
于 2010-09-09T17:14:09.027 回答
8

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

于 2008-09-18T22:08:28.097 回答
4

文本框的点击事件?甚至 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; 
}

也适用于制表符(通过文本框到一个) - 在 Enter 中调用 SelectAll() 以防万一...

于 2008-09-18T22:07:28.987 回答
4

我使用的单行答案......你可能会踢自己......

在输入事件中:

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

于 2009-04-06T20:03:28.723 回答
3
'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;
    }

对我来说,进入控件的选项卡选择了所有文本。

于 2008-09-18T22:09:27.640 回答
3

这是一个帮助函数将解决方案提升到一个新的水平 - 重用而不继承。

    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 事件中连接所有文本框。你可以把这个函数放在你的表单中,或者如果你喜欢我,可以放在实用程序类的某个地方,以便更多地重用。

于 2011-08-07T05:34:30.703 回答
2

这类似于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
于 2012-05-02T15:03:31.083 回答
2

这适用于 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;      
    }
于 2013-03-07T23:55:24.510 回答
1

SelectAll 从来没有为我工作过。

这行得通。

ActiveControl = textBox1;
textBox1->SelectionStart = 0;
textBox1->SelectionLength = textBox1->Text->Length;
于 2012-05-02T20:13:25.380 回答
1

我找到了一个更简单的解决方案:

要确保在单击文本框时选择所有文本,请确保 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();
    }
于 2014-12-01T13:25:28.653 回答
0
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();
    }
}
于 2008-09-18T22:31:05.903 回答
0

有趣的是,我认为,带有 DropDownStyle=Simple 的 ComboBox 几乎完全符合您正在寻找的行为。

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

于 2008-09-18T22:54:38.670 回答
0

实际上 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();
    }
}
于 2008-09-19T07:58:25.383 回答
0

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

private void textbox_MouseDown(object sender, MouseEventArgs e) {
    if (textbox != null && !string.IsNullOrEmpty(textbox.Text))
    {
        textbox.SelectAll();
    } }
于 2008-11-10T07:07:48.017 回答
0

您是否尝试过MSDN 论坛“Windows Forms General”上建议的解决方案,它只是子类 TextBox?

于 2008-12-22T09:18:47.650 回答
0

我在 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);
    }
于 2009-10-26T15:19:32.273 回答
0

只需从 TextBox 或 MaskedTextBox 派生一个类:

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

并在您的表格上使用它。

于 2010-01-06T05:21:03.937 回答
0

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

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;   
}
于 2011-05-23T18:35:43.810 回答
0

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

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

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

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

我还没有发现任何问题..除了它没有立即选择点击的事实,但我遇到了问题....

于 2012-01-13T16:30:15.370 回答
0

以下解决方案对我有用。我添加了OnKeyDown事件OnKeyUp覆盖以保持 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;
    }
}
于 2012-08-31T08:56:11.643 回答
0

离开控件时设置选择。当你回来时它会在那里。围绕表单进行选项卡,当您返回控件时,将选择所有文本。

如果您通过鼠标进入,那么插入符号将正确放置在您单击的位置。

private void maskedTextBox1_Leave(object sender, CancelEventArgs e)
    {
        maskedTextBox1.SelectAll();
    }
于 2013-06-20T18:31:24.203 回答
0

非常简单的解决方案:

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

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

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

于 2014-09-23T15:03:56.030 回答
0

我发现这个效果最好,当鼠标单击而不是立即释放时:

    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;
    }
于 2015-05-27T15:43:07.817 回答
0

我的解决方案非常原始,但适合我的目的

private async void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (sender is TextBox)
    {
        await Task.Delay(100);
        (sender as TextBox).SelectAll();
    }
}
于 2015-07-19T14:21:03.103 回答
-1

下面似乎工作。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();
    }
于 2008-09-18T22:42:15.503 回答
-1

我创建了一个新的 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
于 2010-04-15T18:05:13.770 回答
-1

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

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

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

于 2014-04-02T13:19:38.213 回答
-1

只需在输入和单击事件上使用 selectall()

private void textBox1_Enter(object sender, EventArgs e)
        {

            textBox1.SelectAll();
        }
        private void textBox1_Click(object sender, EventArgs e)
        {
            textBox1.SelectAll();
        }
于 2015-04-14T10:28:09.650 回答
-1

这在 .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.
于 2015-12-01T19:25:23.747 回答