Click here to Skip to main content
Click here to Skip to main content

ComboBox List Control Host

, 9 Jan 2009 CDDL
Rate this:
Please Sign up or sign in to vote.
An article demonstrating how to host list controls inside a standard ComboBox. Easily create your own CheckedList ComboBox and others.

CheckedComboBoxPic.JPG

Introduction

This article allows you to create your own fully customized list controls for display in a combobox drop down style while at the same time staying with as much intrinsic/standard control functionality as is possible. The drop window behaviour supports multiple select operations without closing the drop window, and does not use a single API call. The base combobox implementation uses the ToolStripDropDown component to replace the built in drop window functionality of the base combobox along with a ToolStripControlHost component used internally to host a third control. The base implementation allows a developer to extend functionality by implementing a variety of different controls. Ideally, only use list controls such as the following.

  • ListBox
  • CheckedListBox
  • MonthCalendar
  • TreeView
  • DataGridView

Background

The code for this article is the result of a request that came across my desk. My brief was to "give us a checked combobox like the one used in Team System". After some serious search engine abuse, I came up with nothing usable in any stable format that did exactly what I wanted. All the samples used API calls - badly at that too. I have a rule, when you need to use APIs calls... don't! So, I did the next best thing, and re-invented the wheel, which also led to my very first article which I've wanted to do for sometime now. Hats off to the prolific article writers out there - where you find the time, I couldn't even begin to fathom. Anyway, here goes.

Using the Code

Using the code is pretty straightforward. Within a Windows Forms application, we have Form1. The controls/base folders contain a base combobox implementation and a CheckedListComboBox implementation built on top of the base combobox implementation. Simply extract the source code to a folder near you, open it and build the project in VS 2008. Select the Items property to create a list and hit the Play button. For this version only, our control won't support data binding simply because the standard Windows CheckedListBox control doesn't support data binding - I will address this functionality in my next article.

Base Implementation

Choice of Container

Firstly, we must hide the base drop window size to appear invisible, then prepare our internal containers that are going to provide the necessary functionality, specifically:

  • 01 x standard ToolStripDropDown component, which is a marvelous little component that provides a host of functionality as ‘standard’. One particularly useful tasty morsel is that the behavior allows mouse click functionality to select listed items while at the same time maintaining an open drop list for subsequent select operations. Something that can only be properly achieved in C++. The sample code/articles I found all used API calls – which, besides being unstable, is an attempt to access the root C++ functionality anyway.
  • 01 x standard ToolStripControlHost, almost a Swiss army knife when it comes to its flexibility in wrapping any other control, and ease of use with almost no code required.
namespace CheckedComboTest.Controls.Base
{
    public abstract class ComboBoxEx : ComboBox
    {

        #region Declarations & Constructors

        private ToolStripDropDown tsdd = new ToolStripDropDown();
        private ToolStripControlHost tsch = null;

        private int dropDownHeight;

        new public event EventHandler DropDown;
        new public event EventHandler DropDownClosed;

        public ComboBoxEx()
            : base()
        {
            base.DropDownHeight = 1;
        }

        #endregion

Instantiation

Always important in any component design is the manner and timing of any internal container instantiation. That’s why I like to use the base OnHandleCreated method to build the internals because by the time the thread executes my code, I know the base control has been instantiated and my control instance has a handle attached to it.

#region Base Overrides/Overloads

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    //  our handle has now been officially created; build internals
    BuildInternalHost();
}

#endregion

Internally, we configure our drop container and call the abstract OnCreateHost() method, forcing any implementation up the hierarchy to provide a control for hosting at the same time as the creation of the host container is taking place.

//  call extended implementations to provide a guest control
tsch = new ToolStripControlHost(OnCreateHost());

All we need to do is provide our own drop height functionality, and we can proceed with a custom implementation of ComboBoxEx.

Custom Implementation

Our custom implementation needs a class that inherits from our ComboBoxEx base component, and for our example, let’s use a CheckedListBox control.

public class CheckedListComboBox : Base.ComboBoxEx
{

    #region Declarations & Constructors

    private CheckedListBox checkedListBox = new CheckedListBox();

    public CheckedListComboBox()
        : base()
    {
    }

    #endregion

Actually, all our implementation needs to do is return an instance of a list control back through the OnCreateHost() function, like this…

#region Base Overrides/Overloads

protected override Control OnCreateHost()
{
    return checkedListBox;
}

…and then we can paste from the toolbox onto the form and run the project. The resulting drop window is quite normal at first site, especially when compared with the standard ComboBox, till we actually click to display the drop windows. Our custom drop window has a drop shadow effect along with matching border colors, and all this as provided standard by Microsoft.

Lastly, replace the standard Items property with the one exposed by the CheckedListBox control et voila:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor,
    System.Design, Version=2.0.0.0, Culture=neutral,
    PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[Localizable(true)]
new public CheckedListBox.ObjectCollection Items
{
    get
    {
        return checkedListBox.Items;
    }
}

Points of Interest

Effectively, the only thing created was an intermediate layer of code allowing multiple components to be plugged into each other. We didn’t even have to ‘hack’ any drawing routine or use even a single API call. The available controls are simple building blocks, and while it is great fun to twist and 'hack' something to death, it is easy to overdo, especially when done without a clear idea of how to extend the framework.

In my next article, I will expand on my custom implementations to cover data binding on custom implementations.

History

First release!

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

Share

About the Author

wmerifield
Software Developer (Senior) Motla utilities
South Africa South Africa
Have been coding for the last 10 years - vb(sucks), c#, ms sql, web services, web + mobile(jquery, html5, css3 etc!), windows embedded, mobile + windows azure. Really enjoy abstraction and implementing coding patterns, with some customized component development thrown in for good measure. Have experience in ERP, Medical Practice Management, Laboratory Stats/Calibration, Insurance Underwriting and Utilities Management. Also done quite a bit of re-design & developing of legacy apps from as far back as VB3 (before my time even) through VB6(interop). Really dig the MS tech stack especially what they did with Azure supporting all the open source stuff.

Comments and Discussions

 
GeneralDatabinding PinmemberJaba Jing6-Apr-10 5:54 
GeneralRe: Databinding Pinmemberzaphnath6-Apr-10 8:05 
GeneralHosted control mouse input Pinmemberjolle16-Jan-09 3:08 
GeneralRe: Hosted control mouse input Pinmemberzaphnath18-Jan-09 19:11 
GeneralRe: Hosted control mouse input PinmemberMichael Ceranski18-Aug-09 3:10 
QuestionSample Screenshot? PinmemberJohnny J.11-Jan-09 1:06 
AnswerRe: Sample Screenshot? Pinmemberzaphnath11-Jan-09 19:31 
Questionis this good for VS2005? PinmemberSouthmountain10-Jan-09 7:37 
I am still using VS2005?
AnswerRe: is this good for VS2005? Pinmemberzaphnath11-Jan-09 19:18 
GeneralZip file is damaged PinmemberAp079-Jan-09 11:03 
GeneralRe: Zip file is damaged Pinmemberzaphnath11-Jan-09 19:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 9 Jan 2009
Article Copyright 2009 by wmerifield
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid