Perché il testo nella casella di testo è evidenziato (selezionato) quando viene visualizzato il modulo?


86

Ho un modulo contenente un TextBoxin C # che ho impostato su una stringa come segue:

textBox.Text = str;

Quando viene visualizzato il modulo, perché il testo nel texbox appare evidenziato / selezionato?


La tua domanda potrebbe essere correlato al stackoverflow.com/questions/1140250/...
DarenW

Sei riuscito a risolvere questo problema? Come hai risolto questo problema?
fletcher

@fletcher: non ho ancora avuto modo di guardarlo. Assegnerò la risposta tra pochi giorni.
CJ7

Puoi aggiungere un tag vb.net, poiché il problema è davvero lo stesso e anche la risposta accettata è valida
Andrea Antonangeli

La risposta di BenSmith relativa alla visualizzazione dell'ordine di tabulazione sarà molto utile in questo scenario.
Samitha Chathuranga

Risposte:


130

La casella di testo ha TabIndex0 e TabStopimpostata su true. Ciò significa che al controllo verrà assegnato lo stato attivo quando viene visualizzato il modulo.

Puoi dare a un altro controllo lo 0 TabIndex(se ce n'è uno) e dare alla casella di testo un indice di tabulazione diverso (> 0), oppure impostare TabStopsu false affinché la casella di testo impedisca che ciò accada.


1
Sei sicuro che la casella di testo TabIndex sia impostata su 0? Viene fuori dal suo comportamento?
26071986

@ 26071986 - Bene, ho eseguito un rapido test. Se, su un modulo con una casella di testo e un pulsante, cambio il testo all'interno della casella di testo nel costruttore quando il tabindex è impostato su 0, il testo viene evidenziato. Se il pulsante ha l'indice di tabulazione 0 e l'indice di tabulazione della casella di testo è> 0, il testo non viene evidenziato.
fletcher

Sembra davvero che abbia a che fare con TabIndex - solo che ho cambiato tutti i miei indici di tabulazione degli elementi in modo appropriato (così ho pensato). Si scopre che anche i gruppi hanno indici di tabulazione che è necessario modificare così come tutti i loro elementi contenenti. Quindi, mentre avevo impostato le schede degli elementi da 1 a 9, un gruppo aveva ancora 0, quindi la casella di testo in quel gruppo divenne il primo elemento attivato (quindi aveva i suoi contenuti evidenziati).
atto02392

1
Non è necessariamente correlato ad avere TabIndex = 0, ma certamente accade se il TextBox ha il TabIndex PIÙ BASSO del modulo. Per verificare: impostare TabIndex = 5 nel TextBox e impostare un numero maggiore di 5 in tutti i TabIndex degli altri controlli del form.
Andrea Antonangeli

Ciò accade anche quando si seleziona una nuova TabPage in un TabControl. La stessa soluzione funziona.
JonP

44

Il comportamento predefinito di una casella di testo in Windows Forms consiste nell'evidenziare tutto il testo se viene messo a fuoco per la prima volta mediante tabulazione, ma non se viene fatto clic su di esso. Possiamo vedere questo in Reflector, cercando in la TextBox's OnGotFocus()di override:

protected override void OnGotFocus(EventArgs e)
{
    base.OnGotFocus(e);
    if (!this.selectionSet)
    {
        this.selectionSet = true;
        if ((this.SelectionLength == 0) && (Control.MouseButtons == MouseButtons.None))
        {
            base.SelectAll();
        }
    }
}

È quella dichiarazione if che sta causando il comportamento che non ci piace. Inoltre, per aggiungere la beffa al danno, il Textsetter della proprietà resetta ciecamente quella selectionSetvariabile ogni volta che il testo viene riassegnato:

public override string Text
{
    get
    {
        return base.Text;
    }
    set
    {
        base.Text = value;
        this.selectionSet = false;
    }
}

Quindi, se hai una casella di testo e una scheda in essa, tutto il testo verrà selezionato. Se fai clic su di esso, l'evidenziazione viene rimossa e, se ci si reimposta, la posizione del cursore (e la lunghezza della selezione pari a zero) viene preservata. Ma se impostiamo di nuovo a livello Textdi codice new e tab nella casella di testo, tutto il testo verrà selezionato di nuovo.

Se sei come me e trovi questo comportamento fastidioso e incoerente, allora ci sono due modi per aggirare questo problema.

Il primo, e probabilmente il più semplice, è semplicemente attivare l'impostazione di selectionSetrichiamando DeselectAll()il modulo Load()e ogni volta che le Textmodifiche:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    this.textBox2.SelectionStart = this.textBox2.Text.Length;
    this.textBox2.DeselectAll();
}

( DeselectAll()Solo set SelectionLengtha zero. In realtà SelectionStartche ribalta il TextBox's selectionSetvariabile. Nel caso di cui sopra, la chiamata a DeselectAll()non è necessario poiché stiamo impostando l'inizio e la fine del testo. Ma se abbiamo impostato a qualsiasi altra posizione, come l'inizio del testo, quindi chiamarlo è una buona idea.)

Il modo più permanente è creare il nostro TextBox con il comportamento desiderato attraverso l'ereditarietà:

public class NonSelectingTextBox : TextBox
{
    // Base class has a selectionSet property, but its private.
    // We need to shadow with our own variable. If true, this means
    // "don't mess with the selection, the user did it."
    private bool selectionSet;

    protected override void OnGotFocus(EventArgs e)
    {
        bool needToDeselect = false;

        // We don't want to avoid calling the base implementation
        // completely. We mirror the logic that we are trying to avoid;
        // if the base implementation will select all of the text, we
        // set a boolean.
        if (!this.selectionSet)
        {
            this.selectionSet = true;

            if ((this.SelectionLength == 0) && 
                (Control.MouseButtons == MouseButtons.None))
            {
                needToDeselect = true;
            }
        }

        // Call the base implementation
        base.OnGotFocus(e);

        // Did we notice that the text was selected automatically? Let's
        // de-select it and put the caret at the end.
        if (needToDeselect)
        {
            this.SelectionStart = this.Text.Length;
            this.DeselectAll();
        }
    }

    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            base.Text = value;

            // Update our copy of the variable since the
            // base implementation will have flipped its back.
            this.selectionSet = false;
        }
    }
}

Potresti essere tentato di non chiamare base.OnGotFocus(), ma perderemmo funzionalità utili nella Controlclasse base . E potresti essere tentato di non scherzare affatto con le selectionSetsciocchezze e deselezionare semplicemente il testo ogni volta in OnGotFocus (), ma poi perderemmo l'evidenziazione dell'utente se uscisse dal campo e tornasse indietro.

Brutto? Ci puoi scommettere. Ma è quello che è.


31

Le risposte a questa domanda mi hanno aiutato molto con un problema simile, ma la risposta semplice è solo accennata con molti altri suggerimenti complessi. Basta impostare SelectionStartsu 0dopo aver impostato il testo. Problema risolto!

Esempio:

yourtextbox.Text = "asdf";
yourtextbox.SelectionStart = 0;

4

Puoi anche scegliere l'ordine di tabulazione per i controlli del modulo aprendo:

Visualizza-> Ordine di tabulazione

Nota che questa opzione è disponibile solo in "Visualizza" se hai aperto la vista Struttura modulo.

Selezionando "Tab Order" si apre una visualizzazione del Form che consente di scegliere l'ordine di tabulazione desiderato facendo clic sui controlli.


1
Questo mi ha aiutato molto. In realtà l'indice di tabulazione non ha importanza se ci occupiamo dell'ordine di tabulazione.
Samitha Chathuranga

1

Per deselezionare un campo di testo, con VS 2013, prova init con:

myTextBox.GotFocus += new System.EventHandler(this.myTextBox_GotFocus);

E aggiungi il metodo:

public void myTextBox_GotFocus(object sender, EventArgs e)
{
    myTextBox.SelectionLength=0;
}

Ciò causerebbe la deselezione del testo se in precedenza hai focalizzato la casella di testo, selezionato del testo in essa, allontanato da esso e quindi focalizzato di nuovo.
Stewart

0

Non l'ho testato su C # ma ho riscontrato lo stesso problema utilizzando una finestra di dialogo C ++ WIN32. Sembra che tu possa cambiare il comportamento tornando FALSEda OnInitDialog()o WM_INITDIALOG. Spero che sia di aiuto.


1
Non penso che questo aiuterà molto, poiché l'API di Windows è incapsulata all'interno di winforms.
Nathan A
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.