17

I am using currently the following code to populate a combobox:

combobox.DataSource = datatable;
combobox.DisplayMember = "Auftragsnummer";
combobox.ValueMember = "ID";

Is there a way to display multiple columns. I tried "Auftragsnummer, Kunde, Beschreibung" for DisplayMember but it did not work.

Maniero
  • 10,311
  • 6
  • 40
  • 85

11 Answers11

12

You can't have multiple columns. Though you can have concatenation of multiple fields as Display Member

Check out: How do I bind a Combo so the displaymember is concat of 2 fields of source datatable?

Community
  • 1
  • 1
Rashmi Pandit
  • 23,230
  • 17
  • 71
  • 111
10

There's an article on MSDN describing how a Multicolumn ComboBox can be created.

How to create a multiple-column drop-down list for a combo box in Windows Forms

http://support.microsoft.com/kb/982498


Source code from the download for VB from the above Microsoft Link, that can be easily adapted to work with a ListBox as well as a ComboBox:

'************************************* Module Header **************************************'
' Module Name:  MainForm.vb
' Project:      VBWinFormMultipleColumnComboBox
' Copyright (c) Microsoft Corporation.
' 
' 
' This sample demonstrates how to display multiple columns of data in the dropdown of a ComboBox.
' 
' This source is subject to the Microsoft Public License.
' See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
' All other rights reserved.
' 
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
' WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
'******************************************************************************************'

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports System.Drawing.Drawing2D

Public Class MainForm

    Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim dtTest As DataTable = New DataTable()
        dtTest.Columns.Add("ID", GetType(Integer))
        dtTest.Columns.Add("Name", GetType(String))

        dtTest.Rows.Add(1, "John")
        dtTest.Rows.Add(2, "Amy")
        dtTest.Rows.Add(3, "Tony")
        dtTest.Rows.Add(4, "Bruce")
        dtTest.Rows.Add(5, "Allen")

        ' Bind the ComboBox to the DataTable
        Me.comboBox1.DataSource = dtTest
        Me.comboBox1.DisplayMember = "Name"
        Me.comboBox1.ValueMember = "ID"

        ' Enable the owner draw on the ComboBox.
        Me.comboBox1.DrawMode = DrawMode.OwnerDrawFixed
        ' Handle the DrawItem event to draw the items.
    End Sub

    Private Sub comboBox1_DrawItem(ByVal sender As System.Object, _
                                   ByVal e As System.Windows.Forms.DrawItemEventArgs) _
                                   Handles comboBox1.DrawItem
        ' Draw the default background
        e.DrawBackground()

        ' The ComboBox is bound to a DataTable,
        ' so the items are DataRowView objects.
        Dim drv As DataRowView = CType(comboBox1.Items(e.Index), DataRowView)

        ' Retrieve the value of each column.
        Dim id As Integer = drv("ID").ToString()
        Dim name As String = drv("Name").ToString()

        ' Get the bounds for the first column
        Dim r1 As Rectangle = e.Bounds
        r1.Width = r1.Width / 2

        ' Draw the text on the first column
        Using sb As SolidBrush = New SolidBrush(e.ForeColor)
            e.Graphics.DrawString(id, e.Font, sb, r1)
        End Using

        ' Draw a line to isolate the columns 
        Using p As Pen = New Pen(Color.Black)
            e.Graphics.DrawLine(p, r1.Right, 0, r1.Right, r1.Bottom)
        End Using

        ' Get the bounds for the second column
        Dim r2 As Rectangle = e.Bounds
        r2.X = e.Bounds.Width / 2
        r2.Width = r2.Width / 2

        ' Draw the text on the second column
        Using sb As SolidBrush = New SolidBrush(e.ForeColor)
            e.Graphics.DrawString(name, e.Font, sb, r2)
        End Using
    End Sub
End Class
Paul Seeb
  • 6,006
  • 3
  • 26
  • 38
Irshad
  • 3,071
  • 5
  • 30
  • 51
  • Much easier than it sounds, and it also gives you the chance to change colors based on conditions, change the color of the divider, etc. Good solution. – Wade Hatler Jan 09 '15 at 02:57
7

You can add to your dataset a dummy column (Description) and use that as DisplayMember in the combo box databinding.

