代码之家  ›  专栏  ›  技术社区  ›  Judah Gabriel Himango

使WinForms文本框的行为类似于浏览器的地址栏。

  •  149
  • Judah Gabriel Himango  · 技术社区  · 16 年前

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

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

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

    我想在Winforms中实现这一点。

    最快的枪声警报:回答前请阅读以下内容! 谢谢大家。-)

    期间调用.selectAll()。 .enter或.gotfocus事件不会 工作 因为如果用户单击 文本框中,插入符号将被放置 他点击的地方,因此取消了所有 文本。

    在.click事件期间调用.selectall()将不起作用 因为用户不能用鼠标选择任何文本;.selectAll()调用将不断覆盖用户的文本选择。

    对Focus/Enter事件Enter调用BeginInvoke((操作)文本框.SelectAll)不起作用 因为它违反了上面的规则2,它将继续覆盖用户对焦点的选择。

    31 回复  |  直到 16 年前
        1
  •  104
  •   Judah Gabriel Himango    14 年前

    首先,谢谢你的回答!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浏览器的地址栏完全相同。

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

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

        2
  •  72
  •   Community arnoo    7 年前

    我找到了一个更简单的解决办法。它涉及异步启动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中(感谢 Krishanu Dey )

    Private Sub MyTextBox_Enter(sender As Object, e As EventArgs) Handles MyTextBox.Enter 
        BeginInvoke(DirectCast(Sub() MyTextBox.SelectAll(), Action)) 
    End Sub
    
        3
  •  29
  •   nzhenry    14 年前

    您的解决方案是好的,但在一个特定的案例中失败了。如果通过选择文本范围而不是单击来为文本框提供焦点,则alreadyFocused标志不会设置为true,因此当您第二次单击文本框时,所有文本都会被选中。

    这是我的解决方案版本。我还将代码放入了一个继承文本框的类中,这样逻辑就可以很好地隐藏起来。

    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;
            }
        }
    }
    
        4
  •  8
  •   bluish dmajkic    8 年前

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

        5
  •  4
  •   Jakub Kotrla    16 年前

    单击文本框事件?或者即使是鼠标被重新更改的事件也对我有效。好的。不起作用。

    所以你必须做两件事:

    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(),以防万一…

        6
  •  4
  •   Ian    15 年前

    我用一句话回答你…你可能在踢自己…

    在Enter事件中:

    txtfilter.beginInvoke(新的MethodInvoker(txtfilter.selectAll));

        7
  •  3
  •   MagicKat    16 年前
    'Inside the Enter event
    TextBox1.SelectAll();
    

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

    • 在Enter事件上,启动一个标志,说明您已经进入Enter事件。
    • 在Click事件上,如果设置了标志,则调用.SelectAll()并重置标志。
    • 在mousemove事件中,将entered标志设置为false,这样您就可以单击highlight而不必先输入文本框。

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

    按要求:

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

    对于我来说,控件中的制表符选择所有文本。

        8
  •  3
  •   Bo Persson tox    13 年前

    下面是一个帮助函数,它将解决方案提升到下一个层次——无需继承即可重用。

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

    要使用它,只需调用传递文本框的函数,它就可以为您处理所有混乱的位。我建议在窗体“加载事件”中连接所有文本框。您可以将此函数放在表单中,或者如果您喜欢我,可以将其放在实用程序类中的某个位置,以便进一步重用。

        9
  •  2
  •   slobs    11 年前

    这适用于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;      
        }
    
        10
  •  2
  •   Jimi    6 年前

    这和 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
    
        11
  •  1
  •   Adam Bruss    12 年前

    selectall从未为我工作过。

    这是可行的。

    ActiveControl = textBox1;
    textBox1->SelectionStart = 0;
    textBox1->SelectionLength = textBox1->Text->Length;
    
        12
  •  1
  •   Pieter Heemeryck    10 年前

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

    要确保在单击文本框时选中所有文本,请确保单击处理程序调用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();
        }
    
        13
  •  0
  •   Nescio    16 年前
    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();
        }
    }
    
        14
  •  0
  •   george.lund    16 年前

    有趣的是,我认为一个DropDownStyle=Simple的组合框几乎完全符合你想要的行为。

    (如果将控件的高度降低到不显示列表,然后再增加几个像素,则组合框和文本框之间没有有效的区别。)

        15
  •  0
  •   Shihan    16 年前

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

    private void textbox_MouseDown(object sender, MouseEventArgs e) {
        if (textbox != null && !string.IsNullOrEmpty(textbox.Text))
        {
            textbox.SelectAll();
        } }
    
        16
  •  0
  •   Sreejith K.    15 年前

    我在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);
        }
    
        17
  •  0
  •   Peter Mortensen Sumit Kumar    14 年前

    只需从textbox或maskedtextbox派生类:

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

    把它用在你的表格上。

        18
  •  0
  •   Peter Mortensen Sumit Kumar    14 年前

    你试过了吗? the solution suggested on the MSDN Forum "Windows Forms General" 哪个只是文本框的子类?

        19
  •  0
  •   Peter Mortensen Sumit Kumar    14 年前

    实际上,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();
        }
    }
    
        20
  •  0
  •   JohnD    13 年前

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

    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;   
    }
    
        21
  •  0
  •   Community arnoo    13 年前

    下面的内容似乎有效。 Enter事件处理控件的选项卡,当单击控件时,鼠标悬停将工作。

        private ########### void textBox1_Enter(object sender, EventArgs e)
        {
            textBox1.SelectAll();
        }
    
        private void textBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (textBox1.Focused)
                textBox1.SelectAll();
        }
    
        22
  •  0
  •   Eluem    13 年前

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

    在鼠标悬停事件中,您所要做的就是

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

    它在vb.net中似乎对我有用(我知道这是一个c问题…不幸的是,我不得不在工作中使用vb。我遇到了这个问题,这就是我来到这里的原因……)

    我还没有发现任何问题……除了它没有立即选择点击,但我有问题…

        23
  •  0
  •   ЯegDwight kri    12 年前

    以下解决方案适用于我。我补充说 OnKeyDown OnKeyUp 事件重写以始终选中文本框文本。

        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;
        }
    }
    
        24
  •  0
  •   Rob shassss    11 年前

    离开控件时设置selection。你回来的时候它就在那儿。选项卡,当您返回控件时,所有文本都将被选中。

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

    private void maskedTextBox1_Leave(object sender, CancelEventArgs e)
        {
            maskedTextBox1.SelectAll();
        }
    
        25
  •  0
  •   MDB    10 年前

    实际上,答案可能比上述所有问题都要简单得多,例如(在wpf中):

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

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

        26
  •  0
  •   Mauro Sampietro    10 年前

    非常简单的解决方案:

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

    编辑: 最初的操作特别关注鼠标向下/文本选择/鼠标向上顺序,在这种情况下,上述简单的解决方案将以部分选定的文本结束。

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

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

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

        27
  •  0
  •   EKanadily    9 年前

    只需在Enter和Click事件上使用selectAll()。

    private void textBox1_Enter(object sender, EventArgs e)
            {
    
                textBox1.SelectAll();
            }
            private void textBox1_Click(object sender, EventArgs e)
            {
                textBox1.SelectAll();
            }
    
        28
  •  0
  •   user3729779    9 年前

    当鼠标单击而不立即释放时,我发现这是最有效的方法:

        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;
        }
    
        29
  •  0
  •   BlueWizard UmAnusorn    9 年前

    我的解决方案很原始,但对我来说效果很好

    private async void TextBox_GotFocus(object sender, RoutedEventArgs e)
    {
        if (sender is TextBox)
        {
            await Task.Delay(100);
            (sender as TextBox).SelectAll();
        }
    }
    
        30
  •  0
  •   Cody    9 年前

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