Transpose C1FlexGrid for Winforms

There may be occasions when users, using either one of the grids available with the ComponentOne Studio For Winforms - (C1TrueDbgrid, or C1Flexgrid), may need data to be available in transposed format. Now, C1TrueDbgrid already has provision for this (DataViewEnum.Inverted). C1Flexgrid does not support this transposed view by default. However, the flexible architecture of C1Flexgrid does help us implement this. To begin with, we need to transpose the DataSource for C1Flexgrid (we transpose it beforehand).


//return transposed datatable  
private DataTable TransposeTable(DataTable table)  
{  
    DataTable outputTable = new DataTable();  
    outputTable.Columns.Add(table.Columns[0].ColumnName.ToString());  
    foreach (DataRow inRow in table.Rows)  
    {  
        string newColName = inRow[0].ToString();  
        outputTable.Columns.Add(newColName);  
    }  
    for (int rCount = 0; rCount <= table.Columns.Count - 1; rCount++)  
    {  
        DataRow newRow = outputTable.NewRow();  
        newRow[0] = table.Columns[rCount].ColumnName.ToString();  
        for (int cCount = 0; cCount <= table.Rows.Count - 1; cCount++)  
        {  
            string colValue = table.Rows[cCount][rCount].ToString();  
            newRow[cCount + 1] = colValue;  
        }  
        outputTable.Rows.Add(newRow);  
    }  
    return outputTable;  
}  

Bind the grid with this transposed DataTable.



//set transposed datatable as grid's datasource  
this.c1FlexGrid1.DataSource = TransposeTable(this.nWindDataSet.Employees);  

Now, since C1Flexgrid is not creating a fixed row for column headers on its own; we need to create fixed row. This needs creation of a custom style, to be implemented on custom row/col headers. Nothing fancy, simply a new style based on C1Flexgrid's Frozen style, with its Border's style set to BorderStyleEnum.Raised. And of course, we still need a fixed row at the top. I used "InsertNode" to put it there (a Node is a Row after all).


private void UpdateRowColSettings()  
{  
  this.c1FlexGrid1.Cols.Fixed = 0;  
  this.c1FlexGrid1.Rows.Fixed = 0;  
  this.c1FlexGrid1.Rows.InsertNode(0, -1);  
  this.c1FlexGrid1.Cols.Frozen = 1;  
  this.c1FlexGrid1.Rows.Frozen = 1;  
  this.c1FlexGrid1.Rows[0].Style = this.c1FlexGrid1.Styles["Custom"];  
  this.c1FlexGrid1.Cols[0].Style = this.c1FlexGrid1.Styles["Custom"];  
  this.c1FlexGrid1.Cols[0].AllowEditing = false;  
  this.c1FlexGrid1.Rows[0].AllowEditing = false;  
  this.c1FlexGrid1.Cols[0].ImageAlign = C1.Win.C1FlexGrid.ImageAlignEnum.RightCenter;  
  this.c1FlexGrid1.AutoSizeCol(0);  
}  

Now, we have a C1Flexgrid with transposed dataview. This, custom view, however strips us of few default functionalities provided by the control. Most common of them, being the ability to sort by clicking on column headers. Since we don't have default column headers to click on we can't expect the sort to happen. With the current dataview, we need sort to happen when user clicks on row header instead. The easiest way I could figure out to make this happen, was to sort the DataView itself, when user clicks on RowHeader. This may easily be detected within MouseUp event and then set the sorted DataView as grid's DataSource again. This, I accept, may make the grid load slower if there's too many records in the database; however, calling C1Flexgrid's BeginUpdate() before this operation and EndUpdate() afterwards takes care of this. Standard sorting behavior demands appearance of sort glyphs too, in Row headers in our case. For them to appear, we may employ a Boolean flag that keeps track of the current row's SortDirection; and depending on this flag's value we may set appropriate SortGlyph in the row header using SetCellImage method. Images to be used as Glyphs were easy to come by:


asc_img = this.c1FlexGrid1.Glyphs[C1.Win.C1FlexGrid.GlyphEnum.Ascending];  
desc_image = this.c1FlexGrid1.Glyphs[C1.Win.C1FlexGrid.GlyphEnum.Descending];  

And, this is how we may implement aforementioned logic:


//Implement Sort at Row Header Click  
this.c1FlexGrid1.MouseUp += (s1, e1) =>  
{  
  var flex = s1 as C1.Win.C1FlexGrid.C1FlexGrid;  
  var hittest = flex.HitTest(e1.X, e1.Y);  

  int row = hittest.Row;  
  int col = hittest.Column;  

  if (col == 0 && row != 0)  
  {  
    flex.BeginUpdate();  

    string colname = flex[row, col].ToString();  
    string sort = this.nWindDataSet.Employees.DefaultView.Sort;  

    if (sort == "")  
    {  
      sort = colname + " ASC";  
      flag = true;  
    }  
    else  
    {  
      if (sort == colname + " ASC")  
      {  
        sort = colname + " DESC";  
        flag = false;  
      }  
      else  
      {  
        sort = colname + " ASC";  
        flag = true;  
      }  
     }  

     this.nWindDataSet.Employees.DefaultView.Sort = sort;  

     //reset grid's datasource and set Sorted DataView as grid's DataSource  
     flex.DataSource = TransposeTable(this.nWindDataSet.Employees.DefaultView.ToTable());  

     //Update Fixed Rows/Cols  
     UpdateRowColSettings();  

     //Update and Display SortGylphs  
     if (flag)  
      flex.SetCellImage(row, col, asc_img);  
     else  
      flex.SetCellImage(row, col, desc_image);  

     //Set current Row  
     flex.Row = row;  
     flex.EndUpdate();  
   }  
 };  

This is how a transposed C1Flexgrid looks like. I got the idea to transpose C1Flexgrid this from another user who simply wished to have a transposed view. This, like I said earlier, is a custom view and lacks few functionalities. For e.g. you can't compute Aggregate with this because the column whose index you use in SubTotals method, doesn't contain data of the actual column anymore. Certainly this, and others, may be implemented via code; and if you so wish, please feel free to add it here and share, so that other may benefit too :) Refer to the attached samples for complete implementation. Download CS Sample Download VB Sample

GrapeCity

GrapeCity Developer Tools
comments powered by Disqus