Windows Develop Bookmark and Share   
 index > Windows Forms General > Need MultiColumn ComboBox in C# Windows
 

Need MultiColumn ComboBox in C# Windows

Can Anyone post me the link or code for multi column combo box using c# (Win Forms).

Thanks in Advance
VRReddy0560  Wednesday, October 07, 2009 8:08 PM
This is by no means a polished solution but it might give you a push in the right direction.

using System.Drawing;
using System.Windows.Forms;

namespace MSDN.Forums.Example
{
	public interface IHaveColumnsItem
	{
		string Column1Value { get; }
		string Column2Value { get; }
	}

	public class MultiColumnComboBox : ComboBox
	{
		private bool _hasMultiColumns = false;
		private int _maxItemWidth = 0;
		private const int PADDING = 5;

		public MultiColumnComboBox()
			: base()
		{
			DrawMode = DrawMode.OwnerDrawVariable;
		}

		protected override void OnDrawItem( DrawItemEventArgs e )
		{
			base.OnDrawItem( e );

			object obj = this.Items[ e.Index ];
			string column1Text = GetItemTextInternal( obj );

			e.Graphics.FillRectangle( new SolidBrush( e.BackColor ), e.Bounds );
			e.Graphics.DrawString( column1Text, this.Font, new SolidBrush( this.ForeColor ), e.Bounds.Left, e.Bounds.Top );

			if( _hasMultiColumns )
				e.Graphics.DrawLine( SystemPens.ControlText, _maxItemWidth + PADDING, e.Bounds.Top, _maxItemWidth + PADDING, e.Bounds.Height );

			if( typeof( IHaveColumnsItem ).IsAssignableFrom( obj.GetType() ) )
			{
				string column2Text = ( ( IHaveColumnsItem )obj ).Column2Value;
				e.Graphics.DrawString( column2Text, this.Font, new SolidBrush( this.ForeColor ), _maxItemWidth + ( PADDING * 2 ), e.Bounds.Top );
			}
		}

		protected override void OnMeasureItem( MeasureItemEventArgs e )
		{
			// Reset if we're measuring from the begining.
			if( e.Index == 0 ) _maxItemWidth = 0;

			string itemText = GetItemTextInternal( this.Items[ e.Index ] );
			Size size = e.Graphics.MeasureString( itemText, this.Font ).ToSize();

			if( _maxItemWidth < size.Width )
				_maxItemWidth = size.Width;

			base.OnMeasureItem( e );
		}

		private string GetItemTextInternal( object obj )
		{
			if( typeof( IHaveColumnsItem ).IsAssignableFrom( obj.GetType() ) )
			{
				_hasMultiColumns = true;
				return ( ( IHaveColumnsItem )obj ).Column1Value;
			}
			else return GetItemText( obj ); // The default list control method
		}
	}
}


Hope it helps you some.
"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Thursday, October 08, 2009 1:20 AM
It's used like this...

public Form1()
{
	InitializeComponent();

	multiColumnComboBox1.Items.AddRange( new object[] {
    "Item",
    "Longer Item",
    "An Event Longer Item",
    "The Longest Item So Far"} );
	multiColumnComboBox1.Items.Add( new MultiColumnItem()
	{
		Column1Value = "Value 1",
		Column2Value = "Value 2"
	} );
}

"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Thursday, October 08, 2009 1:22 AM
With an item object like this...

public class MultiColumnItem : IHaveColumnsItem
{
	public string Column1Value { get; set; }
	public string Column2Value { get; set; }
}


Sorry for the multiple posts.
"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Thursday, October 08, 2009 1:22 AM
Use the DrawItem event to draw the columns:

  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
      comboBox1.Items.Add("1,one");
      comboBox1.Items.Add("2,two");
      comboBox1.Items.Add("3,three");
      comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
      comboBox1.DrawItem += new DrawItemEventHandler(comboBox1_DrawItem);
    }
   
    private const int wcol1 = 20;

    void comboBox1_DrawItem(object sender, DrawItemEventArgs e) {
      string txt = comboBox1.Items[e.Index].ToString();
      string[] words = txt.Split(',');
      e.DrawBackground();
      Color fore = Color.FromKnownColor(KnownColor.WindowText);
      if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        fore = Color.FromKnownColor(KnownColor.HighlightText);
      TextFormatFlags fmt = TextFormatFlags.Left;
      Rectangle wordRc1 = new Rectangle(e.Bounds.Left, e.Bounds.Top, wcol1, e.Bounds.Height);
      TextRenderer.DrawText(e.Graphics, words[0], comboBox1.Font, wordRc1, fore, fmt);
      Rectangle wordRc2 = new Rectangle(e.Bounds.Left+wcol1, e.Bounds.Top, e.Bounds.Width-wcol1, e.Bounds.Height);
      TextRenderer.DrawText(e.Graphics, words[1], comboBox1.Font, wordRc2, fore, fmt);
      e.DrawFocusRectangle();
    }
  }


Hans Passant.
nobugz  Thursday, October 08, 2009 1:31 AM
This is by no means a polished solution but it might give you a push in the right direction.

using System.Drawing;
using System.Windows.Forms;

