Dlaczego tekst w TextBox jest podświetlony (zaznaczony), gdy jest wyświetlany formularz?

85

Mam formularz zawierający a TextBoxw C #, który ustawiam na ciąg w następujący sposób:

textBox.Text = str;

Dlaczego po wyświetleniu formularza tekst w polu tekstowym jest podświetlony / zaznaczony?

CJ7
źródło
Twoje pytanie może dotyczyć stackoverflow.com/questions/1140250/ ...
DarenW,
Czy udało ci się to rozwiązać? Jak to naprawiłeś?
fletcher
@fletcher: Nie udało mi się jeszcze na to spojrzeć. Za kilka dni udzielę odpowiedzi.
CJ7
Możesz dodać tag vb.net, ponieważ problem jest naprawdę ten sam, a zaakceptowana odpowiedź jest również ważna
Andrea Antonangeli
Odpowiedź BenSmitha dotycząca przeglądania kolejności zakładek będzie bardzo przydatna w takim scenariuszu.
Samitha Chathuranga,

Odpowiedzi:

129

Pole tekstowe ma TabIndex0 i jest TabStopustawione na true. Oznacza to, że po wyświetleniu formularza fokus zostanie przypisany do kontrolki.

Możesz albo nadać innej kontrolce 0 TabIndex(jeśli istnieje) i nadać polu tekstowemu inny indeks tabulatora (> 0) lub ustawić TabStopna fałsz, aby pole tekstowe to powstrzymało.

fletcher
źródło
1
Czy na pewno pole tekstowe TabIndex jest ustawione na 0? Wynika z jego zachowania?
26071986
@ 26071986 - Cóż, przeprowadziłem szybki test. Jeśli w formularzu z jednym polem tekstowym i przyciskiem zmienię tekst w polu tekstowym w konstruktorze, gdy tabindex jest ustawiony na 0, tekst jest podświetlony. Jeśli przycisk ma indeks zakładki 0, a indeks tabulacji pola tekstowego jest> 0, tekst nie jest podświetlony.
fletcher
Rzeczywiście wydaje się, że ma to związek z TabIndex - tylko ja odpowiednio zmieniłem indeksy wszystkich moich elementów (tak pomyślałem). Okazuje się, że grupy również mają indeksy tabulatorów, które należy zmienić, a także wszystkie zawierające je elementy. Tak więc, podczas gdy ustawiłem zakładki elementów od 1 do 9, grupa nadal miała 0, więc pole tekstowe w tej grupie stało się pierwszym aktywowanym elementem (stąd jego zawartość została podświetlona).
deed02392
1
Niekoniecznie jest to związane z posiadaniem TabIndex = 0, ale z pewnością dzieje się tak, jeśli TextBox ma NAJNIŻSZY TabIndex formularza. Aby sprawdzić: ustaw TabIndex = 5 w TextBox i ustaw liczbę większą niż 5 we wszystkich TabIndexs innych kontrolek formularza.
Andrea Antonangeli
Dzieje się tak również po wybraniu nowej TabPage w TabControl. To samo rozwiązanie działa.
JonP
44

Domyślnym zachowaniem TextBox w Windows Forms jest podświetlenie całego tekstu, jeśli zostanie on skupiony po raz pierwszy, przechodząc do niego, ale nie, jeśli zostanie kliknięty. Widzimy to w reflektor patrząc na TextBox„s OnGotFocus()ręcznym:

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

Chodzi o to, że jeśli stwierdzenie powoduje zachowanie, którego nie lubimy. Ponadto, aby dodać zniewagę do obrażeń, Textustawiacz właściwości ślepo resetuje tę selectionSetzmienną za każdym razem, gdy tekst jest ponownie przypisywany:

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

Więc jeśli masz TextBox i kartę, cały tekst zostanie zaznaczony. Jeśli klikniesz na niego, podświetlenie zostanie usunięte, a jeśli ponownie przejdziesz do niego tabulatorem, pozycja kursora (i długość zaznaczenia równa zero) zostanie zachowana. Ale jeśli programowo ustawimy nowyText i ponownie przejdziemy do TextBox, cały tekst zostanie ponownie zaznaczony.

Jeśli jesteś podobny do mnie i uważasz to zachowanie za irytujące i niespójne, istnieją dwa sposoby obejścia tego problemu.

Pierwszym i prawdopodobnie najłatwiejszym jest po prostu wywołanie ustawienia selectionSetprzez wywołanie DeselectAll()formularza Load()i za każdym razem, gdy Textzmiany:

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

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

( DeselectAll()po prostu ustawia SelectionLengthna zero. Właściwie SelectionStartto odwraca zmienną TextBox' selectionSet. W powyższym przypadku wywołanie DeselectAll()nie jest konieczne, ponieważ ustawiamy początek na koniec tekstu. Ale jeśli ustawimy go na inną pozycję, na przykład początek tekstu, a następnie nazwanie go jest dobrym pomysłem).

Bardziej trwałym sposobem jest utworzenie własnego TextBox z pożądanym zachowaniem poprzez dziedziczenie:

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

Może kusiło Cię, aby po prostu nie dzwonić base.OnGotFocus(), ale wtedy stracilibyśmy użyteczną funkcjonalność w Controlklasie bazowej . I możesz ulec pokusie, aby nie zadzierać zselectionSet bzdurami i po prostu odznaczać tekst za każdym razem w OnGotFocus (), ale wtedy stracilibyśmy wyróżnienie użytkownika, gdyby wyszedł z pola iz powrotem.

Brzydki? Jasne. Ale tak właśnie jest.

Mikołaja Piaseckiego
źródło
31

Odpowiedzi na to pytanie bardzo mi pomogły w podobnym problemie, ale do prostej odpowiedzi podpowiada tylko wiele innych złożonych sugestii. Wystarczy ustawić SelectionStart, aby 0po ustawieniu tekstu. Problem rozwiązany!

Przykład:

yourtextbox.Text = "asdf";
yourtextbox.SelectionStart = 0;
Frank T. Clark
źródło
4

Możesz również wybrać kolejność zakładek dla kontrolek formularza, otwierając:

Widok-> Kolejność zakładek

Zauważ, że ta opcja jest dostępna tylko w „Widok”, jeśli masz otwarty widok projektu formularza.

Wybranie „Kolejność zakładek” otwiera widok formularza, który pozwala wybrać żądaną kolejność zakładek, klikając kontrolki.

Ben Smith
źródło
1
To mi bardzo pomogło. W rzeczywistości indeks zakładek nie ma znaczenia, jeśli chodzi o kolejność zakładek.
Samitha Chathuranga,
1

Aby usunąć podświetlenie pola tekstowego, w VS 2013 spróbuj zainicjować za pomocą:

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

I dodaj metodę:

public void myTextBox_GotFocus(object sender, EventArgs e)
{
    myTextBox.SelectionLength=0;
}
Marty
źródło
Spowoduje to usunięcie zaznaczenia tekstu, jeśli wcześniej wyostrzyłeś pole tekstowe, zaznaczyłeś jakiś tekst w nim, odsunąłeś się od niego, a następnie ponownie wyostrzyłeś.
Stewart
0

Nie testowałem tego w C #, ale napotkałem ten sam problem przy użyciu okna dialogowego C ++ WIN32. Wygląda na to, że możesz zmienić zachowanie, wracając FALSEzOnInitDialog() lub WM_INITDIALOG. Mam nadzieję że to pomoże.

user3658040
źródło
1
Myślę, że to nie pomoże, ponieważ interfejs API systemu Windows jest zamknięty w winforms.
Nathan A