Pergunta

Quando uma caixa de texto C # WinForms recebe foco, eu quero que ele se comportar como barra de endereços do seu navegador.

Para ver o que quero dizer, clique na barra de endereços do seu navegador. Você vai notar o seguinte comportamento:

  1. Ao clicar na caixa de texto deve selecionar todo o texto, se a caixa de texto não foi anteriormente focado.
  2. Mouse para baixo e arraste a caixa de texto deve selecionar apenas o texto Eu destacou com o mouse.
  3. Se a caixa de texto já está focado, clicando não selecionar todo o texto.
  4. Com foco na caixa de texto por meio de programação ou por meio de tabulação teclado deve selecionar todo o texto.

Eu quero fazer exatamente isso em WinForms.

MAIS RÁPIDO GUN ALERT: Por favor, leia o seguinte antes de responder Obrigado rapazes. : -)

Chamando .SelectAll () durante os eventos .Enter ou .GotFocus não vai trabalho , porque se o usuário clicou no caixa de texto, o cursor será colocado onde ele clicou, desmarcando assim todo texto.

Chamando .SelectAll () durante o evento .Clique não funcionará porque o usuário não será capaz de selecionar qualquer texto com o mouse; a chamada .SelectAll () irá manter substituindo seleção de texto do usuário.

Chamando BeginInvoke ((Ação) textbox.SelectAll) no foco / enter evento ENTER não trabalho porque ele infringe a regra # 2 acima, ele irá manter substituindo a seleção do usuário no foco.

Foi útil?

Solução

Antes de tudo, obrigado por respostas! 9 respostas totais. Obrigado.

A má notícia: todas as respostas tinha algumas peculiaridades ou não funcionou muito bem (ou em todos). Eu adicionei um comentário para cada um de seus posts.

Boa notícia: Eu encontrei uma maneira de fazê-lo funcionar. Esta solução é bastante simples e parece funcionar em todos os cenários (passar o mouse para baixo, selecionando o texto, tabulação foco, etc.)

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

Tanto quanto eu posso dizer, isso faz com que uma caixa de texto para se comportar exatamente como barra de endereços do navegador.

Esperamos que isso ajude o próximo cara que tenta resolver este problema aparentemente simples.

Mais uma vez obrigado, rapazes, por todas as suas respostas que ajudaram a levar-me para o caminho correto.

Outras dicas

Eu encontrei uma solução simples para isso. Trata-se dando início à SelectAll de forma assíncrona usando Control.BeginInvoke para que ele ocorre após ter ocorrido os eventos Enter e clique em:

Em C #:

private void MyTextBox_Enter(object sender, EventArgs e)
{
    // Kick off SelectAll asyncronously so that it occurs after Click
    BeginInvoke((Action)delegate
    {
        MyTextBox.SelectAll();
    });
}

Em VB.NET (graças a Krishanu Dey )

Private Sub MyTextBox_Enter(sender As Object, e As EventArgs) Handles MyTextBox.Enter 
    BeginInvoke(DirectCast(Sub() MyTextBox.SelectAll(), Action)) 
End Sub

A sua solução é boa, mas falha em um caso específico. Se você dá o foco TextBox, selecionando um intervalo de texto em vez de clicar apenas, a bandeira alreadyFocussed não se definido como verdadeiro, então quando você clicar na caixa de texto uma segunda vez, todo o texto é selecionado.

Aqui é a minha versão da solução. Eu também colocar o código em uma classe que herda de caixa de texto, então a lógica é muito bem escondido.

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

É um pouco kludgey, mas em seu evento clique, uso SendKeys.Send( "{HOME}+{END}" );.

Clique caso de caixa de texto? Ou mesmo evento MouseCaptureChanged funciona para mim. - ESTÁ BEM. não funciona.

Então você tem que fazer 2 coisas:

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

Obras para tabulação (por meio de caixas de texto para o único), bem como - SelectAll call () em Digite apenas no caso ...

A resposta de uma linha que eu uso ... você pode estar retrocedendo-se ...

Na caixa Digite evento:

txtFilter.BeginInvoke (novo MethodInvoker (txtFilter.SelectAll));

'Inside the Enter event
TextBox1.SelectAll();

Ok, depois de tentar aqui é o que você quer:

  • No evento Enter iniciar uma bandeira que indica que têm sido no entrar evento
  • No evento Click, se você definir o sinalizador, chamar .SelectAll () e redefinir o sinalizador.
  • No evento MouseMove, defina o sinalizador entrou para falso, o que permitirá que você clique destaque sem ter de introduzir a caixa de texto em primeiro lugar.

