Как показать текст в поле со списком, если ни один элемент не выбран?

Вопрос С# и .Net 2.0 (WinForms)

У меня есть набор элементов в ComboBox и не выбран из них. Я хотел бы показать строку в комбо "Пожалуйста, выберите пункт" в этой ситуации.

Текущая реализация просто добавляет пустой элемент с таким текстом в индекс 0 и удаляет его, когда пользователь выбирает один из следующих элементов. К сожалению, пустая позиция также отображается в выпадающем списке. Как избежать этой ситуации или по-другому - есть ли способ показать пользовательский текст на ComboBox, когда элемент не выбран?

Ответы ниже работают, если ComboBoxStyle установлен в DropDown (ComboBox доступен для редактирования). Есть ли возможность сделать это, когда ComboBoxStyle установлено на DropDownList?

Ответы

Ответ 1

Здесь вы можете найти решение, созданное pavlo_ua: Если у вас есть .Net > 2.0 и Если у вас есть .Net == 2.0 (поиск ответа pavlo_ua)

Приветствия, jbk

изменить: Поэтому, чтобы иметь ясный ответ не только ссылку

Вы можете установить Text combobox, когда его стиль установлен как DropDown (и доступен для редактирования). Когда у вас есть .Net-версия < 3.0 нет свойства IsReadonly, поэтому нам нужно использовать win api для установки текстового поля combobox как readonly:

private bool m_readOnly = false;
private const int EM_SETREADONLY = 0x00CF;

internal delegate bool EnumChildWindowsCallBack( IntPtr hwnd, IntPtr lParam );

[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

[ DllImport( "user32.dll" ) ]
internal static extern int EnumChildWindows( IntPtr hWndParent, EnumChildWindowsCallBack lpEnumFunc, IntPtr lParam );


private bool EnumChildWindowsCallBackFunction(IntPtr hWnd, IntPtr lparam)
{
      if( hWnd != IntPtr.Zero )
       {
              IntPtr readonlyValue = ( m_readOnly ) ? new IntPtr( 1 ) : IntPtr.Zero;
             SendMessage( hWnd, EM_SETREADONLY, readonlyValue, IntPtr.Zero );
             comboBox1.Invalidate();
             return true;
       }
       return false;
}

private void MakeComboBoxReadOnly( bool readOnly )
{
    m_readOnly = readOnly;
    EnumChildWindowsCallBack callBack = new EnumChildWindowsCallBack(this.EnumChildWindowsCallBackFunction );
    EnumChildWindows( comboBox1.Handle, callBack, IntPtr.Zero );
}

Ответ 2

Используйте метод вставки combobox для вставки "Пожалуйста, выберите элемент" в 0 индекс,

comboBox1.Items.Insert(0, "Please select any value");

и добавьте все элементы в поле со списком после первого индекса. В форме load set

comboBox1.SelectedIndex = 0;

EDIT:

В форме load напишите текст в comboBox1.Text по жесткому кодированию

comboBox1.Text = "Please, select any value";

а в событии TextChanged из comboBox1 напишите следующий код

 private void comboBox1_TextChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex < 0)
            {
                comboBox1.Text = "Please, select any value";
            }
            else
            {
                comboBox1.Text = comboBox1.SelectedText;
            }
        }

Ответ 3

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

<ComboBox SelectedIndex="0">
    <ComboBoxItem Visibility="Collapsed">Please select one...</ComboBoxItem>
    <ComboBoxItem>1</ComboBoxItem>
    <ComboBoxItem>2</ComboBoxItem>
    <ComboBoxItem>3</ComboBoxItem>
    <ComboBoxItem>4</ComboBoxItem>
</ComboBox>

Идея заключается в том, что первоначальный выбор - это индекс 0, который сбрасывается, поэтому он недоступен при выборе для пользователя, когда они выбирают что-то еще. Недостатком является то, что вы должны помнить, что если вы проверяете выбранный индекс, помните, что индекс 0 означает, что выбор не был сделан.

Ответ 4

    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
        if (comboBox1.Text == "")
            comboBox1.Text = "Select one of the answers"; 
    }

