Click here to Skip to main content
Licence CDDL
First Posted 9 Jan 2009
Views 27,558
Downloads 477
Bookmarked 48 times

ComboBox List Control Host

By | 9 Jan 2009 | Article
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)

About the Author

zaphnath

Software Developer (Senior)
Private Contractor
South Africa South Africa

Member

Developing for the last 8 years, started with VB and been with C# since inception. Prefer windows forms development and have experience in insurance underwriting, medical practice management, laboratory statistics/calibration, erp systems but mainly really enjoy developing solution frameworks/programming models. Have also experienced the dark side with in the re-design/developing of legacy applications from as far back as VB3(before me even) through VB6(interop) for the dotnet framework 1.1 through 3.5

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralDatabinding PinmemberJaba Jing4:54 6 Apr '10  
GeneralRe: Databinding Pinmemberzaphnath7:05 6 Apr '10  
GeneralHosted control mouse input Pinmemberjolle2:08 16 Jan '09  
GeneralRe: Hosted control mouse input Pinmemberzaphnath18:11 18 Jan '09  
GeneralRe: Hosted control mouse input PinmemberMichael Ceranski2:10 18 Aug '09  
QuestionSample Screenshot? PinmemberJohnny J.0:06 11 Jan '09  
AnswerRe: Sample Screenshot? Pinmemberzaphnath18:31 11 Jan '09  
Questionis this good for VS2005? PinmemberSouthmountain6:37 10 Jan '09  
AnswerRe: is this good for VS2005? Pinmemberzaphnath18:18 11 Jan '09  
GeneralZip file is damaged PinmemberAp0710:03 9 Jan '09  
GeneralRe: Zip file is damaged Pinmemberzaphnath18:20 11 Jan '09  

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.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 9 Jan 2009
Article Copyright 2009 by zaphnath
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid