Как показать текст в поле со списком, если ни один элемент не выбран?
Вопрос С# и .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"/>