jotbek
jotbek

Reputation: 1499

How to show text in combobox when no item selected?

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

Answers (17)

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

Kevin
Kevin

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:

Placeholder text for combo box drop down list

Upvotes: 11

wecky
wecky

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

NAPTlME
NAPTlME

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

majjam
majjam

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:

  1. 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;
    
  2. If there is a value selected I send it to the back:

    PleaseSelectValueLabel.SendToBack();
    
  3. 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

Madmenyo
Madmenyo

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

B.K.
B.K.

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

Jesse Adam
Jesse Adam

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

wheezer
wheezer

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

Harry
Harry

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

Rizwan Asif
Rizwan Asif

Reputation: 125

Why not do it XAML?

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

Upvotes: -3

jotbek
jotbek

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

Deanna
Deanna

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

prema
prema

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

Ash Burlaczenko
Ash Burlaczenko

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

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

Moonlight
Moonlight

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

Related Questions