Esta selecionado todo o texto na entrada, mas me permitiu parte destaque do texto depois, ou permitir que você destaque no primeiro clique.

Por solicitação:

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

Para mim, a tabulação nas seleciona o controle todo o texto.

Aqui está uma função auxiliar de tomar a solução para o próximo nível -. Reutilização sem herança

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

Para usar isso simplesmente chamar a função passando uma caixa de texto e ele cuida de todos os bits confuso para você. Sugiro fiação até todas as suas caixas de texto no evento Form_Load. Você pode colocar esta função em sua forma, ou se você gosta de mim, em algum lugar em uma classe de utilitário para ainda mais reutilização.

Isso funcionou por um XAML TextBox WPF /.

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

Este é semelhante ao nzhenry 's resposta popular, mas acho que é mais fácil para não ter de subclasse:

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 nunca trabalhou para mim.

Isso funciona.

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

Eu encontrei uma solução ainda mais simples:

Para se certificar de todo o texto é selecionado ao clicar em uma caixa de texto, certifique-se de que o manipulador de clique chama o manipulador Enter. Não há necessidade de variáveis ??extras!

Exemplo:

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

Curiosamente, uma caixa de combinação com DropDownStyle = Simples tem muito bonito exatamente o comportamento que você está procurando, eu acho.

(Se você reduzir a altura do controle para não mostrar a lista - e depois por um par de pixels mais -. Não há diferença efectiva entre a ComboBox e TextBox)

Por que você não simplesmente usar o MouseDown-evento da caixa de texto? Ele funciona muito bem para mim e não precisa de um boolean adicional. Muito limpo e simples, por exemplo:.

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

Eu chamei SelectAll dentro evento MouseUp e funcionou muito bem para mim.

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

Apenas derivar uma classe de TextBox ou MaskedTextBox:

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

E usá-lo em seus formulários.

Você já tentou a solução sugerida no Fórum MSDN "Windows Forms Geral" que simplesmente subclasses TextBox?

Na verdade GotFocus é o evento certo (mensagem realmente) que você está interessado, desde que não importa como você chegar ao controle que você vai ter esse mesmo eventualmente. A questão é quando você chama SelectAll ().

Tente isto:

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

Para um grupo de caixas de texto em um formulário:

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

A seguir parece trabalho. A entrar alças de eventos a tabulação para o controle ea MouseDown funciona quando o controle é clicado.

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

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

Eu sei que isso já estava resolvido, mas eu tenho uma sugestão que eu acho que é realmente bastante simples.

No rato para cima do evento tudo que você tem a fazer é colocar

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

Parece que funciona para mim em VB.NET (eu sei que isso é uma questão C # ... infelizmente eu sou forçado a usar VB no meu trabalho .. e eu estava tendo este problema, que é o que me trouxe aqui ...)

Eu não encontrei nenhum problema com ele ainda .. exceto pelo fato de que ele não selecionar imediatamente no clique, mas eu estava tendo problemas com isso ....

A solução a seguir funciona para mim. Eu adicionei OnKeyDown e eventos OnKeyUp override para manter o texto TextBox sempre selecionado.

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

Defina o selction quando sair do controle. Ele vai estar lá quando você voltar. Guia em torno da forma e quando você voltar ao controle, todo o texto será selecionado.

Se você entrar com o mouse, em seguida, o acento circunflexo será justamente colocado no ponto onde você clicou.

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

A resposta pode ser realmente muito mais simples do que todos os itens acima, por exemplo (em WPF):

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

é claro que eu não posso saber como você deseja usar esse código, mas a parte principal de olhar para aqui é: Primeira chamada .focus () e, em seguida, chamar .SelectAll ();

solução muito simples:

    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 original era particularmente preocupado com a sequência de ratinho-baixo /-selecção de texto /-rato-se, caso em que o acima solução simples acabaria com o texto a ser parcialmente seleccionado

Isto deve resolver o problema * (na prática eu interceptar 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 );
    }

* Na verdade, a seguinte seqüência termina com a seleção de texto parcial, mas, em seguida, se você mover o mouse sobre a caixa de texto todo o texto será selecionado novamente:

rato-down /-seleção de texto / mouse-movimento fora caixa de texto / rato-up

apenas usar selectAll () na entrada e clique em eventos

private void textBox1_Enter(object sender, EventArgs e)
        {

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

I encontrar este trabalho melhor, quando o mouse clique e não libertar imediatamente:

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

A minha solução é bastante primitivo, mas funciona bem para o meu propósito

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

Esse é um trabalho para mim em .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.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top