Using an Enum Class in a DataGridView Combobox Column

Objective
The purpose of this article is to provide a working example of an enum
class column on a DataGridView
on a Windows Form using C++/CLI where data is drawn from multiple datasources via DataTables
. It will also show a simplified approach to the same feature drawing data from a single source without using a DataTable
and some other unrelated features:
- Row banding
- Cell highlighting
- Error Icons in individual cells
- Using an
enum
class as a flag set - Building a
DataGridView
from multiple data sources
Background
There are very few examples of enum
class columns on the DataGridView
for C++/CLI or indeed C# returned when searching the web, but plenty of requests for assistance. The examples that are present populate their grids from a single datasource
and are both simple and effective in their execution. However, my attempts to broaden this approach to a DataGridView
drawing its data from two or more data sources led to persistent encounters with the display errors: “Error Happened: Formatting, Display” and “Error Happened: Formatting, Preferred Size”. This is down to a conflict between the natural state of an enum
class entry which is ‘Int
’ and the natural state of a DataGridView
cell which is ‘String
’, and it’s not as simple as a quick cast.
Example Origin
The example is drawn from a system I am working on, which relies heavily on expiry dates. Items can expire by a number of time units added to the current date, e.g., two weeks from Today, or by ‘Fixed
’ units where by the time unit ends on a specified day regardless of commencement, e.g., Friday of next week. For simplicity, the example has a hardcoded representation of the ExpiryMaster
table as its primary datasource
and an extract of the Units hardcoded as its secondary datasource
. Fixed intervals have been omitted because they do not add any additional value to the example. I have chosen to hardcode the datasource
s because I presume I am not alone in downloading CodeProject examples only to find I do not have the $%^*!%$ (sorry, required) database installed.
Presenting Data from a Single DataSource
This is the stuff of a Tech Tip, such is its simplicity. There are essentially only two key extra lines involved.
- Create a new Windows Form Application
- Put a new
DataGridView
on the Form - Add two Columns to the form, a text column ‘
dgName
’ and a combobox column ‘dgStatus
’ - Define your
enum
class before the definition of theForm1
class:
public enum class Status_Type {Married, Single};
Add these two lines to the Form1 Constructor
(or load event):
dgStatus->ValueType = Status_Type::typeid;
dgStatus->DataSource = Enum::GetValues(Status_Type::typeid);
Compile and run the application, and there you have it, a working enum
class column in a DataGridView
.
Here's some data to load in:
dataGridView1->Rows->Clear();
array<Object^>^ itemRec = gcnew array<Object^> {"Sean",Status_Type::Married};
dataGridView1->Rows->Add(itemRec);
array<Object^>^ itemRec2 = gcnew array<Object^> {"Tom",Status_Type::Single};
dataGridView1->Rows->Add(itemRec2);
And this works well while data is added row by row through the Rows?Add method. Hardly this stuff of legend. The code for this is in the attached DataGridView1
example.
The fun starts when the DataGridView
is mapped to a DataTable
!
The Enum Class Column on a DataGridView that Draws Data from Multiple Sources using DataTables
When populating your DataGridView
using a DataTable
, the secret to a successful enum
class based column is to map that enum
class to a DataTable
of its own, and treat it as any other secondary datasource
.
Our Objective
This is what we are aiming for:

Architecturally, the primary DataTable
is driven by the ExpiryMaster DataSource
, and there are secondary DataTables
for the Expiry
Type enum
class and another for the Unit DataSource
. The DataTable
derived from the Unit DataSource
drives two combobox columns for good measure, allowing your user to choose a Unit by ID or by Description with the other value updated to correspond.
The Ingredients for a Successful Enum
The Enum
class can be defined immediately before the Form
class:
public enum class Expiry_Type {Units, Fixed_Date};
(although in my working system, I keep definitions like this in a shared assembly).
Include these definitions in your Form
class to enable mapping of the enum
class to a DataTable
:
DataSet ^dsExpTyp;
BindingSource ^bsExpTyp;
DataTable ^dtExpTyp;
I have included a temporary variable to interrogate new values coming from the datagrid
:
Expiry_Type empExpType;
You may position them using the IDE or by referencing my attached example (DataGridEnum4
).
As part of my LaunchForm
function called from my form
constructor, I have:
A definition for the DataTable
that will hold the Enum
class:
dtExpTyp = gcnew DataTable("dtExpTyp");
dtExpTyp->Columns->Add("Expiry_Type", Int32::typeid);
dtExpTyp->Columns->Add("Expiry_Type_Desc", String::typeid);
bsExpTyp = gcnew BindingSource();
dsExpTyp = gcnew DataSet();
dsExpTyp->Tables->Add(dtExpTyp);
The DataTable
that maps to the DataGridView
needs this entry to map to the above datastructure
:
dtViewExpiryData->Columns->Add("Expiry_Type", Int32::typeid);
The datasource
for the column is defined as follows:
gridExpiry->Columns[dgExpiry_Type->Index]->DataPropertyName = "Expiry_Type";
Note: In this example, the DataGridView
is called ‘gridExpiry
’.
And a call to a function that will do the mapping:
Load_Expiry_Enum();
You can see their placement in the example.
The Load_Expiry_Enum()
source code is:
{
DataRow ^row;
for each (Expiry_Type^ tmpEx in Enum::GetValues(Expiry_Type::typeid))
{
row = dsExpTyp->Tables["dtExpTyp"]->NewRow();
row["Expiry_Type"] = tmpEx;
row["Expiry_Type_Desc"] = tmpEx->ToString();
dsExpTyp->Tables["dtExpTyp"]->Rows->Add(row);
}
// Set up the UnitDesc binding source
bsExpTyp->DataSource = dsExpTyp;
bsExpTyp->DataMember = "dtExpTyp";
// bind Name
dgExpiry_Type->DataSource = bsExpTyp;
dgExpiry_Type->DisplayMember = "Expiry_Type_Desc";
dgExpiry_Type->ValueMember = "Expiry_Type";
}
The section that follows this one will show you how this fits in to the primary datasource
in the same manner any other secondary datasource
. In the meantime, we will conclude this section by looking at the code to fetch, display, and interrogate the data on the enum
class column on the DataGridView
.
Now, we will look at two ways of getting the data from the enum
column.
try
{
if (gridExpiry->Rows[e->RowIndex]->Cells[dgExpiry_Type->Index]->Value != nullptr
&&gridExpiry->Rows[e->RowIndex]->Cells[dgExpiry_Type->Index]->
Value->ToString() != "")
{
String^ IntExpType = gridExpiry->Rows[e->RowIndex]->
Cells[dgExpiry_Type->Index]->Value->ToString();
empExpType = safe_cast<Expiry_Type>
(System::Convert::ToInt32(IntExpType));
lblExpiryType->Text = empExpType.ToString();
}
}
catch (...)
{
lblExpiryType->Text = nullptr;
}
And:
array<DataRow^>^ row;
try
{
if (gridExpiry->Rows[e->RowIndex]->Cells[dgExpiry_Type->Index]->Value != nullptr
&&gridExpiry->Rows[e->RowIndex]->Cells[dgExpiry_Type->Index]->
Value->ToString() != "")
{
String^ IntExpType = gridExpiry->Rows[e->RowIndex]->
Cells[dgExpiry_Type->Index]->Value->ToString();
row =dtExpTyp->Select(String::Format("Expiry_Type={0}", IntExpType));
if (row->Length > 0)
{
// ItemArray[0] holds the integer representation of the enum,
// alternately
lblExpiryType->Text = row[0]->ItemArray[1]->ToString();
}
}
}
catch (Exception ^e)
{
String ^MessageString =
" Error reading internal enum table for Expiry Type: " + e->Message;
MessageBox::Show(MessageString);
lblExpiryType->Text = nullptr;
}
Either one of these methods allows you to use your enum
class at will.
Walking Through the Attached Code
The attached DataGridEnum4
example is a complete Visual Studio 2008 project, cleaned before zipping. First a note on my style. I don’t like much more than the definitions in my .h files, so where the IDE adds a Windows Form function to the .h, my practice is to call a user defined function in the .cpp passing on the parameters. It’s an overhead, because I cannot force the IDE to insert Windows Form functions directly into the .cpp, and when I relocate them there, the IDE gets confused – but I prefer the order that it gives things.
This sample is a standard Windows Forms application with a DataGridView
and several labels dropped on from the toolbox as illustrated in the second screenshot. The Expiry Type column is a combobox
column as are Unit ID and Unit Description, the other three columns are textbox
columns. All this is achieved using the form designer.
In here, we will take a further look at the Form1.h and DataGridEnum4.cpp modules.
Form1.h
This is the complete list of assemblies I am referencing:
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::IO;
using namespace System::Collections::Generic;
I have defined the Expiry_Type enum
class inside the application namespace, but before the form class.
In addition to the Launchform
function call, I have one other line in the constructor. This is for the error icon.
m_CellInError = gcnew Point(-2, -2);
After the...
#pragma endregion
...I define my internal variables and functions. Included here is another enum
class, this one prefixed [Flags]
. You will see examples of a flag variable, m_ElementList
, being set and reset throughout the code. This is particularly useful when you need to write an update statement to commit your changes to a database. The flag settings determine the columns that need updating.
There are two variables defined for the error icon handling followed by the definitions for the DataTables
, BindingSources
and DataSets
.
The final segment of the .h file has the function definitions added through the form designer on the IDE for the DataGridView
and the Exit button. They are:
UserAddedRow
(not used in this example)CellValueChanged
CellValidating
(not used in this example)ColumnHeaderMouseClick
– used to eliminate double click on the dropdownsRowEnter
RowValidating
CellBeginEdit
– Stores colours – doesn’t have anything in the .CPPCellEndEdit
– Restores Colour, then calls .CPP functionExit_Click
– Shuts down the exampleCellClick
DataError
DataGridEnum4.cpp
LaunchForm
There are a few interesting ‘bells and whistles’ on show in this function called from the constructor.
This code customized the grid header:
DataGridViewCellStyle^ headerStyle = gcnew DataGridViewCellStyle;
headerStyle->Font = gcnew System::Drawing::Font("Times New Roman", 12,FontStyle::Bold);
gridExpiry->ColumnHeadersDefaultCellStyle = headerStyle;
Personalizing the selection colours:
gridExpiry->DefaultCellStyle->SelectionBackColor=Color::FromArgb(255,255,128);
gridExpiry->DefaultCellStyle->SelectionForeColor=Color::Black;
Tooltip text on the column headers:
for each(DataGridViewColumn^ column in gridExpiry->Columns)
column->ToolTipText = L"Click to\nsort rows";
Apply Colour banding to the grid:
gridExpiry->AlternatingRowsDefaultCellStyle->BackColor = Color::LightGray;
Datatable
for the Units datasource
and the Expiry
Type Enum
class are defined as seen already, followed by the datatable
definition for the expiry datasource
.
Next up, the grid columns are mapped to data properties:
gridExpiry->Columns[dgExpiry_ID->Index]->DataPropertyName = "Expiry_ID";
gridExpiry->Columns[dgExpiry_Type->Index]->DataPropertyName = "Expiry_Type";
gridExpiry->Columns[dgDescription->Index]->DataPropertyName = "Description";
gridExpiry->Columns[dgUnitIDNum->Index]->DataPropertyName = "UnitIDNum";
gridExpiry->Columns[dgUnitDesc->Index]->DataPropertyName = "Unit_ID";
gridExpiry->Columns[Number_Interval_Units->Index]->
DataPropertyName = "Number_Interval_Units";
The function concludes with calls to dedicated functions which will populate each data table and conclude the grid definition.
List_Setup
The key thing here is the binding of the primary datatable
to the DataGridView
:
gridExpiry->DataSource = dtViewExpiryData;
RowEntered
This function has little of note except the initialization of the flags, and reading the data from the combo box columns. I have already given two examples of how to read the comb box columns, here are the Enum
Flags being initialized:
m_ElementList = m_ElementList & ~ m_FlagBits::EXPIRY_ID;
m_ElementList = m_ElementList & ~ m_FlagBits::EXPIRY_TYPE;
m_ElementList = m_ElementList & ~ m_FlagBits::DESCRIPTION;
m_ElementList = m_ElementList & ~ m_FlagBits::UNIT_ID;
m_ElementList = m_ElementList & ~ m_FlagBits::NUMBER_OF_INTERVAL_UNITS;
CellEndEdit
Use this function to display an icon in any cells that you want to enforce population of. In this example, I am applying it at row level to produce this effect:

