Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / containers / docker

ComboBox DataSource AddItem Extension

4.00/5 (2 votes)
19 Nov 2015CPOL3 min read 15.4K   142  
A simple extension to add an item that has a data source bound to combobox.items

Introduction

In .NET, if you set ComboBox.DataSource = ComboBox.Items and then later try to add a new item, .NET will throw an exception. The only way to add a new item to this simple binding (without implementing a more complex data source) is to remove the binding, recreate the Items collection, and rebind.

Additionally, if you simply do ComboBox.DataSource = null to clear the binding, the items in ComboBox.Items are cleared. Thus, you either recreate every item or copy the ComboBox.Items to a new array, unbind the data source, re-insert the original items, add the new item, and rebind the data source.

To get around this problem, in .NET, you can write Extensions that will add functions to existing classes, without having to fully extend the original class and then implement the extended class in various places in your projects.

This tip shows how to add a function called 'AddItem' to the base ComboBox class which will automate all of this, and make it so you don't have to go through your code and place all instances of ComboBox controls with a new extended version. Additionally, a simple sort functionality has been included as part of the extension method.

Using the Code

The example project included can be compiled to create a DLL that can be referenced in your projects, or you can simply copy the code into your existing projects. Source code for both C# and VB are included (and a simple test project). Along with two separate ways to handle doing the simple sorting.

Sorting methods:

  1. Extended Combo Box - Extensions currently don't natively support properties, so you can't add properties to an existing class without extending the actual class. This project extends the ComboBox and adds a SortedDS Boolean property. An alternative to this would be to store a Boolean in the ComboBox.Tag, but this breaks if something else is stored in the Tag property. One advantage of this route over the alternative #2 is that the SortedDS property will show up in the Visual Studio Designer (in the Properties docker).
  2. Extended Property - Thanks to a very informative article by Oleg Shilo titled "Extension Properties" Revised (http://www.codeproject.com/Articles/399932/Extension-Properties-Revised) this project adds a GetSortedDS and SetSortedDS method to all ComboBoxes automatically. The pro is that all your combo box controls will automatically have this property. The con is that it doesn't show up in the Designer.

This article only covers AddItem with sorting method #1 above. Download the example project to see method #2. The AddItem code can be easily copied and modified to provide additional useful functions such as AddItemRange, EditItem, InsertItem, and RemoveItem.

Step 1

Add a static class (or Module in VB) to your project named ComboBoxAddItem.

Copy and paste the following code:

C#
public int AddItem(this System.Windows.Forms.ComboBox cbo, object item)
{
    //If a combo box has datasource = cbo.Items, adding items throws an error.
    //So if you add an item you have to clear the datasource which apparently clears
    //the items, and recreate the whole thing. Which can be a pain. This is just a simple
    //function to automate so I don't have to duplicate the code everywhere I have a
    //combo box.

    if (cbo.DataSource == null)
    {
        // No data source, just add the item.
        return cbo.Items.Add(item);
    }
    else if (cbo.DataSource is System.Windows.Forms.ComboBox.ObjectCollection)
    {
        //create a new array that is 1 larger than the current number of items.
        object[] items = new object[cbo.Items.Count + 1];
        string dm, vm; //save the display member and value member.
        //save the selected item so it can be reset.
        object selectedItem = cbo.SelectedItem;
        bool enabled = cbo.Enabled; //save whether the combobox is enabled or not.
        dm = cbo.DisplayMember;
        vm = cbo.ValueMember;

        cbo.Enabled = false;
        cbo.BeginUpdate();

        cbo.Items.CopyTo(items, 0);
        items[items.Length - 1] = item;

        cbo.DataSource = null;
        cbo.Items.AddRange(items);
        // Clearing the Data Source also messes with the display and value members.
        cbo.DisplayMember = dm;
        cbo.ValueMember = vm;

        if (cbo is SortedDSComboBox && ((SortedDSComboBox)cbo).SortedDS)
        {
            //If you set a combobox.sorted = true, then = false, before doing
            //cbo.DataSource = cbo.Items will result in a sorted combox box.
            cbo.Sorted = true;
            //Have to set this to false or you get an empty combo box for some reason.
            cbo.Sorted = false;

            cbo.DataSource = cbo.Items;

            cbo.SelectedItem = selectedItem;

            cbo.EndUpdate();
            cbo.Enabled = enabled;

            return cbo.Items.IndexOf(item);
        }
        else
        {
            cbo.SelectedItem = selectedItem;

            cbo.EndUpdate();
            cbo.Enabled = enabled;

            return cbo.Items.Count - 1;
        }
    }
    else
    {
        throw new InvalidOperationException("DataSource is not null or cbo.Items - " +
            "any other data source needs to be handled explicitly.");
    }
}

The gist of it is:

  1. If the data source is null, just the item - nothing extra needed.
  2. If the data source is the cbo.Items, then:
    1. Copy certain necessary properties from the combo box.
    2. Copy the items into a new array that is 1 size larger than the current number of items.
    3. Add the new item to the end of the array.
    4. Resort the array if need be.
    5. Reset the copied properties and data source.
  3. Throw an error if the data source is not the simple cbo.Items.

Step 2

Add a SortedDSComboBox that extends the System.Windows.Forms.ComboBox to your project, and paste in the following code:

C#
public class SortedDSComboBox : System.Windows.Forms.ComboBox
{
    private bool _sortedDS = false;

    [DefaultValue(false)]
    [Category("Behavior")]
    [Description("Indicates whether the data source is sorted or not. " +
        "Used in conjunction with AddItem extension.")]
    public bool SortedDS { get { return _sortedDS; } set { _sortedDS = value; } }
}

Step 3

If you need or want the extra functionality such as AddRange or InsertItem, copy the AddItem method above, rename it to the appropriate method name, and make any minor modifications you need to have it perform that particular function.

For more information on how to do the Extended property, download the example project and read over the article by Oleg Shilo titled "Extension Properties" Revised (http://www.codeproject.com/Articles/399932/Extension-Properties-Revised).

History

  • 20th November 2015: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)