namespace MSDN.Forums.Example
{
	public interface IHaveColumnsItem
	{
		string Column1Value { get; }
		string Column2Value { get; }
	}

	public class MultiColumnComboBox : ComboBox
	{
		private bool _hasMultiColumns = false;
		private int _maxItemWidth = 0;
		private const int PADDING = 5;

		public MultiColumnComboBox()
			: base()
		{
			DrawMode = DrawMode.OwnerDrawVariable;
		}

		protected override void OnDrawItem( DrawItemEventArgs e )
		{
			base.OnDrawItem( e );

			object obj = this.Items[ e.Index ];
			string column1Text = GetItemTextInternal( obj );

			e.Graphics.FillRectangle( new SolidBrush( e.BackColor ), e.Bounds );
			e.Graphics.DrawString( column1Text, this.Font, new SolidBrush( this.ForeColor ), e.Bounds.Left, e.Bounds.Top );

			if( _hasMultiColumns )
				e.Graphics.DrawLine( SystemPens.ControlText, _maxItemWidth + PADDING, e.Bounds.Top, _maxItemWidth + PADDING, e.Bounds.Height );

			if( typeof( IHaveColumnsItem ).IsAssignableFrom( obj.GetType() ) )
			{
				string column2Text = ( ( IHaveColumnsItem )obj ).Column2Value;
				e.Graphics.DrawString( column2Text, this.Font, new SolidBrush( this.ForeColor ), _maxItemWidth + ( PADDING * 2 ), e.Bounds.Top );
			}
		}

		protected override void OnMeasureItem( MeasureItemEventArgs e )
		{
			// Reset if we're measuring from the begining.
			if( e.Index == 0 ) _maxItemWidth = 0;

			string itemText = GetItemTextInternal( this.Items[ e.Index ] );
			Size size = e.Graphics.MeasureString( itemText, this.Font ).ToSize();

			if( _maxItemWidth < size.Width )
				_maxItemWidth = size.Width;

			base.OnMeasureItem( e );
		}

		private string GetItemTextInternal( object obj )
		{
			if( typeof( IHaveColumnsItem ).IsAssignableFrom( obj.GetType() ) )
			{
				_hasMultiColumns = true;
				return ( ( IHaveColumnsItem )obj ).Column1Value;
			}
			else return GetItemText( obj ); // The default list control method
		}
	}
}


Hope it helps you some.
"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Thursday, October 08, 2009 1:20 AM
It's used like this...

public Form1()
{
	InitializeComponent();

	multiColumnComboBox1.Items.AddRange( new object[] {
    "Item",
    "Longer Item",
    "An Event Longer Item",
    "The Longest Item So Far"} );
	multiColumnComboBox1.Items.Add( new MultiColumnItem()
	{
		Column1Value = "Value 1",
		Column2Value = "Value 2"
	} );
}

"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Thursday, October 08, 2009 1:22 AM
With an item object like this...

public class MultiColumnItem : IHaveColumnsItem
{
	public string Column1Value { get; set; }
	public string Column2Value { get; set; }
}


Sorry for the multiple posts.
"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Thursday, October 08, 2009 1:22 AM
Use the DrawItem event to draw the columns:

  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
      comboBox1.Items.Add("1,one");
      comboBox1.Items.Add("2,two");
      comboBox1.Items.Add("3,three");
      comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
      comboBox1.DrawItem += new DrawItemEventHandler(comboBox1_DrawItem);
    }
   
    private const int wcol1 = 20;

    void comboBox1_DrawItem(object sender, DrawItemEventArgs e) {
      string txt = comboBox1.Items[e.Index].ToString();
      string[] words = txt.Split(',');
      e.DrawBackground();
      Color fore = Color.FromKnownColor(KnownColor.WindowText);
      if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        fore = Color.FromKnownColor(KnownColor.HighlightText);
      TextFormatFlags fmt = TextFormatFlags.Left;
      Rectangle wordRc1 = new Rectangle(e.Bounds.Left, e.Bounds.Top, wcol1, e.Bounds.Height);
      TextRenderer.DrawText(e.Graphics, words[0], comboBox1.Font, wordRc1, fore, fmt);
      Rectangle wordRc2 = new Rectangle(e.Bounds.Left+wcol1, e.Bounds.Top, e.Bounds.Width-wcol1, e.Bounds.Height);
      TextRenderer.DrawText(e.Graphics, words[1], comboBox1.Font, wordRc2, fore, fmt);
      e.DrawFocusRectangle();
    }
  }


Hans Passant.
nobugz  Thursday, October 08, 2009 1:31 AM
Hi VRReddy0560,

You can take a look at this sample:
http://www.codeproject.com/KB/combobox/multicolumncombo.aspx

Regards,
Aland Li
Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
Aland Li  2 hours 49 minutes ago

You can use google to search for other answers

Custom Search

More Threads

• set a button in mdi parent form
• Firing a custom control's mouse enter event
• Custom Control to act as container
• printwindow form mess-up
• Bitmap resizing
• How do I show counted numbers in Label or Status Strip?
• Download files from web browser
• Bad opinion about .NET framework
• Workaround Needed for No Tab KeyChar
• UserControl doesn't update