Fare in modo che una casella di testo WinForms si comporti come la barra degli indirizzi del tuo browser

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

Domanda

Quando una casella di testo C# WinForms riceve lo stato attivo, voglio che si comporti come la barra degli indirizzi del browser.

Per capire cosa intendo, fai clic sulla barra degli indirizzi del tuo browser web.Noterai il seguente comportamento:

  1. Facendo clic nella casella di testo si dovrebbe selezionare tutto il testo se la casella di testo non era stata precedentemente focalizzata.
  2. Tieni premuto il mouse e trascina nella casella di testo per selezionare solo il testo che ho evidenziato con il mouse.
  3. Se la casella di testo è già focalizzata, facendo clic non si seleziona tutto il testo.
  4. Mettere a fuoco la casella di testo a livello di codice o tramite tabulazione della tastiera dovrebbe selezionare tutto il testo.

Voglio fare esattamente questo in WinForms.

AVVISO DELLA PISTOLA PIÙ VELOCE:per favore leggi quanto segue prima di rispondere! Grazie ragazzi.:-)

Chiamare .selectall () durante gli eventi .enter o .gotfocus non funzionano Perché se l'utente ha fatto clic sulla casella di testo, il carezza verrà posizionato dove ha fatto clic, deselezionando così tutto il testo.

La chiamata a .SelectAll() durante l'evento .Click non funzionerà perché l'utente non potrà selezionare alcun testo con il mouse;la chiamata .SelectAll() continuerà a sovrascrivere la selezione di testo dell'utente.

La chiamata a BeginInvoke((Action)textbox.SelectAll) sull'evento focus/enter enter non funziona poiché infrange la regola n. 2 di cui sopra, continuerà a sovrascrivere la selezione dell'utente sul focus.

È stato utile?

Soluzione

Innanzitutto grazie per le risposte!9 risposte totali.Grazie.

Cattive notizie:tutte le risposte presentavano alcune stranezze o non funzionavano del tutto correttamente (o non funzionavano affatto).Ho aggiunto un commento a ciascuno dei tuoi post.

Buone notizie:Ho trovato un modo per farlo funzionare.Questa soluzione è piuttosto semplice e sembra funzionare in tutti gli scenari (scorrimento del mouse verso il basso, selezione del testo, messa a fuoco mediante tabulazione, ecc.)

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

Per quanto ne so, questo fa sì che una casella di testo si comporti esattamente come la barra degli indirizzi di un browser web.

Speriamo che questo aiuti il ​​prossimo che cercherà di risolvere questo problema apparentemente semplice.

Grazie ancora, ragazzi, per tutte le vostre risposte che mi hanno aiutato a guidarmi verso la strada corretta.

Altri suggerimenti

Ho trovato una soluzione più semplice a questo.Implica l'avvio di SelectAll in modo asincrono utilizzando Control.BeginInvoke in modo che si verifichi dopo che si sono verificati gli eventi Enter e Click:

In C#:

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

In VB.NET (grazie a Krishanu Dey)

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

La tua soluzione è buona, ma fallisce in un caso specifico.Se dai il focus alla casella di testo selezionando un intervallo di testo invece di fare semplicemente clic, il flag già Focussed non viene impostato su true, quindi quando fai clic nella casella di testo una seconda volta, tutto il testo viene selezionato.

Ecco la mia versione della soluzione.Ho anche inserito il codice in una classe che eredita TextBox, quindi la logica è ben nascosta.

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

È un po' complicato, ma nel tuo evento click usa SendKeys.Send( "{HOME}+{END}" );.

Fare clic sull'evento della casella di testo?O anche l'evento MouseCaptureChanged funziona per me.- OK.non funziona.

Quindi devi fare 2 cose:

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

Funziona anche per il tabulazione (tramite textBoxes fino a quello): chiama SelectAll() in Invio per ogni evenienza...

Una risposta di una riga che utilizzo... potresti prenderti a calci da solo...

Nell'evento di ingresso:

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

'Inside the Enter event
TextBox1.SelectAll();

Ok, dopo averlo provato ecco cosa vuoi:

  • All'evento Enter inizia una bandiera che indica che sei stato nell'evento enter
  • Nell'evento Click, se imposti il ​​flag, chiama .SelectAll() e reimposta il flag.
  • Nell'evento MouseMove, imposta il flag inserito su false, che ti consentirà di fare clic sull'evidenziazione senza dover prima inserire la casella di testo.

Ciò ha selezionato tutto il testo all'immissione, ma mi ha permesso di evidenziare parte del testo in seguito o di consentirti di evidenziarlo al primo clic.

Su richiesta:

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

Per me, la scheda nel controllo seleziona tutto il testo.

Ecco una funzione di supporto che porta la soluzione al livello successivo: riutilizzo senza ereditarietà.

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

Per usarlo è sufficiente chiamare la funzione che passa un TextBox e si prenderà cura di tutti i bit disordinati per te.Suggerisco di collegare tutte le caselle di testo nell'evento Form_Load.Puoi inserire questa funzione nel tuo modulo o, se sei come me, da qualche parte in una classe di utilità per un riutilizzo ancora maggiore.

Questo ha funzionato per una casella di testo 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;      
    }

Questo è simile a nzhenryè la risposta popolare, ma trovo più semplice non dover creare una sottoclasse:

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 non ha mai funzionato per me.

Funziona.

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

Ho trovato una soluzione ancora più semplice:

Per assicurarti che tutto il testo sia selezionato quando fai clic su una casella di testo, assicurati che il gestore Click chiami il gestore Enter.Non c'è bisogno di variabili extra!

Esempio:

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

È interessante notare che un ComboBox con DropDownStyle=Simple ha praticamente esattamente il comportamento che stai cercando, credo.

(Se riduci l'altezza del controllo per non mostrare l'elenco, e quindi di un paio di pixel in più, non c'è alcuna differenza effettiva tra ComboBox e TextBox.)

Perché non usi semplicemente l'evento MouseDown della casella di testo?Funziona bene per me e non ha bisogno di un valore booleano aggiuntivo.Molto pulito e semplice, ad esempio:

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

Ho chiamato SelectAll all'interno dell'evento MouseUp e ha funzionato bene per me.

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

Basta derivare una classe da TextBox o MaskedTextBox:

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

E usalo sui tuoi moduli.

Hai provato la soluzione suggerita sul forum MSDN "Windows Forms General" che semplicemente sottoclasse TextBox?

In realtà GotFocus è l'evento giusto (il messaggio in realtà) che ti interessa, poiché non importa come arrivi al controllo, alla fine lo otterrai.La domanda è quando chiami SelectAll().

Prova questo:

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

Per un gruppo di caselle di testo in un modulo:

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

Quanto sotto sembra funzionare.L'evento enter gestisce la tabulazione del controllo e MouseDown funziona quando si fa clic sul controllo.

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

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

So che questo è già stato risolto, ma ho un suggerimento che penso sia in realtà piuttosto semplice.

Nell'evento mouse up tutto quello che devi fare è posizionare

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

Sembra funzionare per me in VB.NET (so che questa è una domanda C#...purtroppo sono costretto a usare VB nel mio lavoro..e stavo avendo questo problema, che è ciò che mi ha portato qui...)

Non ho ancora riscontrato alcun problema con esso..tranne per il fatto che non si seleziona immediatamente al clic, ma ho avuto problemi con quello....

La seguente soluzione funziona per me.Ho aggiunto OnKeyDown E OnKeyUp override dell'evento per mantenere il testo della casella di testo sempre selezionato.

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

Imposta la selezione quando lasci il controllo.Sarà lì quando tornerai.Scorri il modulo e quando torni al controllo, tutto il testo verrà selezionato.

Se entri con il mouse, il cursore verrà posizionato correttamente nel punto in cui hai cliccato.

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

La risposta può essere in realtà molto più semplice di TUTTO quanto sopra, ad esempio (in WPF):

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

ovviamente non posso sapere come vuoi utilizzare questo codice, ma la parte principale da guardare qui è:Chiama prima .Focus() e poi chiama .SelectAll();

Soluzione molto semplice:

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

MODIFICARE: L'OP originale era particolarmente preoccupato per la sequenza mouse giù/selezione testo/mouse su, nel qual caso la semplice soluzione di cui sopra finirebbe con il testo parzialmente selezionato.

Questo dovrebbe risolvere* il problema (in pratica intercetto 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 );
    }

*In realtà la sequenza seguente termina con una selezione parziale del testo, ma se si sposta il mouse sulla casella di testo tutto il testo verrà nuovamente selezionato:

mouse giù/selezione testo/muovi-fuori-casella di testo/mouse su

basta usare selectall() sugli eventi enter e click

private void textBox1_Enter(object sender, EventArgs e)
        {

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

Trovo che questo funzioni meglio, quando si fa clic con il mouse e non si rilascia immediatamente:

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

La mia soluzione è piuttosto primitiva ma funziona bene per il mio scopo

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

Funziona per me in .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.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top