Custom Combo Boxes

I came across the need to develop a custom combo box recently, and started playing around with controls to try and mimic the drop down of a combo box but display my own control in it’s place. The combo box control does not allow this out of the box as far as I could see, so this was a perfect time to create a nice reusable control.

I started off with a simple UserControl, and created a custom ComboBox component which I then placed to the right of the UserControl to mimic the look of a combo box.

So, this is a quick image of the parts involved, as you can see I have a textbox in the background (the blue outline) which is used as a border, a label control inside that which I use to display the selected item in the custom drop down, and a custom combobox on the right hand side which doesn’t act like a combobox and essentially is just a button (but has all the nice visuals that go with the combobox to keep things the same). Please note I have expanded the controls so that you can see the parts, once brought together they look exactly like a normal combobox.

 

 

Here is my definition of my custom combobox:-

public class ContactComboBox : ComboBox

{

    public event EventHandler DisplayCustomItems;

 

    private void OnDisplayCustomItems(object sender, EventArgs e)

    {

        if (DisplayCustomItems != null)

        {

            DisplayCustomItems(sender, e);

        }

    }

 

    const int WM_LBUTTONDOWN = 0x0201;

    const int WM_LBUTTONDBLCLK = 0x0203;

 

    protected override void WndProc(ref Message m)

    {

        switch (m.Msg)

        {

            case WM_LBUTTONDOWN:

            case WM_LBUTTONDBLCLK:

                OnDisplayCustomItems(this, EventArgs.Empty);

                return;

        }

        base.WndProc(ref m);

    }

}

 

So, all this does is override WndProc to catch the mouse down event, and then send it off as an event to my usercontrol. This means that when it is clicked, it doesn’t show a drop down but passes the event to my control which can then display my custom drop down list.

 

private void searchCombo_DisplayCustomItems(object sender, EventArgs e)

{

    DisplayContactSearch();

}

 

private void DisplayContactSearch()

{

    using (ContactSelectionToolbox toolBox = new ContactSelectionToolbox())

    {

        Point reference = this.PointToScreen(new Point(0, 0));

        toolBox.Width = this.Width;

        toolBox.Height = 150;

        toolBox.StartPosition = FormStartPosition.Manual;

 

        //Find out if the drop down will run off the bottom of the screen,

        //and if yes we should display it upwards instead.

 

        if ((reference.Y + toolBox.Height) >

            Screen.FromControl(this).Bounds.Bottom)

        {

            toolBox.Location = new Point(

                reference.X,

                reference.Y – toolBox.Height

                );

        }

        else

        {

            toolBox.Location = new Point(

                reference.X,

                reference.Y + this.Height

                );

        }

 

 

        toolBox.ShowDialog(this.FindForm());

 

        if (toolBox.DialogResult == DialogResult.OK)

        {

            //Do whatever you need to do

        }

    }

}

 

So, this block of code catches the combobox click event and then displays a custom toolbox window from which the user can select an item. It positions the item exactly below the combobox and sizes itself accordingly. The only issue that remains now is that as you can see we are using ShowDialog which will cause the dialog to show on top of the current form (this.FindForm()), and it will be modal. To mimic a combo box, we need to hide the dialog when the user clicks on a item inside it, or when the dialog loses focus:-

 

 

 

protected override void WndProc(ref Message m)

{

    switch (m.Msg)

    {

        case 134:

            if (m.WParam.ToInt32() == 0)

            {

                this.Close();

            }

            break;

    }

    base.WndProc(ref m);

}

So, essentially this little override can be placed inside a Form class (ContactSelectionToolbox in my case) and then when the form loses focus it will close itself. Put all this together and you have the basic functionality of a combo box with the difference that you can make the modal dialog display whatever data you want. This leaves lots of room for item filtering for huge lists (putting a little textbox at the top for an addressbook for instance) and lots of other enhancements.