CellValueChanged
Again, you have already seen how a combobox
column may be read. The other feature of note here is the setting of a flag when a cell value change is detected.
m_ElementList = m_ElementList | m_FlagBits::EXPIRY_ID;
CellClick
ComboBox
columns on DataGridViews
have an annoying habit of needing to be clicked twice in order to open the dropdown. This function has the effect of opening the dropdown as soon as the cell is clicked.
RowValidating
This function places the error icon on any cell that should have a value when your user attempts to leave a row.
DataError
This section is included to handle unforeseen display failures on the DataGridView
. These errors occur when the DataGridView
doesn’t know how to display a particular value. For example, in this solution where we are using datatable
s, if we used the simpler enum
method above, we would see plenty of “Error Happened: Formatting Display” etc., because the DataGridView
is looking for a string
value, but the enum
class is supplying an integer.
That said, it is good practice to include this function regardless of whether or not you are using enum
classes because it nicely catches unexpected display issues with the DataGridView
.
History
- 2011-05-16 - V1.0 - Initial submission
发表评论
Zu9Ooz to find something more safe. Do you have any suggestions?
5FJYxH Websites we recommend Wow, amazing blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your site is fantastic, as well as the content!
hCr2Db There is certainly a great deal to know about this subject. I love all of the points you have made.
qdDuDK Muchos Gracias for your article.Much thanks again. Keep writing.
ICUnQP Looking forward to reading more. Great article post.Much thanks again. Really Great.
FnUmGU Very neat post.Much thanks again. Awesome.
make my blog jump out. Please let me know where you got your design.
You have made some decent points there. I looked on the internet for more information about the issue and found most individuals will go along with your views on this site.
This is really interesting, You are a very skilled blogger. I have joined your feed and look forward to seeking more of your great post. Also, I ave shared your site in my social networks!
Thanks-a-mundo for the blog article.Really thank you! Will read on
The action comedy Red is directed by Robert Schewentke and stars Bruce Willis, Mary Louise Parker, John Malkovich, Morgan Freeman, Helen Mirren, Karl Urban and Brian Cox.
This website was how do I say it? Relevant!! Finally I have found something that helped me. Thank you!
I truly appreciate this blog article. Cool.
I really liked your article. Much obliged.
Wow, amazing blog structure! How lengthy have you ever been blogging for? you make blogging look easy. The whole look of your web site is excellent, as well as the content!
Very good blog.Really looking forward to read more. Cool.
It is truly a great and useful piece of info. I am glad that you shared this helpful information with us. Please keep us informed like this. Thank you for sharing.
Still, the site is moving off blogger and will join the nfl nike jerseys.
Paragraph writing is also a fun, if you be familiar with then you can write
I use pocket money also. I love it. I also use MPG and it allows me to record my gas purchases and maintenance transactions into pocket money right from MPG.
This is very interesting, You are a very skilled blogger. I ave joined your rss feed and look forward to seeking more of your excellent post. Also, I have shared your website in my social networks!
Way cool! Some extremely valid points! I appreciate you penning this post plus the rest of the site is also really good.
Well I definitely liked studying it. This post procured by you is very practical for good planning.
Wow! This could be one particular of the most useful blogs We have ever arrive across on this subject. Actually Wonderful. I am also an expert in this topic therefore I can understand your hard work.
pretty useful material, overall I imagine this is well worth a bookmark, thanks
still care for to keep it smart. I can at wait to read far more from you. This is actually a great site.
loves can you say that about?) louis vuitton hlouis vuitton handbags replicabags replica it as back this fall in mouth watering chocolate. How can you go wrong
Regards for helping out, fantastic information.
It as really a nice and helpful piece of info. I am glad that you just shared this helpful info with us. Please keep us informed like this. Thanks for sharing.
Very informative article post.Really looking forward to read more. Great.
It as hard to come by knowledgeable people on this subject, however, you sound like you know what you are talking about! Thanks
I truly appreciate this post. I have been looking all over for this! Thank God I found it on Google. You ave made my day! Thanks again.
Muchos Gracias for your article.Really looking forward to read more. Will read on
This blog is obviously entertaining and factual. I have found a lot of useful tips out of this amazing blog. I ad love to return over and over again. Thanks a lot!
This blog has lots of very useful stuff on it. Thanks for sharing it with me!
to continue your great job, have a nice afternoon!
your presentation however I find this topic to be really one thing
This is one awesome article post.Really looking forward to read more. Much obliged.
Say, you got a nice post.Much thanks again. Keep writing.
You must take part in a contest for top-of-the-line blogs on the web. I will suggest this web site!
w8ZGeM whoah this blog is magnificent i love reading your articles. Keep up the good work! You know, many people are hunting around for this info, you can aid them greatly.
It as challenging to find educated persons by this topic, nonetheless you sound in the vein of you already make out what you are speaking about! Thanks
Thanks-a-mundo for the post.Much thanks again. Awesome.
Very neat blog.Really thank you! Really Cool.
we like to honor many other world wide web websites around the internet, even if they aren
I think this is a real great article post. Much obliged.
Really appreciate you sharing this article.Really thank you! Want more.
You are my inspiration, I own few web logs and occasionally run out from brand . Truth springs from argument amongst friends. by David Hume.
What as Happening i am new to this, I stumbled upon this I have found It absolutely useful and it has helped me out loads. I hope to contribute & help other users like its helped me. Good job.
Wow, marvelous blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your website is fantastic, as well as the content!