制作WinForms TextBox的行为与浏览器的地址栏相似

时间:2008-09-18 22:02:18

标签: .net winforms user-interface textbox

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

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

  1. 如果文本框之前没有聚焦,则单击文本框应选择所有文本。
  2. 鼠标按下并在文本框中拖动时,应仅选择我用鼠标突出显示的文本。
  3. 如果文本框已经聚焦,则单击不会选择所有文本。
  4. 以编程方式或通过键盘标签对焦文本框应选择所有文本。
  5. 我想在WinForms中做到这一点。

    最快枪支警告:请在回答之前阅读以下内容!谢谢大家。 : - )

      

    在调用期间调用.SelectAll()   .Enter或.GotFocus事件不会   工作因为如果用户点击了   文本框,将放置插入符号   他点击的地方,从而取消了全部   文本。

         

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

         

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

31 个答案:

答案 0 :(得分:105)

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

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

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

再次感谢各位,您的所有答案都帮助我走上了正确的道路。

答案 1 :(得分:74)

我找到了一个更简单的解决方案。它涉及使用Control.BeginInvoke异步启动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

答案 2 :(得分:29)

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

答案 3 :(得分:8)

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

答案 4 :(得分:4)

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

在输入事件中:

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

答案 5 :(得分: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; 
}

也适用于Tab键(通过textBoxes到一个) - 在Enter中调用SelectAll()以防万一...

答案 6 :(得分: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;
    }

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

答案 7 :(得分: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事件中连接所有文本框。您可以将此功能放在表单中,或者如果您喜欢我,可以在实用程序类中的某个位置进行更多重用。

答案 8 :(得分:2)

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

答案 9 :(得分: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

答案 10 :(得分:1)

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

要确保在单击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();
    }

答案 11 :(得分:1)

SelectAll从未为我工作过。

这很有效。

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

答案 12 :(得分: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;
    }

答案 13 :(得分:0)

只需在输入并单击事件

上使用selectall()
private void textBox1_Enter(object sender, EventArgs e)
        {

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

答案 14 :(得分:0)

我的解决方案很原始,但我的目的很好用

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

答案 15 :(得分: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特别关注鼠标按下/文本选择/鼠标按下序列,在这种情况下,上述简单解决方案最终会部分选择文本。< / p>

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

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

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

答案 16 :(得分:0)

这在.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.

答案 17 :(得分:0)

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

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

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

答案 18 :(得分:0)

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

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

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

答案 19 :(得分:0)

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

答案 20 :(得分:0)

我知道这已经解决但我有一个建议,我认为其实很简单。

在鼠标注册事件中,您只需要放置

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

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

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

答案 21 :(得分: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;   
}

答案 22 :(得分:0)

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

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

并在表单上使用它。

答案 23 :(得分: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);
    }

答案 24 :(得分:0)

您是否尝试过简单地将TextBox子类化的the solution suggested on the MSDN Forum "Windows Forms General"

答案 25 :(得分:0)

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

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

答案 26 :(得分: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();
    }
}

答案 27 :(得分:0)

有趣的是,我认为使用DropDownStyle = Simple的ComboBox几乎就是你正在寻找的行为。

(如果你将控件的高度减少到不显示列表 - 然后再增加几个像素 - 那么ComboBox和TextBox之间没有任何有效的区别。)

答案 28 :(得分:0)

以下似乎有效。 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();
    }

答案 29 :(得分: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();
    }
}

答案 30 :(得分:-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
相关问题