SELECT Users.*, Surname+' '+Name+' - '+UserRole AS Description FROM Users
ComboBox.DataBindings.Add(new Binding("SelectedValue", bs, "ID"));
ComboBox.DataSource = ds.Tables["Users"];
ComboBox.DisplayMember = "Description";
ComboBox.ValueMember = "ID";

Simple and works.

Michał Powaga
  • 22,561
  • 8
  • 51
  • 62
bizabo
  • 71
  • 1
  • 1
3

It's not available out-of-the-box in .NET (be it Windows forms or asp.net's dropdownlist) CHeck out this code project item for reference on how to build your own. (there are loads more though).

Code Project

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Colin
  • 10,630
  • 28
  • 36
  • Thanks for you advice but i googled first and i came across those projects too. I decided to ask anyway because it seemed to me that some of the projects are a little bit old and i wanted somehow i definit answer that there is no standard way for implementing multiple columns in a combobox. –  Jul 07 '09 at 10:17
  • They are old, but they should still provide you with the answers on how to create your own "OwnerDrawn" combobox. – Colin Jul 07 '09 at 10:20
2

There's an article on Code Project describing how a Multicolumn ComboBox can be created.

Multicolumn Combobox - Code Project

Pop Catalin
  • 61,751
  • 23
  • 87
  • 115
2

Here's the full solution in C# which I've converted from Visual Basic.

I've been using that for the past 8 years. Note the date format is for non-American users.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;

namespace MultiColumnCombcs
{
    public partial class MultiColumnCombocs: ComboBox
    {
    // Hide some properties
    [Browsable(false)]
    public new bool IntegralHeight { get; set; }

    [Browsable(false)]
    public new DrawMode DrawMode { get; set; }

    [Browsable(false)]
    public new int DropDownHeight { get; set; }

    [Browsable(false)]
    public new ComboBoxStyle DropDownStyle { get; set; }

    [Browsable(false)]
    public new bool DoubleBuffered { get; set; }

    public Boolean paintHandled = false;
    public const int WM_PAINT = 0xF;
    public int intScreenMagnification = 125; // Screen Magnification = 125%
    // Dropdown
    private string _columnWidths;
    private string[] columnWidthsArray;

    // 'Combo Box
    private Color _buttonColor = Color.Gainsboro;
    private Color _borderColor = Color.Gainsboro;
    private readonly Color bgSelectedColor = Color.PaleGreen; 
    private readonly Color textselectedcolor = Color.Red;
    private readonly Color bgColor = Color.White;
    private readonly Color lineColor = Color.White;
   
    private Brush backgroundBrush = new SolidBrush(SystemColors.ControlText);
    private Brush arrowBrush = new SolidBrush(Color.Black);
    private Brush ButtonBrush = new SolidBrush(Color.Gainsboro);

    //Properties
    [Browsable(true)]
    public Color ButtonColor
    {
        get
        {
            return _buttonColor;
        }
        set
        {
            _buttonColor = value;
            ButtonBrush = new SolidBrush(this.ButtonColor);
            this.Invalidate();
        }
    }

    [Browsable(true)]
    public Color BorderColor
    {
        get
        {
            return _borderColor;
        }
        set
        {
            _borderColor = value;
            this.Invalidate();
        }
    }
    //Column Widths to be set in Properties Window as string containing width of each column in Pixels, 
    // delimited by ';' eg 15;45;40;100,50;40 for six columns

    [Browsable(true)]
    public string ColumnWidths 
    {
        get
        {
        if (string.IsNullOrEmpty(_columnWidths))
            {
                _columnWidths = "15";  //default value
            }

            return _columnWidths;
        }
        set
        {
            _columnWidths = value;
            // split Column Widths string into Array of substrings delimited by ';' character
            columnWidthsArray = _columnWidths.Split(System.Convert.ToChar(";")); 
            int w = 0;
            foreach (string str in columnWidthsArray)
                w += System.Convert.ToInt32(System.Convert.ToInt32(str) * intScreenMagnification / 100);// ******
            DropDownWidth = (w + 20);
        }
    }

    // Constructor stuff
    public MultiColumnCombocs() : base()
    {
        base.IntegralHeight = false;
        base.DrawMode = DrawMode.OwnerDrawFixed;
        base.DropDownStyle = ComboBoxStyle.DropDown;
        MaxDropDownItems = 12;
        // Minimise flicker in painted control
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    }

