Click here to Skip to main content
15,891,607 members
Articles / Programming Languages / C#

Multi Column Combo Cell for the .NET 2.0 DataGridView Control

Rate me:
Please Sign up or sign in to vote.
3.19/5 (14 votes)
25 Dec 2008CPOL2 min read 194.9K   9.8K   70   66
This article will demonstrate an approach to solve the issue of a multi-column cell for DataGridView.

Illustration.gif

Introduction

This article will demonstrate an approach to solve the issue of multi-column combobox cells in a DataGridView in VS8.

*New in this version

*After multiple comments that I got about the old implementation, I decided to make this solution nicer. I am following the solution using designed DataSet tables and dropping some workarounds and fixing some bugs I had in my first version!

Background

Several months ago, I invested several days in order to find how to implement the multiline combobox issue. I found several solutions but they didn't fit my needs. I wanted something very simple. And I found it using the owner draw approach - just drawing a multicolumn control by myself. Here are the results.

Using the code

The code implementation and usage is extremely simple.

You do all the steps as you do if you want to embed a regular combobox into your DataGridView, but in place of the DataGridViewComboColumn, you use my class DataGridViewMultiColumnComboColumn. This class is derived from DataGridViewComboColumn. Additionally, you need to set the column CellTemplate with the DataGridViewMultiColumnComboCell class that is derived from DataGridViewMultiColumnComboCell. After creating the DataGridViewMultiColumnComboCell class, you will need to set two data members in order to allow the multiline combobox to display the relevant values.

C#
//create the multicolumncombo column
DataGridViewMultiColumnComboColumn newColumn = 
            new DataGridViewMultiColumnComboColumn();

newColumn.CellTemplate = new DataGridViewMultiColumnComboCell();
//Set the source table settings from the database for combobox values
newColumn.DataSource = ds.LogMessageTypes;
newColumn.DisplayMember = ds.LogMessageTypes.TypeNameColumn.ColumnName;
newColumn.ValueMember = ds.LogMessageTypes.TypeIdColumn.ColumnName;

//this property point on main table of this grid to bind to this column
newColumn.DataPropertyName = ds.LogTable.TypeColumn.ColumnName;
newColumn.HeaderText = ds.LogTable.TypeColumn.ColumnName;

newColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;

dataGridView1.Columns.Remove(ds.LogTable.TypeColumn.ColumnName);
dataGridView1.Columns.Insert(position, newColumn);
dataGridView1.Columns[position].Width = 300;

Points of interest

First, I am very happy that after 12 years of programming experience I found a way to contribute something small to this great professional discussion.

I am originally a C++/MFC programmer and I still work mostly using these programming languages. So I am strictly used to things that implement non-standard UIs. I think Microsoft did a great job developing the .NET platform. Anyway.

BTW: I still love developing ActiveX in C++ but there is no client that wants it anymore and I can understand why :).

Disclaimer of warranty

All of the code, information, instructions, and recommendations in this article are offered on a strictly "as is" basis. This material is offered as a free public resource, without any warranty, expressed or implied.

This code is completely free. I will be happy to know if it was helpful for somebody.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Israel Israel
Software Development freelancer.

Comments and Discussions

 
QuestionHow to display in the comboxbox all the items Pin
dsapo8-Aug-08 4:35
dsapo8-Aug-08 4:35 
AnswerRe: How to display in the comboxbox all the items Pin
IssaharNoam25-Dec-08 5:58
IssaharNoam25-Dec-08 5:58 
QuestionAnyone have some more solid code? Pin
Member 359872110-Jun-08 8:12
Member 359872110-Jun-08 8:12 
AnswerRe: Anyone have some more solid code? Pin
IssaharNoam10-Jun-08 10:20
IssaharNoam10-Jun-08 10:20 
AnswerRe: Anyone have some more solid code? Pin
IssaharNoam25-Dec-08 6:00
IssaharNoam25-Dec-08 6:00 
QuestionMultiline combobox Pin
kaandemirtas3-Feb-08 7:43
kaandemirtas3-Feb-08 7:43 
AnswerRe: Multiline combobox Pin
IssaharNoam25-Dec-08 6:00
IssaharNoam25-Dec-08 6:00 
QuestionQuestion from the article Multi Column Combo Cell C#, hoping for author to help! Pin
quakertistar1-Oct-07 3:17
quakertistar1-Oct-07 3:17 
I've tried so hard for a whole day that I still cannot get through this tough problem, somebody please, help me!



I've got the code for Multi Column Combo in DataGridView to solve the problem of displaying multiple data, but I got stuck in displaying some values. Everything goes just fine, but when I tried to display values with the key value diplicated, it doesn't work. For example, I intended to display two rows "bmx2100 |23455 |34" and "bmx2100 |11111 |100", they have the same attribute "bmx2100", but the primary key "23455" and "11111" are different. That was what suppose to be, but now, the program displayed "bmx2100 |23455 |34" twice, and during DEBUG, I print out all the temporary variables and I found that they are all correct! So, what would be the problem!?



This is the Multi Column Combo Cell : http://www.codeproject.com/useritems/Multi_Column_Combo_Cell.asp



And this is the code snippet I modified:




protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)<br />
{<br />
Rectangle rec = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);<br />
DataGridViewMultiColumnComboColumn column = ownerCell.OwningColumn as DataGridViewMultiColumnComboColumn;<br />
DataTable valuesTbl = column.valuesTbl;<br />
string joinByField = column.joinFieldName;<br />
SolidBrush NormalText = new SolidBrush(System.Drawing.SystemColors.ControlText);<br />
object currentItem = Items[e.Index];<br />
string currentText = GetItemText(currentItem);<br />
<br />
//If there is an item<br />
if (e.Index > -1)<br />
{<br />
//first redraw the normal while background<br />
SolidBrush normalBack = new SolidBrush(Color.White); //TODO: fix to be system edit box background<br />
e.Graphics.FillRectangle(normalBack, rec);<br />
if (DroppedDown && !(Margin.Top == rec.Top))<br />
{<br />
int currentOffset = rec.Left;<br />
<br />
//now find this text corrent join field<br />
DataRow[] itemRows = valuesTbl.Select("[" + joinByField + "]='" + currentText + "'");<br />
<br />
SolidBrush HightlightedBack = new SolidBrush(System.Drawing.SystemColors.Highlight);<br />
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)<br />
{<br />
//draw selected color background<br />
e.Graphics.FillRectangle(HightlightedBack, rec);<br />
}<br />
StreamWriter sw = new StreamWriter(File.OpenWrite("record"));<br />
foreach (DataRow currentRow in itemRows)<br />
{<br />
bool addBorder = false;<br />
<br />
foreach (object dataRowItem in currentRow.ItemArray)<br />
{<br />
string value = dataRowItem.ToString(); //TODO: support for different types!!!<br />
<br />
<br />
<br />
#region DrawLine<br />
if (addBorder)<br />
{<br />
//draw dividing line<br />
//currentOffset ++; <br />
SolidBrush gridBrush = new SolidBrush(Color.Gray); //TODO: make the border color configurable<br />
long linesNum = lineWidth;<br />
while (linesNum > 0)<br />
{<br />
linesNum--;<br />
Point first = new Point(rec.Left + currentOffset, rec.Top);<br />
Point last = new Point(rec.Left + currentOffset, rec.Bottom);<br />
e.Graphics.DrawLine(new Pen(gridBrush), first, last);<br />
currentOffset++;<br />
}<br />
//currentOffset++;<br />
}<br />
else<br />
addBorder = true;<br />
#endregion<br />
<br />
//measure the string that we are goin to draw and cut it with wrapping if too large<br />
SizeF extent = e.Graphics.MeasureString(value, e.Font);<br />
Rectangle textRec = new Rectangle(currentOffset, rec.Y, (int)extent.Width + 20, rec.Height);<br />
<br />
//now draw the relevant to this column value text<br />
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)<br />
{<br />
//draw selected<br />
SolidBrush HightlightedText = new SolidBrush(System.Drawing.SystemColors.HighlightText);<br />
//now redraw the backgrond it order to wrap the previous field if was too large<br />
e.Graphics.FillRectangle(HightlightedBack, currentOffset, rec.Y, fixedAlignColumnSize, extent.Height);<br />
//draw text as is <br />
e.Graphics.DrawString(value, e.Font, HightlightedText, textRec); sw.Write(value + "|");<br />
}<br />
else<br />
{<br />
//now redraw the backgrond it order to wrap the previous field if was too large<br />
e.Graphics.FillRectangle(normalBack, currentOffset, rec.Y, fixedAlignColumnSize, extent.Height);<br />
//draw text as is <br />
e.Graphics.DrawString(value, e.Font, NormalText, textRec); sw.Write(value + "|");<br />
}<br />
//advance the offset to the next position<br />
currentOffset += fixedAlignColumnSize;<br />
}<br />
sw.WriteLine();<br />
}<br />
sw.Close();<br />
}<br />
else<br />
//if happens when the combo is closed, draw single standard item view<br />
e.Graphics.DrawString(currentText, e.Font, NormalText, rec);<br />
}<br />
}<br />
/**************************************************************************************************/<br />
} 

AnswerRe: Question from the article Multi Column Combo Cell C#, hoping for author to help! Pin
IssaharNoam7-Oct-07 5:26
IssaharNoam7-Oct-07 5:26 
GeneralRe: Question from the article Multi Column Combo Cell C#, hoping for author to help! Pin
quakertistar8-Oct-07 4:49
quakertistar8-Oct-07 4:49 
GeneralDrop Down Arrow Pin
Barry T7-Sep-07 7:18
Barry T7-Sep-07 7:18 
GeneralRe: Drop Down Arrow Pin
Barry T7-Sep-07 8:35
Barry T7-Sep-07 8:35 
QuestionC++ *and* C#? Pin
#realJSOP10-Apr-07 2:39
mve#realJSOP10-Apr-07 2:39 
AnswerRe: C++ *and* C#? Pin
toxcct10-Apr-07 7:41
toxcct10-Apr-07 7:41 
GeneralRe: C++ *and* C#? Pin
IssaharNoam10-Apr-07 9:28
IssaharNoam10-Apr-07 9:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.