Reputation: 1499
C# & .Net 2.0 question (WinForms)
I have set of items in ComboBox
and non of them selected. I would like to show a string on combo "Please select item" in that situation.
Current implementation is just added empty item with such text on index 0 and remove it when user select one of following items. Unfortunately empty item is shown in dropdown list as well. How to avoid this situation or in other way - is there any way to show custom text on ComboBox
when no item is selected?
Answers below work when ComboBoxStyle
is set to DropDown
(ComboBox
is editable). Is there possibility to do this when ComboBoxStyle
is set to DropDownList
?
Upvotes: 33
Views: 162217
Reputation: 1
Add this class to your solution. You will see ComboBoxPlus in your toolbox after rebuild the solution. It works well with DropDownList for DropDownStyle of comboBox. Enjoy it.
class ComboBoxPlus : System.Windows.Forms.ComboBox
{
private const int CB_SETCUEBANNER = 0x1703;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(System.IntPtr hWnd, int msg, int wParam, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]string lParam);
private string placeholder = string.Empty;
public string Placeholder
{
get { return placeholder; }
set
{
placeholder = value;
SendMessage(Handle, CB_SETCUEBANNER, 0, Placeholder);
}
}
}
Upvotes: 0
Reputation: 337
Credit must be given to IronRazerz in a response to TextBox watermark (CueBanner) which goes away when user types in single line TextBox (not for RichTextBox).
You will need to declare the following in your class:
private const int CB_SETCUEBANNER = 0x1703;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]string lParam);
Then you can use it with something like:
SendMessage(this.comboBox1.Handle, CB_SETCUEBANNER, 0, "Please select an item...");
This is assuming the Combo Box's DropDownStyle
is set to DropDownList
, as is the original poster's question.
This should result in something like the following:
Upvotes: 11
Reputation: 910
I could not get @Andrei Karcheuski 's approach to work but he inspired me to this approach: (I added the Localizable Property so the Hint can be translated through .resx files for each dialog you use it on)
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;
}
}
Upvotes: 0
Reputation: 11
I was hoping to find a solution to this as well. I see that this is an older post, but hoping my approach might simplify this problem for someone else.
I was using a combobox with a drop down style of DropDownList, but this should work with other styles. In my case I wanted the text to read "Select Source" and I wanted the other options to be "File" and "Folder"
comboBox1.Items.AddRange(new string[] {"Select Source", "File", "Folder" });
comboBox1.Text = "Select Source";
You can select the 0 index instead if you like. I then removed the "Select Source" item when the index is changed as it no longer matters if that text is visible.
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
}
}
}
Thanks
Upvotes: 0
Reputation: 1326
Unfortunately none of the above worked for me, so instead I added a label on top of the comboxbox that says "Please select". I used the following code to show and hide it:
When I initialise my combobox, if there is no selected value I bring it to the front and set the text:
PleaseSelectValueLabel.BringToFront();
PleaseSelectValueLabel.Text = Constants.AssessmentValuePrompt;
If there is a value selected I send it to the back:
PleaseSelectValueLabel.SendToBack();
I then use the following events to move the label to the front or back depending on whether the user has selected a value:
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();
}
}
Upvotes: 0
Reputation: 8584
One line after form InitializeComponent();
cbo_MyDropBox.Text = "Select a server...";
You only need it once right? All you need to do if a pick is mandatory is check if the box index != -1
. Could anyone elaborate why the other answers jump through hoops to get this going?
The only thing I'm missing here is having just this initial text grayed out. If you really want that just use a label in front and turn it off once the index is changed.
Upvotes: 1
Reputation: 10172
Here's how I do it. It might not be the best method, and offers least control; however, it's simple and quick and I thought it might be a good idea to share it so that more options are available for others.
<ComboBox SelectedIndex="0">
<ComboBoxItem Visibility="Collapsed">Please select one...</ComboBoxItem>
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
<ComboBoxItem>4</ComboBoxItem>
</ComboBox>
The idea behind this is that the initial selection is index 0, which is collapsed, so it's not available under selection for the user once they select something else. The downside is that you have to remember that if you're checking for a selected index, remember that index 0 means there was no selection made.
Upvotes: 4
Reputation: 415
I used a quick work around so I could keep the DropDownList style.
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;
}
}
}
If you use databinding you'll have to create a dummy version of the type you're bound to - just make sure you remove it before any persistence logic.
Upvotes: 3
Reputation: 145
I realize this is an old thread, but just wanted to let others who might search for an answer to this question know, in the current version of Visual Studio (2015), there is a property called "Placeholder Text" that does what jotbek originally asked about. Use the Properties box, under "Common" properties.
Upvotes: 0
Reputation: 1825
if ComboBoxStyle
is set to DropDownList
then the easiest way to make sure the user selects an item is to set SelectedIndex = -1
, which will be empty
Upvotes: 0
Reputation: 125
Why not do it XAML?
<ComboBox x:Name="myComboBoxMenu" PlaceholderText="Hello"/>
Upvotes: -3
Reputation: 1499
Here you can find solution created by pavlo_ua: If you have .Net > 2.0 and If you have .Net == 2.0 (search for pavlo_ua answer)
Cheers, jbk
edit: So to have clear answer not just link
You can set Text of combobox when its style is set as DropDown (and it is editable). When you have .Net version < 3.0 there is no IsReadonly property so we need to use win api to set textbox of combobox as 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 );
}
Upvotes: 1
Reputation: 24283
I can't see any native .NET way to do it but if you want to get your hands dirty with the underlying Win32 controls...
You should be able to send it the CB_GETCOMBOBOXINFO
message with a COMBOBOXINFO
structure which will contain the internal edit control's handle.
You can then send the edit control the EM_SETCUEBANNER
message with a pointer to the string.
(Note that this requires at least XP and visual styles to be enabled.
Upvotes: 5
Reputation: 427
Make the Dropdownstyle property of combo box to Dropdown and set the combo box text to "Select" as below
combobox.DataSource = dsIn.Tables[0];
combobox.DisplayMember = "Name";
combobox.ValueMember = "Value";
combobox.Text = "--Select--";
Upvotes: 2
Reputation: 25475
If none of the previous solution are working for you, why not add some validation on combobox something like,
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;
}
}
Upvotes: 1
Reputation: 11844
Use the insert method of the combobox to insert the "Please select item" in to 0 index,
comboBox1.Items.Insert(0, "Please select any value");
and add all the items to the combobox after the first index. In the form load set
comboBox1.SelectedIndex = 0;
EDIT:
In form load write the text in to the comboBox1.Text
by hardcoding
comboBox1.Text = "Please, select any value";
and in the TextChanged event of the comboBox1 write the following code
private void comboBox1_TextChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex < 0)
{
comboBox1.Text = "Please, select any value";
}
else
{
comboBox1.Text = comboBox1.SelectedText;
}
}
Upvotes: 19
Reputation: 708
private void comboBox1_TextChanged(object sender, EventArgs e)
{
if (comboBox1.Text == "")
comboBox1.Text = "Select one of the answers";
}
should do the trick at startup this line is present, when selected an item on combobox, this items text will appear. when deleling the text this text will appear again
Upvotes: 4