Field rendering in DataGridView with dynamic query

M

michael sorens

If I populate a DataGridView with a query supplied at runtime, boolean fields
render as a CheckBox instead of just a text rendering of '0' or '1'. That is
nice sometimes, but I would like the flexibility of showing text sometimes as
well. Is there an easy way to get the text '0' or '1' instead of the
CheckBox? My DataGridView is filled in with this basic code:

DataTable dataTable = new DataTable();
qBindingSource.DataSource = dataTable;
qBindingSource.DataMember = null;
SqlDataAdapter tableAdapter = new SqlDataAdapter(myQuery, myConnString);
tableAdapter.Fill(dataTable);

Note that the query is completely arbirtrary so I do not know in advance
which columns, if any, are boolean.

My basic approach would be to have a button that lets the user switch
between "raw" (i.e. 0 or 1 showing) and "enhanced" (i.e. with checkboxes)
displays. Then after I load the DataGridView, scan each column type, looking
for DataGridViewCheckBoxColumn. Could I just change that to
DataGridViewTextBoxColumn on the fly? Also, when I am showing checkboxes, I
want to distinguish 0 from null, so could I change the ThreeState property on
the fly as well?

Environment: C# 2.0, .NET 2.0, VS2005
 
N

Nicholas Paldino [.NET/C# MVP]

Michael,

That's exactly how I would do it. Instead of letting the DataGridView
figure out how to display the columns, you manually add the columns that you
want to it, applying whatever logic you want (in this case, the checkbox
with the three-state logic, or the text column) and then set the data
source.
 
M

michael sorens

While you said "yes" to my suggestion, your explanation implies "no". Let me
explain. My sample code populates the DataGridView "automatically". I wanted
to just change the column type (somehow) and have it then behave differently.
What I infer from your response, however, is that I need to replace the
column with one of a different type. I found a post that indicates that this
means all the data is lost, however
(http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=217676&SiteID=1). The
performance hit, I suspect, would be too great on a table with a hundred
thousand lines, for example.

So, backing up to your actual suggestion--creating the DataGridView
customized from the start--could you point me to any sample code that
populates the DataGridView less automatically so that I could, as you
suggest, customize to what I want?
 
L

Linda Liu[MSFT]

Hi Michael,
Could I just change that to DataGridViewTextBoxColumn on the fly?

No, you have to remove the DataGridViewCheckBoxColumn that is generated by
the DataGridView automatically after its DataSource property is set and
then insert a DataGridViewTextBoxColumn at the postion of the original
DataGridViewCheckBoxColumn.
when I am showing checkboxes, I want to distinguish 0 from null, so could
I change the ThreeState property on the fly as well?

Yes, you can. Enumerate through the columns in the DataGridView and if it
is DataGridViewCheckBoxColumn, set the ThreeState property of the column to
true.
What I infer from your response, however, is that I need to replace the
column with one of a different type. I found a post that indicates that
this means all the data is lost,

If the column is bound to a data source, the data will not be lost. The
post you mentioned is concerned about these columns that are not bound to
any data source.

I will illustrate how to get what you want with a sample. It requires that
you create a WinForm applicatioin project and add a DataGridView and a
Button on the form. You also need to set the Text property of the Button to
"TextBox".

public partial class Form1 : Form
{
DataTable table = new DataTable();
private void Form1_Load(object sender, EventArgs e)
{
DataColumn col = new DataColumn("ID", typeof(int));
table.Columns.Add(col);
col = new DataColumn("Bool Value 1", typeof(bool));
table.Columns.Add(col);
col = new DataColumn("Bool Value 2", typeof(bool));
table.Columns.Add(col);
col = new DataColumn("Name");
table.Columns.Add(col);

DataRow row = table.NewRow();
row[0] = 1;
row[1] = true;
row[2] = false;
row[3] = "row 1";
table.Rows.Add(row);

row = table.NewRow();
row[0] = 2;
row[2] = true;
row[3] = "row 2";
table.Rows.Add(row);

row = table.NewRow();
row[0] = 3;
row[1] = false;
row[3] = "row 3";
table.Rows.Add(row);
}

private void button1_Click(object sender, EventArgs e)
{
if (this.button1.Text == "TextBox")
{
this.button1.Text = "CheckBox";
this.dataGridView1.DataSource = null;
this.dataGridView1.DataSource = table;
for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
{
if (this.dataGridView1.Columns.GetType() ==
typeof(DataGridViewCheckBoxColumn))
{
DataGridViewTextBoxColumn txtColumn = new
DataGridViewTextBoxColumn();
txtColumn.HeaderText =
this.dataGridView1.Columns.HeaderText;
txtColumn.DataPropertyName =
this.dataGridView1.Columns.DataPropertyName;
this.dataGridView1.Columns.RemoveAt(i);
this.dataGridView1.Columns.Insert(i, txtColumn);
}
}
}
else
{
this.button1.Text = "TextBox";
this.dataGridView1.DataSource = null;
this.dataGridView1.DataSource = table;
for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
{
if (this.dataGridView1.Columns.GetType() ==
typeof(DataGridViewCheckBoxColumn))
{
(this.dataGridView1.Columns as
DataGridViewCheckBoxColumn).ThreeState = true;
}
}
}
}
}

Build and run the application. At first, the Text of the Button is
"TextBox". Click the button, and you should see the DataGridView is
populated with four columns and the two columns in the middle are
DataGridViewTextBoxColumn. Click the button again, and you still see four
columns in the DataGridView but the two columns in the middle become
DataGridViewCheckBoxColumn.

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
M

michael sorens

[I am hoping this will still get read even though I already marked that the
question had been answered...]

While my original question was answered, I have a follow-up:
Changing the CheckBox column to a Text column renders "True" or "False"
rather than a checked/unchecked box. That is better for my application, but
what I really want is the raw data, i.e. 0 or 1. How does one do this?
 
L

Linda Liu[MSFT]

Hi Michael,
That is better for my application, but what I really want is the raw
data, i.e. 0 or 1. How does one do this?

You can handle the CellFormatting event of the DataGridView to show 0 or 1
instead of True or False in the cells.

The following is a sample:

void dataGridView1_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
DataGridView dgv = sender as DataGridView;
if (dgv.Columns[e.ColumnIndex].GetType() ==
typeof(DataGridViewTextBoxColumn)
&& e.Value != null && e.Value.GetType() == typeof(bool))
{
if ((bool)e.Value)
e.Value = "1";
else
e.Value = "0";

e.FormattingApplied = true;
}
}

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
M

