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

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

textBox.Text = str;

Когда отображается форма, почему текст в texbox отображается выделенным/выбранным?

Ответ 1

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

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

Ответ 2

Поведение TextBox по умолчанию в Windows Forms по умолчанию заключается в том, чтобы выделить весь текст, если он будет сфокусирован в первый раз, введя в него вкладку, но не при нажатии на него. Мы можем увидеть это в Reflector, посмотрев на TextBox OnGotFocus() 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();
        }
    }
}

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

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

Итак, если у вас есть TextBox и вкладка в него, будет выбран весь текст. Если вы нажмете на него, выделение будет удалено, и если вы заново вложите его в него, ваша позиция каретки (и длина выделения равна нулю) будет сохранена. Но если мы программным образом добавим новый 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 в 0. Фактически SelectionStart, который переворачивает переменную TextBox 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(), но тогда мы потеряем подсветку пользователя, если они будут выведены из поля и обратно.

Гадкий? Еще бы. Но это то, что есть.

Ответ 3

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

Пример:

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

Ответ 4

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

View- > Tab Order

Обратите внимание, что этот параметр доступен только в "Вид", если у вас открыто представление формы.

Выбор "Tab Order" открывает вид формы, который позволяет вам выбрать желаемый порядок вкладок, щелкнув элементы управления.

Ответ 5

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

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

И добавьте метод:

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

Ответ 6

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