    protected override void WndProc(ref Message m)  // Listen for operating system messages
    {   
        base.WndProc(ref m);  /*Inheriting controls should call the base class's WndProc(Message) method
                                to process any messages that they do not handle.*/
        switch (m.Msg)
        {
            case WM_PAINT:
                // Draw Combobox and dropdown arrow
                Graphics g = this.CreateGraphics();
                // Background - Only the borders will show up because the edit box will be overlayed
                try
                {
                    backgroundBrush = new SolidBrush(Color.White);
                    g.FillRectangle(backgroundBrush, 0, 0, Size.Width, Size.Height);
                    // Border
                    Rectangle rectangle = new Rectangle();
                    Pen pen = new Pen(BorderColor, 2);
                    rectangle.Size = new Size(Width - 2, Height);
                    g.DrawRectangle(pen, rectangle);
                    
                    // Background of the dropdown button
                    ButtonBrush = new SolidBrush(ButtonColor);
                    Rectangle rect = new Rectangle(Width - 15, 0, 15, Height);
                    g.FillRectangle(ButtonBrush, rect);

                    // Create the path for the arrow
                    g.SmoothingMode = SmoothingMode.AntiAlias;

                    GraphicsPath pth = new GraphicsPath();
                    PointF TopLeft = new PointF(Width - 12, System.Convert.ToSingle((Height - 5) / 2));
                    PointF TopRight = new PointF(Width - 5, System.Convert.ToSingle((Height - 5) / 2));
                    PointF Bottom = new PointF(Width - 8, System.Convert.ToSingle((Height + 4) / 2));
                    pth.AddLine(TopLeft, TopRight);
                    pth.AddLine(TopRight, Bottom);

                    // Determine the arrow and button's color.
                    arrowBrush = new SolidBrush(Color.Black);

                    if (this.DroppedDown)
                    {
                        arrowBrush = new SolidBrush(Color.Red);
                        ButtonBrush = new SolidBrush(Color.PaleGreen);
                    }
                    // Draw the arrow
                    g.FillRectangle(ButtonBrush, rect);
                    g.FillPath(arrowBrush, pth);

                    pen.Dispose();
                    pth.Dispose();

                }
                finally
                {
                    // Cleanup
                    g.Dispose();
                    arrowBrush.Dispose();
                    backgroundBrush.Dispose();
                }
                break;
               
           default:
              {
                break;
              }
        }
    }

    protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
    {
        // Draw Dropdown with Multicolumns
        Cursor = Cursors.Arrow;
        DataRowView row = (DataRowView)base.Items[e.Index];

        int newpos = e.Bounds.X;
        int endpos = e.Bounds.X;
        int intColumnIndex = 0;

        // Draw the current item text based on the current Font and the custom brush settings
        foreach (string str in columnWidthsArray)
        {
            // paint each column, "intColumnIndex" is local integer
            string strColWidth = columnWidthsArray[intColumnIndex];
            int ColLength = System.Convert.ToInt32(strColWidth);
            // Adjust ColLength
            ColLength = System.Convert.ToInt32(ColLength * intScreenMagnification / 100); // ******
            endpos += ColLength;

            string strColumnText = row[intColumnIndex].ToString();

            if (IsDate(strColumnText))  //Format Date as 'dd-MM-yy' (not avail as 'ToString("Format")'
            {
                strColumnText = strColumnText.Replace("/", "-");
                string strSaveColumn = strColumnText;
                strColumnText = strSaveColumn.Substring(0, 6) + strSaveColumn.Substring(8, 2);
                ColLength = 40;
            }

            // Paint Text
            if (ColLength > 0)
            {
                RectangleF r = new RectangleF(newpos + 1, e.Bounds.Y, endpos - 1, e.Bounds.Height);
                // Colours of normal row and text

                //   Colours of normal row and text
                SolidBrush textBrush = new SolidBrush(Color.Black);
                SolidBrush backbrush = new SolidBrush(Color.White);
                StringFormat strFormat = new StringFormat();
                try 
                {
                    // Colours of selected row and text
                    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                    {
                        textBrush.Color = textselectedcolor; // Red
                        backbrush.Color = bgSelectedColor; // Pale Green
                    }
                    e.Graphics.FillRectangle(backbrush, r);

                    strFormat.Trimming = StringTrimming.Character;
                    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                    e.Graphics.DrawString(strColumnText, e.Font, textBrush, r, strFormat);
                    e.Graphics.SmoothingMode = SmoothingMode.None;
                }
                finally
                { 
                    backbrush.Dispose();
                    strFormat.Dispose();
                    textBrush.Dispose();
                }

                //Separate columns with white border
                if (intColumnIndex > 0 && intColumnIndex <= (columnWidthsArray.Length))
                {
                    e.Graphics.DrawLine(new Pen(Color.White), endpos, e.Bounds.Y, endpos, ItemHeight * MaxDropDownItems);
                }
                newpos = endpos;
                intColumnIndex++;
            } // end if
        }// end for

        // load ValueMember value into combobox when using mouse on dropped down list
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        {
          string selectedItem = SelectedValue.ToString();  
            base.Text = selectedItem.ToString();
        }
    } //end sub