michael sorens

Thanks for the pointer on that; right on target!

Last question on the same topic: For a column that contains a DateTime
value, I tracked down an issue where the column of a DataGridView renders a
date in a default format of "mm/dd/yyyy hh:mm AM" yet if I print the value
from that column to the console it has seconds as well. How do I change the
date formatting in a DataGridView to show the seconds as well? Or to show the
time without the date?
 
L

Linda Liu[MSFT]

Hi Michael,
How do I change the date formatting in a DataGridView to show the seconds
as well? Or to show the time without the date?

You can set the Format property of the DefaultCellStyle property of the
DataGridView column that contains date time values to the "T". For example,

this.dataGridView1.DataSource = datatable;
for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
{
if (this.dataGridView1.Columns.ValueType == typeof(DateTime))
{
DataGridViewCellStyle dgvcellStyle = new
DataGridViewCellStyle();
dgvcellStyle.Format = "T";
this.dataGridView1.Columns.DefaultCellStyle = dgvcellStyle;
}
}

Hope this helps.
If you have any question, please feel free to let me know.

PS. (just a reminding) You'd better post new posts for new questions in the
future. Thanks!


Sincerely,
Linda Liu
Microsoft Online Community Support
 
A

Andrus

DataGridViewCellStyle dgvcellStyle = new
DataGridViewCellStyle();
dgvcellStyle.Format = "T";
this.dataGridView1.Columns.DefaultCellStyle =
dgvcellStyle;


Much simpler is set DefaultCellStyle directly:

this.dataGridView1.Columns.DefaultCellStyle.Format = "T";

Andrus.
 
M

michael sorens

Thanks both to Linda for putting me in the correct location and Andrus for
the short form of the assignment. I found the reference page that tells me
what "T" et al actually mean so I can use other variations as well.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top