Как заставить текстовое поле WinForms вести себя подобно адресной строке вашего браузера

StackOverflow https://stackoverflow.com/questions/97459

Вопрос

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

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

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

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

САМАЯ БЫСТРАЯ БОЕВАЯ ТРЕВОГА:пожалуйста, прочтите следующее, прежде чем отвечать! Спасибо, ребята.:-)

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

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

Вызов BeginInvoke(текстовое поле (Действие).selectAll) при вводе события фокусировки / enter не работает поскольку это нарушает правило № 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

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

Вот моя версия решения.Я также поместил код в класс, который наследует 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;
        }
    }
}

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

Событие щелчка по текстовому полю?Или даже событие mousecapture_changed работает у меня.- Хорошо.не работает.

Итак, вам нужно сделать 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; 
}

Работает и для табуляции (через текстовые поля к единице) - на всякий случай вызовите selectAll() в Enter...

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

В событии Ввода:

txtFilter.BeginInvoke(новый метод вызова ( txtFilter.Выбрать все));

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

Для меня при вводе вкладки в элемент управления выделяется весь текст.

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

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

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

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

Чтобы убедиться, что при нажатии на текстовое поле выделяется весь текст, убедитесь, что обработчик щелчка вызывает обработчик ввода.Нет необходимости в дополнительных переменных!

Пример:

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 и TextBox не будет.)

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

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

Я вызвал 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);
    }

Просто создайте класс из 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;   
}

Приведенное ниже, кажется, работает.Событие ввода обрабатывает переход к элементу управления, а наведение курсора мыши срабатывает при нажатии на элемент управления.

    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 на своей работе..и у меня возникла эта проблема, которая и привела меня сюда ...)

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

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

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

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

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