      private bool IsDate(string strColumnText)
      {
        DateTime dateValue;

        if (DateTime.TryParse(strColumnText, out dateValue))
        {
            return true;
        }
        else
        {
            return false;
        }
     } // end sub

    protected override void OnMouseWheel(MouseEventArgs e)
    {
        // Overrides Sub of same name in parent class
        HandledMouseEventArgs MWheel = (HandledMouseEventArgs)e;
        // HandledMouseEventArgs prevents event being sent to parent container
        if (!this.DroppedDown)
        {
            MWheel.Handled = true;
        }
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        if (!this.DroppedDown & e.KeyCode == Keys.Down)
            this.DroppedDown = true;
        else if (e.KeyCode == Keys.Escape)
        {
            this.DroppedDown = false;
            this.SelectedIndex = -1;
            this.Text = null; 
        }
     }


    }
}
  • This is working pretty well for me, but how do you make the selected row's display text show a string from one of the cells? Right now, regardless of which row I select, it displays "System.Data.DataRow" in the combobox. The dropdown looks good though. – Collin Brittain Nov 19 '20 at 21:30
  • Further still.. for Colin I have added some code to the "OnDrawItem", ie if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { string selectedItem = SelectedValue.ToString(); base.Text = selectedItem.ToString(); } I have updated the code.... you will need to set "DisplayMember" and "ValueMember" to "" in the main application – Bruce Caldwell Apr 19 '21 at 06:00
  • Further still even more....... I have extended the ESC key processing in the main code so the Text clears when pressing ESC by adding the following: this.DroppedDown = false; this.SelectedIndex = -1; this.Text = null; – Bruce Caldwell Apr 20 '21 at 04:43
0

You can't have a multiple column combo-box.

Would you not be better off using a DataGridView instead

James
  • 80,725
  • 18
  • 167
  • 237
  • The fact that it doesn't exist natively in the .NET framework doesn't mean you can't have it... You can code it yourself, or use a third party control – Thomas Levesque Jul 07 '09 at 10:11
  • Think he is looking to do this via the standard controls in .NET tho – James Jul 07 '09 at 10:15
  • Thanks James. I will use a DataGridView instead now that am sure that there is no out of the box multiple column combobox in .Net. –  Jul 07 '09 at 10:19
  • You are right James. I was looking for standard controls in .Net. –  Jul 07 '09 at 10:24
0

Quick solution
Datatables should be partical classes as far as I remember

  1. Create a 2nd file for your datatable MyDataTable.custom.cs
  2. Add a string property in the partial datatable class called "DisplayProperty"
  3. In that property return a string.format("{0} {1} {2}", Auftragsnummer, Kunde, Beschreibung);
  4. Bind your Datamember to your DisplayProperty
Peter Gfader
  • 7,673
  • 8
  • 55
  • 56
0

The MultiColumn ComboBox Control combines the Text Box control to edit and the Grid View in the drop down list to display data.

0

easy and quick! look at this...

combobox.Datasource = 
entities.tableName.Select(a => a.Coulmn1 + " " + a.Coulmn2).ToList();
0

The full C# solution I provided for a Multicolumn Combo Box caused a problem when debugging in the app that used it. The problem was with the line "DateTime dt = DateTime.Parse(strColumnText);" in the method "IsDate" here is a new version of the method that uses DateTimeTryparse" instead: I have replaced the faulty version in the original. (N B For all its faults, it works!) cheers, Bruce Caldwell

     private bool IsDate(string strColumnText)
    {
        DateTime dateValue;

        if (DateTime.TryParse(strColumnText, out dateValue))
        {
            return true;
        }
        else
        {
            return false;
        }
    } // end sub