简体   繁体   中英

Replace text in ComboBox upon selecting an item

I have an editable ComboBox that should contain a path. The user can select several default paths (or enter his own) from a dropdown list, such as %ProgramData%\\\\Microsoft\\\\Windows\\\\Start Menu\\\\Programs\\\\ (All Users) . The items in the dropdown list contain a short explanation, like the (All Users) part in the former example. Upon selection of such an item, I want to remove this explanation, so that a valid path is displayed in the ComboBox.

I currently strip the explanation out of the string and try to change the text via setting the Text property of the ComboBox. But this doesn't work, the string is parsed correctly, but the displayed text won't update (it stays the same as in the dropdown list, with the explanation).

private void combobox_TextChanged(object sender, EventArgs e) {
            //..             

               string destPath = combobox.GetItemText(combobox.SelectedItem);                  
               destPath = destPath.Replace("(All Users)", "");                   
               destPath.Trim();                   
               combobox.Text = destPath; 

            //..
}

I suggest you to create PathEntry class to store both Path and its Description .

public sealed class PathEntry
{
    public string Path { get; private set; }
    public string Description { get; private set; }

    public PathEntry(string path)
      : this(path, path)
    {
    }

    public PathEntry(string path, string description)
    {
        this.Path = path;
        this.Description = description;
    }
}

Then create an instance of BindingList<PathEntry> to store all the known paths and descriptions. Later you can add user-defined paths to it.

private readonly BindingList<PathEntry> m_knownPaths =
  new BindingList<PathEntry>();

And update your Form's constructor as follows:

public YourForm()
{
    InitializeComponent();

    m_knownPaths.Add(new PathEntry("%ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs",
      "(All Users)"));
    // TODO: add other known paths here

    combobox.ValueMember = "Path";
    combobox.DisplayMember = "Description";
    combobox.DataSource = m_knownPaths;

}

private void combobox_DropDown(object sender, EventArgs e)
{
    combobox.DisplayMember = "Description";
}

private void combobox_DropDownClosed(object sender, EventArgs e)
{
    combobox.DisplayMember = "Path";
}

You might want to learn more abount DataSource , DisplayMember and ValueMember from MSDN.

I found the solution in a similar question , by using BeginInvoke()

Using Nikolay's solution, my method now looks like this:

private void combobox_SelectedIndexChanged(object sender, EventArgs e) {
            if (combobox.SelectedIndex != -1) {
                //Workaround (see below)
                var x = this.Handle;
                this.BeginInvoke((MethodInvoker)delegate { combobox.Text = combobox.SelectedValue.ToString(); });                  
            }
}

The workaround is required, since BeginInvoke requires the control to be loaded or shown, which isn't necessarily the case if the program just started. Got that from here .

this is probably not the most elegant solution, but a simple one for beginners - like me - who don't want to use those InvokeMethods before they understand them a little better.

The boolean is required because when assign a new string(object) to the position in the Items array, the handler is fired again - recursively.

I figured this out just now, since i was working on the exact same problem.

Just sharing :)

    bool preventDoubleChange = false;
    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (preventDoubleChange){
            preventDoubleChange = false;
            return;
        }

        preventDoubleChange = true;

        switch (comboBox1.SelectedIndex)
        {
            case 0:
                comboBox1.Items[0] = "ChangeToThisText";
                break;
            case 1:
                comboBox1.Items[1] = "ChangeToThisText";
                break;
            default:
                preventDoubleChange = false;
                break;
        }            
    }

...or if you are comfortable using the "Tag" field, you can avoid the whole mess with the boolean. This second variation is also cleaner in my opinion.

    public Form1()
    {
        InitializeComponent();

        comboBox1.Items.Add("Item One");                        //Index 0
        comboBox1.Items.Add("Item Two");                        //Index 1
        comboBox1.Items.Add("Item Three");                             //Index 2
        comboBox1.Items.Add("Item Four");                       //Index 3
    }

    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (comboBox1.Tag != null && (int)comboBox1.Tag == comboBox1.SelectedIndex)
            return;

        switch (comboBox1.SelectedIndex)
        {
            case 0:
                break;
            case 1:
                comboBox1.Tag = comboBox1.SelectedIndex;
                comboBox1.Items[comboBox1.SelectedIndex] = "changed item 2";
                break;
            case 2:
                comboBox1.Tag = comboBox1.SelectedIndex;
                comboBox1.Items[comboBox1.SelectedIndex] = "changed item 3";
                break;
            case 3:
                break;
            default:
                break;
        }
    }

redfalcon,

You can't change the text this way. What you need to do is get the selectedindex value and then set the Text property. Something like that:

 protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    {
        var index = DropDownList1.SelectedIndex;

        DropDownList1.Items[index].Text = "changed";
    }

` private void combobox_TextChanged(object sender, EventArgs e) { //..

           string destPath = combobox.SelectedItem.Text;                  
           destPath = destPath.Replace("(All Users)", "");                   
           destPath.Trim();                   
           combobox.SelectedItem.Text = destPath; 

        //..

} `

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM