0

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; 

            //..
}
Lennart
  • 9,657
  • 16
  • 68
  • 84
  • 1
    What or how does the display text look that is not working correctly..? – MethodMan Oct 10 '12 at 16:50
  • and have you tried capturing the SelectedItemIndex so that you know exactly which combox.Text to set..? – MethodMan Oct 10 '12 at 16:52
  • If it's no working correctly, the text is exactly the same as if I hadn't stripped out the text. I don't really understand your second comment, since setting the Text property doesn't work in any case. – Lennart Oct 10 '12 at 17:01
  • are you storing paths with %ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs\\ (All Users) less the (All Users) please clarify – MethodMan Oct 10 '12 at 17:08
  • No, the path in the dropdown list includes the `(All Users)`, I want to remove that and display only the path (sans `(All Users)`) in the text field of the combobox. – Lennart Oct 10 '12 at 17:16

5 Answers5

1

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.

Nick Hill
  • 4,867
  • 3
  • 23
  • 29
  • This is a nice idea, but it still doesn't resolve my actual problem. If I now select an item from the dropdown list, e.g. `(All Users)` the text in editable portion of the ComboBox after selecting the item will still be `(All Users)`, and not `%ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs`. – Lennart Oct 11 '12 at 09:44
1

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.

Community
  • 1
  • 1
Lennart
  • 9,657
  • 16
  • 68
  • 84
1

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;
        }
    }
Toastgeraet
  • 371
  • 1
  • 11
0

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";
    }
Daniel
  • 455
  • 4
  • 14
  • Where do I get that DropDownList object from? I use the "integrated" from the ComboBox. – Lennart Oct 10 '12 at 17:28
  • DropDownList is the same thing as your combobox object right? – Daniel Oct 10 '12 at 17:34
  • @Daniel redfalcon said his ComboBox is editable. So I suspect he set combobox.DropDownStyle to ComboBoxStyle.DropDown and he's able to change the text. That's why I downvoted your answer. – Nick Hill Oct 10 '12 at 17:38
0

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

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

        //..

} `

Fonseca
  • 111
  • 4
  • combobox.SelectedItem has no Text property. See the [MSDN](http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.selecteditem.aspx) entry. – Lennart Oct 10 '12 at 17:28