it-swarm.com.ru

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

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

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

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

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

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

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

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

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

150
Judah Gabriel Himango

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

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

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

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

105
Judah Gabriel Himango

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

Ваше решение хорошо, но не в одном конкретном случае. Если вы фокусируете 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;
        }
    }
}
29
nzhenry

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

8
Todd Benning

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

В событии Enter:

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

4
Ian

Нажмите событие текстового поля? Или даже событие 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 к одному) - вызовите SelectAll () в Enter на всякий случай ...

4
Jakub Kotrla

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

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

3
Ross K.
'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;
    }

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

3
MagicKat

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

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

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

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

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

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

ActiveControl = textBox1;
textBox1->SelectionStart = 0;
textBox1->SelectionLength = textBox1->Text->Length;
1
Adam Bruss

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

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

На самом деле 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();
    }
}
0
Ali

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

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

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

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

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

0
george.lund

Вы пробовали решение, предложенное на форуме MSDN "Windows Forms General" , которое просто подклассов TextBox?

0
huseyint

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

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

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

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

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

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

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

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

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

0
Eluem

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

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

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

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

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

0
MDB

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

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

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

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

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

мышь-вниз/выделение текста/мышь-перемещение-текстовое поле/мышь вверх

0
Mauro Sampietro

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

private void textBox1_Enter(object sender, EventArgs e)
        {

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

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

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

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

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

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

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

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

0
Mohammad Mahdipour