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.

Basic Settings

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;  
}

Adding CheckBox Images to Column Header and Custom Sorting

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;  
    }  
}

Download Sample