none
Setting up a combobox to execute selections RRS feed

  • General discussion

  • Although this discussion involves a combobox, it's not really about Winforms but about C# itself. Consider, then, a combobox, and each of its entries corresponds to a method you wish to invoke. A common way to do this is:

    private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
    	var cmb = sender as ComboBox;
    	switch (cmb.SelectedIndex)
    	{
    		case 0:
    			FunctionA();
    			break;
    		case 1:
    			FunctionB();
    			break;
    		case 2:
    			FunctionC();
    			break;
    		default:
    			break;
    	}
    }
    

    This is a very simple solution, but some people don't like it for various reasons. Regardless of the pros and cons, there is a way of achieving the same result without any switch statement.

    At the class level, declare,

    private List<string> userOptions = new List<string>();
    private List<Func<bool>> methods = new List<Func<bool>>();
    

    Then, after InitializeComponent(), 

    InitializeComponent();
    
    methods.Add(FunctionA);
    methods.Add(FunctionB);
    methods.Add(FunctionC);
    
    userOptions.Add("Feature A name");
    userOptions.Add("Feature B name");
    userOptions.Add("Feature C name");
    
    ComboBox1.DataSource = new BindingSource(userOptions, null);
    ComboBox1.SelectedIndex = -1;
    

    Now the ComboBox will display the items from the userOptions list. When the user selects an entry in the ComboBox, the SelectedIndexChanged event fires. The SelectedIndex property is then used to select the method to invoke.

    private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
    	var cmb = sender as ComboBox;
    	if ((cmb.SelectedIndex == -1) is false)
    	{
    		methods[cmb.SelectedIndex].Invoke();
    	}
    }
    

    What do you think? Which of the two methods is the better practice? Can you simplify it more? I couldn't find a way to use just one collection.

    Thursday, January 2, 2020 2:08 AM

All replies

  • This really is a Winforms question because the answer is tied to how Winforms works. This solution doesn't work for other areas but the concept would.

    I agree a switch statement isn't the best option but I don't believe your solution is OOP enough. The way I solve this problem is by relying on the `Tag` property. This property can be used to store anything you want. But in the case of a combo then you are dealing with objects so the item in the combo is the data so `Tag` isn't needed.

    First you create an instance of the object that has the necessary logic to be called when needed. 

    //Assume a simple data object being stored in the combo
    public class MyData
    {
       public int Id { get; set; }
       public void DoWork () 
       { 
          Debug.WriteLine(Id.ToString());
       }
    }
    
    //Create some data to show
    var data = new [] {
       new MyData() { Id = 1 },
       new MyData() { Id = 2 },
       new MyData() { Id = 3 }
    };
    
    //Bind to the combo
    combo1.Items.AddRange(data);

    If you are using a type provided elsewhere and need to invoke some functionality that isn't on that object then create a generic wrapper around it. The results are the same.

    Now get the item in your UI.

    void ComboBox1_SelectedIndexChanged ( object sender, EventArgs e )
    {
       var ctrl = sender as ComboBox;
       var item = ctrl.SelectedItem as MyData;
       if (item != null)
          item.DoWork();
    }
    Alternatively once you have the data itself you can call a helper method in the UI to do the actual work. It really doesn't matter at this point. Nevertheless you don't need separate collections of methods or whatnot. 


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, January 2, 2020 3:13 PM
    Moderator