Создание WinForms TextBox ведет себя как адресная строка вашего браузера

Когда текстовое поле С# WinForms получает фокус, я хочу, чтобы он вел себя как адресная строка вашего браузера.

Чтобы узнать, что я имею в виду, нажмите в адресной строке вашего веб-браузера. Вы заметите следующее поведение:

  • Щелчок в текстовом поле должен выбрать весь текст, если текстовое поле ранее не было сфокусировано.
  • Мышь вниз и перетаскивание в текстовое поле должны выбирать только текст, который я выделил с помощью мыши.
  • Если текстовое поле уже сфокусировано, щелчок не отображает весь текст.
  • Фокусировка текстового поля программно или с помощью клавиатуры, чтобы выбрать весь текст.

Я хочу сделать именно это в WinForms.

БЫСТРОЕ ПРЕДУПРЕЖДЕНИЕ ОШИБОК: пожалуйста, прочитайте следующее, прежде чем отвечать! Спасибо, ребята.: -)

Вызов .SelectAll() во время события .Enter или .GotFocus не будут работа, потому что если пользователь нажал текстовое поле, каретка будет размещена где он нажал, тем самым отменив выбор всех текст.

Вызов .SelectAll() во время события .Click не будет работать, потому что пользователь не сможет выбрать какой-либо текст с помощью мыши; вызов .SelectAll() будет переписывать выбор текста пользователя.

Вызов BeginInvoke ((Action) textbox.SelectAll) при вводе/вводе события не работает, потому что он прерывает правило № 2 выше, он будет удерживать выбор пользователя в фокусе.

Ответ 1

Прежде всего, спасибо за ответы! 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();
    }
}

Насколько я могу судить, это приводит к тому, что текстовое поле ведет себя точно так же, как адресная строка веб-браузера.

Надеюсь, это поможет следующему парню, который пытается решить эту обманчиво простую проблему.

Еще раз спасибо, ребята, за все ваши ответы, которые помогли привести меня к правильному пути.

Ответ 2

Я нашел более простое решение этого. Он включает асинхронное отключение SelectAll, используя Control.BeginInvoke, чтобы он произошел после событий Enter и Click:

В С#:

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

Ваше решение хорошо, но не в одном конкретном случае. Если вы даете фокус TextBox, выбирая диапазон текста, а не просто щелкнув, флаг ужеFocussed не получает значение 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;
        }
    }
}

Ответ 4

Это немного kludgey, но в вашем событии click используйте SendKeys.Send( "{HOME}+{END}" );.

Ответ 5

Выберите событие текстового поля? Или даже событие MouseCaptureChanged работает для меня. - ОК. не работает.

Итак, вы должны сделать 2 вещи:

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

Работает для табуляции (через textBoxes к одному) - call SelectAll() в Enter на всякий случай...

Ответ 6

Ответ на один ответ, который я использую... вы можете пинать себя...

В поле "Ввод событий:

txtFilter.BeginInvoke(новый MethodInvoker (txtFilter.SelectAll));

Ответ 7

'Inside the Enter event
TextBox1.SelectAll();

Хорошо, попробовав, вот что вам нужно:

  • В начале события введите флаг, в котором указано, что вы были в событии ввода
  • В событии Click, если вы установили флаг, вызовите флаг .SelectAll() и reset.
  • В событии MouseMove установите для введенного флага значение false, которое позволит вам щелкнуть выделение без ввода текстового поля.

Это отобразило весь текст в записи, но потом позволил мне выделить часть текста или выделить вам первый клик.

По запросу:

    bool entered = false;
    private void textBox1_Enter(object sender, EventArgs e)
    {
        entered = true;
        textBox1.SelectAll();   //From Jakub 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

Здесь вспомогательная функция, принимающая решение на следующий уровень - повторное использование без наследования.

    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. Вы можете разместить эту функцию в своей форме или, если хотите, как я, где-нибудь в классе утилиты для еще большего повторного использования.

Ответ 9

Это похоже на популярный ответ 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

Это работало для текстового поля 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;      
    }

Ответ 11

SelectAll никогда не работал у меня.

Это работает.

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

Ответ 12

Я нашел еще более простое решение:

Чтобы убедиться, что весь текст выбран при нажатии на текстовое поле, убедитесь, что обработчик 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();
    }

Ответ 13

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

Ниже показано, как работает. Событие ввода обрабатывает табуляцию в элементе управления, а MouseDown работает при нажатии элемента управления.

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

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

Ответ 15

Интересно, что ComboBox с DropDownStyle = Simple имеет в точности то же самое поведение, которое вы ищете, я думаю.

(Если вы уменьшите высоту элемента управления, чтобы не показывать список, а затем на пару пикселей больше - нет эффективной разницы между ComboBox и TextBox.)

Ответ 16

Фактически 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();
    }
}

Ответ 17

Почему бы вам просто не использовать MouseDown-Event в текстовом поле? Он отлично работает для меня и не нуждается в дополнительном логическом значении. Очень чистый и простой, например:

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

Ответ 19

Я назвал SelectAll внутри события MouseUp, и он отлично работал у меня.

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

Ответ 20

Просто выведите класс из TextBox или MaskedTextBox:

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

И используйте его в своих формах.

Ответ 21

Для группы текстовых полей в форме:

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

Я знаю, что это уже было решено, но у меня есть предположение, что я думаю, что это довольно просто.

В событии мыши все, что вам нужно сделать, это разместить

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

Кажется, для меня работает в VB.NET(я знаю, что это вопрос на С#... к сожалению, я вынужден использовать VB на моей работе.. и у меня была эта проблема, что и привело меня сюда...)

Я еще не нашел с ним никаких проблем... кроме того, что он не сразу выбирает клик, но у меня были проблемы с этим....

Ответ 23

Следующее решение работает для меня. Я добавил переопределение события 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;
    }
}

Ответ 24

Установите настройку, когда вы покидаете элемент управления. Он будет там, когда вы вернетесь. Вкладка вокруг формы и когда вы вернетесь к элементу управления, будет выбран весь текст.

Если вы заходите мышью, то каретка будет правильно размещена в точке, где вы нажали.

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

Ответ 25

Ответ может быть на самом деле более простым, чем ВСЕ из приведенных выше, например (в WPF):

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

конечно, я не знаю, как вы хотите использовать этот код, но основная часть, на которую вы смотрите, - это первый вызов .Focus(), а затем вызов .SelectAll();

Ответ 26

Очень простое решение:

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

EDIT: Оригинальный 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 );
    }

* На самом деле следующая последовательность заканчивается частичным выбором текста, но затем, если вы переместите мышь над текстовым полем, весь текст будет выбран снова:

мыши-вниз/текст-выбор/мышь-перемещение-textbox/мышь вверх

Ответ 27

просто используйте selectall() для ввода и нажатия событий

private void textBox1_Enter(object sender, EventArgs e)
        {

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

Ответ 28

Я нахожу эту работу лучше всего, когда щелчок мыши и немедленный выпуск:

    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

Мое решение довольно примитивно, но отлично работает для моей цели

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

Ответ 30

Это работает для меня в .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.