Заставить WinForms TextBox вести себя как адресная строка вашего браузера - PullRequest
149 голосов
/ 19 сентября 2008

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

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

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

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

Предупреждение о быстром огнестрельном оружии: пожалуйста, прочитайте следующее, прежде чем ответить! Спасибо, ребята. : -)

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

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

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

Ответы [ 31 ]

105 голосов
/ 19 сентября 2008

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

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

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

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

74 голосов
/ 28 июля 2011

Я нашел более простое решение для этого. Он включает в себя асинхронное отключение 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
29 голосов
/ 09 сентября 2010

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

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

4 голосов
/ 19 сентября 2008

Событие клика в текстовом поле? Или даже событие 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; 
}

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

4 голосов
/ 07 апреля 2009

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

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

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

3 голосов
/ 19 сентября 2008
'Inside the Enter event
TextBox1.SelectAll();

Хорошо, после попытки вот что вы хотите:

  • В событии 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;
    }

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

3 голосов
/ 07 августа 2011

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

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

2 голосов
/ 02 мая 2012

Это похоже на популярный ответ 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
2 голосов
/ 08 марта 2013

Это сработало для текстового поля 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;      
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...