Reputation:
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.
Upvotes: 17
Views: 106511
Reputation: 21
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;
}
}
}
}
Upvotes: 2
Reputation: 21
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
Upvotes: 0
Reputation: 111
easy and quick! look at this...
combobox.Datasource =
entities.tableName.Select(a => a.Coulmn1 + " " + a.Coulmn2).ToList();
Upvotes: 0
Reputation: 3131
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
Upvotes: 10
Reputation: 1
The MultiColumn ComboBox Control combines the Text Box control to edit and the Grid View in the drop down list to display data.
Upvotes: 0
Reputation: 71
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.
Upvotes: 7
Reputation: 10638
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).
Upvotes: 3
Reputation: 7751
Quick solution
Datatables should be partical classes as far as I remember
Upvotes: 0
Reputation: 23848
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?
Upvotes: 12
Reputation: 62970
There's an article on Code Project describing how a Multicolumn ComboBox can be created.
Multicolumn Combobox - Code Project
Upvotes: 2
Reputation: 82136
You can't have a multiple column combo-box.
Would you not be better off using a DataGridView instead
Upvotes: 0