avatar

professional geek ramblings
est. 2003
About

Forcing the DataGridView to do my bidding - a tale of ComboBox hackery

*sigh* Winforms team, winforms team, when will you start making my life easier? As others have said (and I completely agree ) windowsforms.net is pretty useless. Well, there's some new Whidbey .NET 2.0 content, but all of the things I enjoyed when starting w/ v1 of .NET (like, erm, QuickStarts? What happened to installing those locally?) seem to be gone. To be fair, they do have a presence over on forums.microsoft.com where there are a few PM's and devs answering questions. I even found a hack fix for my dilemma via one of the posts that links to a download from Beta 2 or somewhere close.

At first I was optimistic about the DataGridView samples (overview)(Download The DataGridView samples), but I didn't see anything that did what I wanted to do: take an enum value and represent it in the grid with a combobox. So, here's how I did it.

First, I just plopped a DataGridView onto a form and gave it a BindingSource. The bindingSource gets its DataSource property set via a call into my DAL that returns a DataTable:

//CF: set to null before setting it to the current to 
//clear out previous results
this.bindingSource1.DataSource = null;

this.bindingSource1.DataSource = MyDal.GetDataTable();

Then comes the hackery. Since I have about 20 columns in this DataTable, all of interest as far as values but not all needing to be visible, directly after (like the line after) setting the datasource, I call a method to format the grid. This method looks something like this:

private void _formatGrid(){
	this.dataGridView1.Columns["ID"].Visible = false;
	this.dataGridView1.Columns.Remove("Status");//CF: this is where we want enums.
	...
	this._formatStatusColumn();
}

Then the _formatStatusColumn method is where the magick happens:

DataTable dt = new DataTable("Status");

//CF: actually how it's stored in the db.
dt.Columns.Add("Status", typeof(int)); 
dt.Columns.Add("Status_Name", typeof(string));

//CF: this way I can add or remove enum values, and
//the combo will always reflect the correct values.
foreach(int index in Enum.GetValues(typeof(Status)){
	dt.Rows.Add(index, Enum.GetName(typeof(Status), index));
}

//CF: now for the UI column
DataGridViewComboBoxColumn statusColumn = 
	new DataGridViewComboBoxColumn();

//CF: seems to control where the column is placed.
statusColumn.DisplayIndex = 3;
statusColumn.HeaderText = "Status";

statusColumn.DataPropertyName = "Status";
statusColumn.DataSource = dt;
statusColumn.DisplayMember = "Status_Name";
statusColumn.ValueMember = "Status";

this.dataGridView1.Columns.Add(statusColumn);

I was hoping that there would be some way to predefine columns so I don't have to filter and rebuild every time I get data from the database, but I couldn't find anything on it. There is no SelectedIndex member of the DataGridViewComboBoxCell, either.

I really hope this helps someone else out there: I tried for a day and a half to get this to work, and I still think it looks like a hack.