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

要明白我的意思,请单击网络浏览器的地址栏。您会注意到以下行为:

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

我想在 WinForms 中做到这一点。

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

在.enter或.gotFocus事件期间呼叫.selectall()无法使用 因为如果用户单击了文本框,则将其放置在他单击的位置,从而取消选择所有文本。

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

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

有帮助吗?

解决方案

首先感谢各位的解答!总共 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();
    }
}

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

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

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

其他提示

我找到了一个更简单的解决方案。它涉及使用异步方式启动 SelectAll Control.BeginInvoke 以便在 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 中(感谢 克里沙努·戴伊)

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

您的解决方案很好,但在一种特定情况下失败了。如果通过选择文本范围而不是仅单击来为 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;
        }
    }
}

这有点混乱,但是在您的点击事件中,使用 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; 
}

也适用于 Tab 键切换(通过文本框到文本框) - 在 Enter 中调用 SelectAll() 以防万一...

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

在输入事件中:

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

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

对我来说,按 Tab 键进入控件会选择所有文本。

这是一个辅助函数,将解决方案提升到一个新的水平 - 无需继承即可重用。

    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 事件中连接所有文本框。您可以将此函数放置在您的表单中,或者如果您像我一样,可以将其放置在实用程序类中的某个位置,以便更多地重用。

这适用于 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;      
    }

这类似于 恩真里的流行答案,但我发现不必子类化更容易:

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;

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

要确保单击文本框时选择所有文本,请确保 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();
    }
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 几乎具有您正在寻找的行为。

(如果您减小控件的高度以不显示列表 - 然后再减少几个像素 - 组合框和文本框之间没有有效的区别。)

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

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 Forms General”上建议的解决方案 它只是 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();
    }
}

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

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 事件处理对控件的 Tab 键切换,并且当单击控件时 MouseDown 起作用。

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

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

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

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

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

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

我还没发现有什么问题..除了它不会立即选择点击这一事实,但我遇到了问题......

以下解决方案对我有用。我添加了 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;
    }
}

当您离开控件时设置选择。当你回来时它就会在那里。在表单周围按 Tab 键,当您返回到控件时,所有文本都将被选中。

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

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

非常简单的解决方案:

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

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

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

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

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.
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top