Skip to main content Skip to footer

How to Display Row Numbers in C1TrueDBGrid

We often receive requests from our customers asking to implement Row Indexing in C1TrueDBGrid for Winforms similar to what we see in Excel application. Row headers are marked with indexes to identify the rows independently. Currently, there is no built in feature to show the row numbers. This blog explains, how C1TrueDBGrid can be customized to display the row numbers when the grid is bound. Since Record Selector column or the row headers for C1TrueDBGrid is not customizable, we need to define a separate column to replace the original Row Headers. This unbound column is added to the grid that serves to display the row numbers. Placed at the leftmost position in the grid, this unbound column is given the look and feel of the row header. Once the column is added, the UnboundColumnFetch event is used to populate the unbound column with row numbers as shown in the code block provided below:

private void c1TrueDBGrid1_UnboundColumnFetch(object sender, C1.Win.C1TrueDBGrid.UnboundColumnFetchEventArgs e)  
 {  
   if (e.Row == row)  
   {  
     e.Value = "";  
   }  
   else  
   {  
     if (!filter)  
      {  
         e.Value = (e.Row + 1).ToString();  
      }  
      else  
      {  
         if (!filterdone)  
          {  
            counter++;  
            for (int i = filindex; i < filtercol.Length; i++)  
            {  
              if (filtercol[ i ] == c1TrueDBGrid1.Columns[c1TrueDBGrid1.Col].FilterText || filtercol[ i ].StartsWith(c1TrueDBGrid1.Columns[c1TrueDBGrid1.Col].FilterText))  
              {  
                e.Value = rowindex[ i ];  
                filindex = i + 1;  
                filteredindexes[counter - 1] = rowindex[i];  
                break;  
              }  
            }  
            if (counter == c1TrueDBGrid1.RowCount)  
            {  
              counter = 0;  
              filterdone = true;  
            }  
         }  
         else  
         {  
           e.Value = filteredindexes[e.Row];  
         }  
       }  
     }  
   }  

Next step is to use the OwnerDrawCell event. This event is used to show either the row selector or the row number depending on whether the row is the active row or not respectively:

this.c1TrueDBGrid1.OwnerDrawCell += (ss, ee) =>  
{  
  if (ee.Row == row)  
   ee.Style.BackgroundImage = Image.FromFile(@"..\\..\\Images\\Rec_Sel.png");  
};  

Now this row indexing works effectively after addition or deletion of rows and column sorting . The only scenario that needs to be handled is Filtering so as to display the correct row numbers for the filtered rows. The same is managed handling the BeforeColEdit and AfterFilter event:

private void c1TrueDBGrid1_AfterFilter(object sender, C1.Win.C1TrueDBGrid.FilterEventArgs e)  
{  
  if (e.Condition != "")  
  {  
   filter = true;  
   filindex = 0;  
   filterdone = false;  
   filteredindexes = new string[c1TrueDBGrid1.RowCount];  
  }  
  else  
  {  
   filter = false;  
  }  
}  

private void c1TrueDBGrid1_BeforeColEdit(object sender, C1.Win.C1TrueDBGrid.BeforeColEditEventArgs e)  
{  
 if (c1TrueDBGrid1.FilterActive && c1TrueDBGrid1.Columns[e.ColIndex].FilterText == "")  
 {  
   filtercol = new string[c1TrueDBGrid1.RowCount];  
   rowindex = new string[c1TrueDBGrid1.RowCount];  
   for (int r = 0; r < c1TrueDBGrid1.RowCount; r++)  
   {  
     rowindex[r] = c1TrueDBGrid1[r, 0].ToString();  
     filtercol[r] = c1TrueDBGrid1[r,e.ColIndex].ToString();  
   }  
 }  
}  

At the end, once again the UnboundColumnFetch event populates the row numbers in the unbound column.

Hunter Haaf