должен сделать трюк при запуске эта строка присутствует, когда выбран элемент в поле со списком, появится этот текст. при удалении текста этот текст снова появится

Ответ 5

Я использовал быструю работу, чтобы сохранить стиль DropDownList.

class DummyComboBoxItem
{
    public string DisplayName
    {
        get
        {
            return "Make a selection ...";
        }
    }
}
public partial class mainForm : Form
{
    private DummyComboBoxItem placeholder = new DummyComboBoxItem();
    public mainForm()
    {
        InitializeComponent();

        myComboBox.DisplayMember = "DisplayName";            
        myComboBox.Items.Add(placeholder);
        foreach(object o in Objects)
        {
            myComboBox.Items.Add(o);
        }
        myComboBox.SelectedItem = placeholder;
    }

    private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (myComboBox.SelectedItem == null) return;
        if (myComboBox.SelectedItem == placeholder) return;            
        /*
            do your stuff
        */
        myComboBox.Items.Add(placeholder);
        myComboBox.SelectedItem = placeholder;
    }

    private void myComboBox_DropDown(object sender, EventArgs e)
    {
        myComboBox.Items.Remove(placeholder);
    }

    private void myComboBox_Leave(object sender, EventArgs e)
    {
        //this covers user aborting the selection (by clicking away or choosing the system null drop down option)
        //The control may not immedietly change, but if the user clicks anywhere else it will reset
        if(myComboBox.SelectedItem != placeholder)
        {
            if(!myComboBox.Items.Contains(placeholder)) myComboBox.Items.Add(placeholder);
            myComboBox.SelectedItem = placeholder;
        }            
    }       
}

Если вы используете привязку данных, вам придется создать фиктивную версию типа, к которому вы привязаны, - просто убедитесь, что вы удалили его перед любой логикой сохранения.

Ответ 6

Сделайте свойство Dropdownstyle в поле со списком в раскрывающемся списке и установите текст в поле со списком "Выбрать", как показано ниже

            combobox.DataSource = dsIn.Tables[0];
            combobox.DisplayMember = "Name";
            combobox.ValueMember = "Value";
            combobox.Text = "--Select--";

Ответ 7

Я не вижу никакого родного способа .NET, но если вы хотите, чтобы ваши руки были грязными с базовыми элементами управления Win32...

