locked
Need MultiColumn ComboBox in C# Windows RRS feed

  • Question

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

    Thanks in Advance
    mercredi 7 octobre 2009 20:08

Réponses

  • 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
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:20
  • 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
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:22
  • 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
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:22
  • 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.
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:31

Toutes les réponses

  • 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
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:20
  • 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
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:22
  • 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
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:22
  • 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.
    • Marqué comme réponse Aland Li vendredi 9 octobre 2009 08:06
    jeudi 8 octobre 2009 01:31
  • 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.
    vendredi 9 octobre 2009 08:06