Почему текст в TextBox выделяется (выбирается) при отображении формы?

86

У меня есть форма, содержащая a TextBoxна C #, которую я установил в строку следующим образом:

textBox.Text = str;

Почему при отображении формы текст в текстовом поле выделяется / выделяется?

CJ7
источник
Ваш вопрос может быть связан с stackoverflow.com/questions/1140250/…
DarenW
Удалось ли вам разобраться? Как ты это исправил?
fletcher
@fletcher: Я еще не успел взглянуть на это. Награду ответ через несколько дней.
CJ7
Вы можете добавить тег vb.net, поскольку проблема действительно та же, и принятый ответ также действителен
Андреа Антонанджели
Ответ BenSmith, связанный с просмотром порядка вкладок, будет очень полезен в таком сценарии.
Самита Чатуранга

Ответы:

130

Текстовое поле имеет значение TabIndex0 и имеет TabStopзначение true. Это означает, что элемент управления будет находиться в фокусе при отображении формы.

Вы можете либо дать другому элементу управления значение 0 TabIndex(если он есть) и дать текстовому полю другой индекс табуляции (> 0), либо установить TabStopзначение false для текстового поля, чтобы этого не происходило.

Флетчер
источник
1
Вы уверены, что для текстового поля TabIndex установлено значение 0? Это связано с его поведением?
26071986 06
@ 26071986 - Ну, я провел быстрый тест. Если в форме с одним текстовым полем и кнопкой я изменяю текст в текстовом поле в конструкторе, когда для tabindex установлено значение 0, текст выделяется. Если кнопка имеет индекс табуляции 0, а индекс табуляции текстового поля> 0, текст не выделяется.
fletcher
Похоже, это действительно связано с TabIndex - только я соответствующим образом изменил индексы вкладок всех элементов (так я подумал). Оказывается, у групп тоже есть индексы вкладок, которые вам нужно изменить, а также все содержащиеся в них элементы. Итак, пока я настраивал вкладки элементов с 1 по 9, в группе все еще оставалось 0, поэтому текстовое поле в этой группе стало первым активированным элементом (следовательно, его содержимое было выделено).
deed02392 08
1
Это не обязательно связано с наличием TabIndex = 0, но, безусловно, происходит, если TextBox имеет САМЫЙ НИЗКИЙ TabIndex формы. Чтобы проверить: установите TabIndex = 5 в TextBox и установите число больше 5 во всех TabIndex других элементов управления формы.
Андреа Антонанджели
Это также происходит, когда вы выбираете новую вкладку TabPage в TabControl. То же решение работает.
JonP
44

Поведение TextBox по умолчанию в Windows Forms заключается в выделении всего текста, если он становится сфокусированным в первый раз, путем перехода к нему, но не при нажатии на него. Мы можем увидеть это в рефлектор, посмотрев на TextBox«S OnGotFocus()переопределение:

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

Это оператор if, который вызывает поведение, которое нам не нравится. Кроме того, чтобы добавить оскорбления к травме, Textустановщик свойства вслепую сбрасывает эту selectionSetпеременную всякий раз, когда текст переназначается:

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

Поэтому, если у вас есть TextBox и вкладка, весь текст будет выделен. Если вы щелкнете по нему, выделение будет удалено, а если вы перейдете в него, ваше положение курсора (и длина выделения, равная нулю) сохранится. Но если мы программно установим new Textи снова введем вкладку в TextBox, тогда весь текст будет снова выбран.

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

Первый и, вероятно, самый простой - просто запустить настройку selectionSet, вызвав DeselectAll()форму Load()и всякий раз, когда Textменяются:

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

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

( DeselectAll()Только наборы SelectionLengthк нулю. Это на самом деле , SelectionStartчто переворачивает TextBox«s selectionSetпеременной. В приведенном выше случае, вызов DeselectAll()не является необходимым , так как мы устанавливаем начало в конце текста. Но если мы устанавливаем его в любое другое положение, как начало текста, а затем его вызов - хорошая идея.)

Более постоянный способ - создать наш собственный TextBox с желаемым поведением через наследование:

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

У вас может возникнуть соблазн просто не вызывать base.OnGotFocus(), но тогда мы потеряем полезную функциональность в базовом Controlклассе. И у вас может возникнуть соблазн вообще не связываться с selectionSetерундой и просто каждый раз снимать выделение текста в OnGotFocus (), но тогда мы потеряем выделение пользователя, если они будут выходить из поля и обратно.

Некрасиво? Еще бы. Но что есть, то есть.

Николай Пясецкий
источник
31

Ответы на этот вопрос очень помогли мне с аналогичной проблемой, но простой ответ лишь намекает на множество других сложных предложений. Просто установите SelectionStartзначение 0после установки текста. Задача решена!

Пример:

yourtextbox.Text = "asdf";
yourtextbox.SelectionStart = 0;
Фрэнк Т. Кларк
источник
4

Вы также можете выбрать порядок табуляции для элементов управления вашей формы, открыв:

Просмотр-> Порядок табуляции

Обратите внимание, что этот параметр доступен только в «Представлении», если у вас открыто представление дизайна формы.

При выборе «Порядок вкладок» открывается вид формы, который позволяет вам выбрать желаемый порядок вкладок, щелкнув элементы управления.

Бен Смит
источник
1
Это мне очень помогло. На самом деле индекс табуляции не имеет значения, если мы говорим о порядке табуляции.
Самита Чатуранга,
1

Чтобы отменить выделение текстового поля в VS 2013, попробуйте выполнить init с помощью:

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

И добавляем метод:

public void myTextBox_GotFocus(object sender, EventArgs e)
{
    myTextBox.SelectionLength=0;
}
Марти
источник
Это приведет к отмене выделения текста, если вы ранее сфокусировали текстовое поле, выделили в нем какой-то текст, отодвинулись от него, а затем снова сфокусировали его.
Стюарт
0

Я не тестировал это на C #, но я столкнулся с той же проблемой, используя диалоговое окно C ++ WIN32. Кажется, вы можете изменить поведение, вернувшись FALSEиз OnInitDialog()или WM_INITDIALOG. Надеюсь это поможет.

user3658040
источник
1
Я не думаю, что это сильно поможет, поскольку Windows API инкапсулируется внутри winforms.
Nathan A