ComponentOne TrueDbGrid provides support for displaying boolean values as checkboxes. This is done by setting the Presentation property to PresentationEnum.CheckBox (for more information refer to C1TrueDbGrid Documentation). However, there is no direct property or method available in the control to display checkbox in the column header of boolean column. This blog explains the approach to display checkbox in the column header. The actual implementation is to set the HeadingStyle.ForegroundImage of the DisplayColumn and toggle the checking/unchecking of rows and image in the HeadClick event of C1TrueDbGrid.
First step is to bind C1TrueDbGrid. For simplicity we will bind the grid with Products table of C1Nwind.mdb. We will define our own Custom Sorting. For this, disable the default sorting of the grid by setting the AllowSort property to False and make the column header act like buttons by setting the ButtonHeader property of all DisplayColumns to true. The SortOrder of the grid will be saved in the DisplayColumn.Tag property. Also, we will set the HeadingStyle.ForegroundImage of 'Discontinued' column to indeterminate checkbox image. The code for FormLoad event looks as follows :
enum SortDir { None, Asc, Desc };
Image imgCheck, imgUncheck, imgIndeterminate;
Bitmap \_sortup, \_sortdn;
bool flag = true;
//Form Load event
private void Form1_Load(object sender, EventArgs e)
{
OleDbConnection1.ConnectionString = GetModifiedConnectionString(OleDbConnection1.ConnectionString);
OleDbDataAdapter1.Fill(c1NWindDataSet1.Products);
c1TrueDBGrid1.DataSource = c1NWindDataSet1.Tables["Products"].DefaultView;
c1TrueDBGrid1.AllowSort = false;
foreach (C1.Win.C1TrueDBGrid.C1DisplayColumn dc in c1TrueDBGrid1.Splits[0].DisplayColumns)
{
// make the column headers act like buttons
dc.ButtonHeader = true;
// default sort order
dc.DataColumn.Tag = SortDir.None;
}
//set the image paths
imgCheck = Properties.Resources.Check;
imgUncheck = Properties.Resources.Uncheck;
imgIndeterminate = Properties.Resources.Indeterminate;
_sortdn = Properties.Resources.SortDn;
_sortup = Properties.Resources.SortUp;
_sortdn.MakeTransparent(Color.Red);
_sortup.MakeTransparent(Color.Red);
c1TrueDBGrid1.Splits[0].DisplayColumns["Discontinued"].HeadingStyle.ForegroundImage = imgIndeterminate;
}
We will add the checkboxes and apply custom sorting in the HeadClick event. When the clicked DisplayColumn is not "Discontinued", then custom sorting is applied and sort images are added to the grid header. Otherwise, check/uncheck images are toggled and grid rows are checked and unchecked.
//Handles Custom Sorting and Setting of Checked/Unchecked Images
private void c1TrueDBGrid1_HeadClick(object sender, ColEventArgs e)
{
// get the display column that was clicked
C1.Win.C1TrueDBGrid.C1DisplayColumn dc = this.c1TrueDBGrid1.Splits[0].DisplayColumns[e.ColIndex];
//Exclude "EmployeeId" from Sort procedure
if(dc.DataColumn.DataField != "Discontinued")
{
// new sort order
SortDir newsort = SortDir.None;
switch ((SortDir)dc.DataColumn.Tag)
{
case SortDir.None:
case SortDir.Desc: newsort = SortDir.Asc;
break;
default: newsort = SortDir.Desc;
break;
}
// clear all sort states and our sort indicators
foreach (C1.Win.C1TrueDBGrid.C1DisplayColumn col in c1TrueDBGrid1.Splits[0].DisplayColumns)
{
if (col.DataColumn.DataField != "Discontinued")
{
col.DataColumn.Tag = SortDir.None;
col.HeadingStyle.ForegroundImage = null;
}
}
//build our new sort condition
string sortCondition = dc.DataColumn.DataField + " ";
sortCondition += (newsort == SortDir.Desc ? "DESC" : "");
// sort it
c1NWindDataSet1.Tables["Products"].DefaultView.Sort = sortCondition;
// save the sort state
dc.DataColumn.Tag = newsort;
// update the sorting indicator
if( newsort == SortDir.Asc )
dc.HeadingStyle.ForegroundImage = _sortup;
else
dc.HeadingStyle.ForegroundImage = _sortdn;
}
else
{
//update the column check indicator on "Discontinued"
if(flag)
{
dc.HeadingStyle.ForegroundImage = imgCheck ;
flag = false;
for (int i = 0; i < this.c1TrueDBGrid1.RowCount; i++)
this.c1TrueDBGrid1[i, 9] = true;
}
else
{
dc.HeadingStyle.ForegroundImage = imgUncheck;
for (int i = 0; i < this.c1TrueDBGrid1.RowCount; i++)
this.c1TrueDBGrid1[i, 9] = false;
}
flag = true;
}
// sort/check indicators go to the right of header text
dc.HeadingStyle.ForeGroundPicturePosition = C1.Win.C1TrueDBGrid.ForeGroundPicturePositionEnum.LeftOfText;
}
}
Now, if the cell value of "Discontinued" column is changed after setting the check/uncheck images, then the header image is changed to Indeterminate image in the 'AfterColUpdate' event. The code for this is :
//Changes the Column Header Image to Indeterminate if any checkbox state is changed in the grid
private void c1TrueDBGrid1_AfterColUpdate(object sender, ColEventArgs e)
{
if (e.ColIndex == 9)
{
if (e.Column.DataColumn.Value != (object)flag )
this.c1TrueDBGrid1.Splits[0].DisplayColumns[9].HeadingStyle.ForegroundImage = imgIndeterminate;
}
}