Вы должны отправить сообщение CB_GETCOMBOBOXINFO с помощью структуры COMBOBOXINFO, которая будет содержать внутренний дескриптор управления. Затем вы можете отправить управление редактированием сообщение EM_SETCUEBANNER указателем на строку. (Обратите внимание, что для этого требуется включить как минимум XP, так и визуальные стили.

Ответ 8

Одна строка после формы InitializeComponent();

cbo_MyDropBox.Text = "Select a server...";

Вам это нужно только один раз? Все, что вам нужно сделать, если выбор является обязательным, - это проверить, если индекс ящика != -1. Может ли кто-нибудь объяснить, почему другие ответы перепрыгивают через обручи, чтобы добиться этого?

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

Ответ 9

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

    var orginalindex = 0;

    private void comboBox1_SelectedItemChanged(object sender, EventArgs e)
    {
        if (comboBox1.SelectedIndex == 0)
        {
            comboBox1.Text = "Select one of the answers";
            comboBox1.SelectedIndex = comboBox1.SelectedIndex;
        }
        else
        {
            orginalindex = comboBox1.SelectedIndex;
        }
    }

Ответ 10

если ComboBoxStyle установлено на DropDownList, тогда самый простой способ убедиться, что пользователь выбирает элемент, - это установить SelectedIndex = -1, который будет пустым

Ответ 11

Я понимаю, что это старый поток, но просто хотел, чтобы другие, которые могли бы найти ответ на этот вопрос, знали, что в текущей версии Visual Studio (2015) есть свойство, называемое "Text Placeholder", которое делает о чем изначально спрашивали jotbek. Используйте поле "Свойства" в разделе "Общие".

Ответ 12

К сожалению, ни один из вышеперечисленных не работал у меня, поэтому вместо этого я добавил ярлык поверх comboxbox, который говорит "Пожалуйста, выберите". Я использовал следующий код, чтобы показать и скрыть его:

  • Когда я инициализирую свой combobox, если нет выбранного значения, я привожу его на передний план и задаю текст:

    PleaseSelectValueLabel.BringToFront();
    PleaseSelectValueLabel.Text = Constants.AssessmentValuePrompt;
    
  • Если выбрано значение, я отправляю его обратно:

    PleaseSelectValueLabel.SendToBack();
    
  • Затем я использую следующие события для перемещения метки вперед или назад в зависимости от того, выбрал ли пользователь значение:

    private void PleaseSelectValueLabel_Click(object sender, EventArgs e)
    {
        PleaseSelectValueLabel.SendToBack();
        AssessmentValue.Focus();
    }
    
    private void AssessmentValue_Click(object sender, EventArgs e)
    {
        PleaseSelectValueLabel.SendToBack();
    }
    
    //if the user hasnt selected an item, make the please select label visible again
    private void AssessmentValue_Leave(object sender, EventArgs e)
    {
        if (AssessmentValue.SelectedIndex < 0)
        {
            PleaseSelectValueLabel.BringToFront();
        }
    }
    

Ответ 13

Я надеялся найти решение этого. Я вижу, что это более старая должность, но надеюсь, что мой подход может упростить эту проблему для кого-то другого.

Я использовал combobox с выпадающим стилем DropDownList, но это должно работать с другими стилями. В моем случае я хотел, чтобы текст читал "Выбрать источник", и я хотел, чтобы другие параметры были "Файл" и "Папка"

comboBox1.Items.AddRange(new string[] {"Select Source", "File", "Folder" });
comboBox1.Text = "Select Source";

Вместо этого вы можете выбрать индекс 0, если хотите. Затем я удалил элемент "Выбрать источник", когда индекс был изменен, поскольку не имеет значения, видно ли этот текст.

comboBox1.SelectedIndexChanged += new EventHandler(comboBox1_IndexChanged);

private void comboBox1_IndexChanged(object sender, EventArgs e)
    {
        comboBox1.Items.Remove("Select Source");
        if (comboBox1.SelectedIndex != -1)
        {
            if (comboBox1.SelectedIndex == 0) // File
            {
                // Do things
            }
            else if (comboBox1.SelectedIndex == 1) // Folder
            {
                // Do things
            }
        }
    }

Спасибо

Ответ 14

Это работает со стилем DropDownList - создайте класс, производный от ComboBox
(появится в панели инструментов после перестроения), который рисует подсказку с помощью System.Drawing,
поместите этот элемент управления из панели инструментов в форму и установите подсказку "Пожалуйста, выберите элемент" в ее свойствах.

public class HintComboBox : ComboBox
{
    string hint;
    public string Hint
    {
        get { return hint; }
        set { hint = value; Invalidate(); }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == 0xf && !Focused && string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Hint))
           using (var g = CreateGraphics())
           {
               TextRenderer.DrawText(g, Hint, Font, ClientRectangle, SystemColors.GrayText, BackColor,
                                    TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
           }
    }
}

Ответ 15

Я не мог получить подход @Andrei Karcheuski к работе, но он вдохновил меня на этот подход: (Я добавил Localizable Property, чтобы подсказка могла быть переведена через файлы .resx для каждого диалога, на котором вы его используете)

 public partial class HintComboBox : ComboBox
{
    string hint;
    Font greyFont;

    [Localizable(true)]
    public string Hint
    {
        get { return hint; }
        set { hint = value; Invalidate(); }
    }

    public HintComboBox()
    {
        InitializeComponent();
    }

    protected override void OnCreateControl()
    {
        base.OnCreateControl();

        if (string.IsNullOrEmpty(Text))
        {
            this.ForeColor = SystemColors.GrayText;
            Text = Hint;
        }
        else
        {
            this.ForeColor = Color.Black;
        }
    }

    private void HintComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if( string.IsNullOrEmpty(Text) )
        {
            this.ForeColor = SystemColors.GrayText;
            Text = Hint;
        }
        else
        {
            this.ForeColor = Color.Black;
        }
    }

Ответ 16

Почему бы не сделать это XAML?

<ComboBox x:Name="myComboBoxMenu" PlaceholderText="Hello"/>