Grid / Improve Performance
Improve Performance

Use Data Virtualization

To efficiently render large data sets, FlexGrid supports data vitualization in which data is fetched in pages as the user scrolls down. The grid knows the total number of rows but only loads and displays those that are visible to the user. For instance, you can use C1.DataCollection package to implement virtualizable data source. Create a class inherited from the C1VirtualDataCollection and implement GetPageAsync method which returns one page of data from data source you have assigned. The following GIF shows how FlexGrid appears in the virtual scrolling mode.

Data virtualization

public class VirtualModeCollectionView : C1VirtualDataCollection<Customer>
{
   public int TotalCount { get; set; } = 1_000;
   protected override async Task<Tuple<int, IReadOnlyList<Customer>>> GetPageAsync(int pageIndex, int startingIndex, int count, IReadOnlyList<SortDescription> sortDescriptions = null, FilterExpression filterExpression = null, CancellationToken cancellationToken = default(CancellationToken))
   {
      await Task.Delay(500, cancellationToken);//Simulates network traffic.
      return new Tuple<int, IReadOnlyList<Customer>>(TotalCount, Enumerable.Range(startingIndex, count).Select(i => new Customer(i)).ToList());
   }
}              

Use BeginUpdate and EndUpdate Methods

The BeginUpdate and EndUpdate methods are used to optimize the performance of the grid. Call BeginUpdate before making extensive changes, and call EndUpdate when done to suspend repainting. This reduces flicker and increases performance. This optimization is especially effective when adding large number of rows to the grid, because it needs to recalculate ranges and update scrollbars each time a row is added.

The code below shows how to add a large number of rows to the WinForms FlexGrid efficiently. Note how the EndUpdate method is called inside a 'finally' block to ensure repainting is properly restored.

void UpdateGrid(C1FlexGrid c1FlexGrid1)
{
  try
  {
    c1FlexGrid1.BeginUpdate(); // suspend painting to avoid flicker
    c1FlexGrid1.Rows.Count = 1;
    for (int i = 1; i < 10000; i++)
      c1FlexGrid1.AddItem("Row " + i.ToString());
  }
  finally
  {
    c1FlexGrid1.EndUpdate(); // always restore painting
  }
}  
                        

Keep AutoResize Property to False (default)

In case of bound grid, if AutoResize property is set to true, the control automatically resizes its columns to fit the widest entry every time new data is read from the data source. If the data source contains a large number of rows and columns, the automatic resizing may take a relatively long time. In such cases, you should consider setting AutoResize to false and setting the column widths directly in code.

Assign Styles Dynamically

FlexGrid allows you to create cell styles and assign them to rows, columns, and arbitrary cell ranges. You can use this feature to format the grid cells conditionally. Usually, you do this by using the SetCellStyle() method. However, in that case you have to update the style whenever the cell value changes. Also, if the grid is bound to a data source, styles are lost whenever data source is reset after operations such as sorting and filtering. A better alternative in these cases is to use the OwnerDraw feature and select styles dynamically based on the cell values. For example, the sample code shows how to display negative values in red color and values above 1,000 in green color in the WinForms FlexGrid.

private void Form1_Load(object sender, EventArgs e)
{
   // Fill a column with random values.
      c1FlexGrid1.Cols[1].DataType = typeof(int);
      Random rnd = new Random();
      for (int r = 1; r < c1FlexGrid1.Rows.Count; r++)
       {
          c1FlexGrid1[r, 1] = rnd.Next(-10000, 10000);
       }
 
   // Create style used to show negative values.
      c1FlexGrid1.Styles.Add("Red").ForeColor = Color.Red;
 
   // Enable OwnerDraw by setting the DrawMode property.
      c1FlexGrid1.DrawMode = C1.Win.C1FlexGrid.DrawModeEnum.OwnerDraw;
      c1FlexGrid1.OwnerDrawCell += new C1.Win.C1FlexGrid.OwnerDrawCellEventHandler(C1FlexGrid1_OwnerDrawCell);
}

private void C1FlexGrid1_OwnerDrawCell(object sender, OwnerDrawCellEventArgs e)
{
    if(!e.Measuring)
    {
        // Check that the row and column contain integer data.
        if (e.Row > 0 && c1FlexGrid1.Cols[e.Col].DataType == typeof(int))
        {
           // Apply the style "Red" 
           e.Style = c1FlexGrid1.Styles["Red"];
        }
    }
}       
                        

Avoid Modifying Styles in the OwnerDrawCell Event

Another way to improve performance is not to modify the CellStyle object passed as a parameter in the OwnerDrawCell event. Instead, assign a new value to the e.Style parameter. This is important because the CellStyle passed to the event handler is often used by other cells. For example, you could, unintentionally change a normal style of the WinForms FlexGrid, which would affect other similar cells as well in the grid.

// ** CORRECT APPROACH:
private void C1FlexGrid1_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
{
    // Select style to use when painting this cell:
    e.Style = MyStyleSelector(e.Row, e.Col);
}
                                                
// ** WRONG APPROACH:
private void C1FlexGrid1_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
{
    // Select style to use when painting this cell:
    // This is wrong because changing any CellStyle objects invalidates the
    // grid, which would cause this event handler to be called over and
    // over again.
    e.Style.Color = MyColorSelector(e.Row, e.Col);
}                               
                        

Show Ellipses in a Single Column

The Trimming property should be used to show ellipses in a single column of the grid. To determine how long strings are trimmed to fit the cell, the Trimming property can be set to either None, Character, Word, EllipsisCharacter, EllipsisWord, or EllipsisPath. For more information on trimming, see Display Trimmed Text.

The following code sets the Trimming property to show ellipses at the end of the second WinForms Flexgrid column, with the text trimmed to the nearest character:

c1FlexGrid1.Cols[1].StyleNew.Trimming =StringTrimming.EllipsisCharacter;

Show Multi-line Text in a Cell

When showing multiple lines of text in a cell, use the WordWrap and Height properties. The WordWrap property determines whether the grid should automatically break long strings that contain spaces and display them in multiple lines. Strings that contain hard line breaks (vbCrLf or "\n\r") are always displayed in multiple lines. Multiple line text can be displayed in both fixed and scrollable cells. For more information on word wrapping, see Wrap Text.

Refer to code below to see how a multi-line text should be effectively displayed in the WinForms FlexGrid.

// Set the WordWrap property.
c1FlexGrid1.Styles["Normal"].WordWrap = true;
 
// Set the row height.
c1FlexGrid1.Rows[1].Height = 2 * fg.Rows.DefaultSize;
 
// Add text to the cell.
c1FlexGrid1[1, 2] = "This is the first line. \r\n This is the second line.";                            

Retrieve Data Sorting When Bound to a Data Table

To maintain the way the grid is sorted when data is refreshed, you can use the default view's Sort property and a sort expression. The Sort property uses a string containing the column name followed by ASC(default) or DESC to sort the column in ascending or descending order respectively. Multiple columns can be sorted by specifying each column name separated by a comma. A sort expression can include names of grid columns or a calculation. Setting the sort expression at run time immediately reflects the changes in the data view.

Below code shows how to use the sort expression with Sort property in the WinForms FlexGrid.

// Sort the data by the UnitsInStock column then by the ProductID column.
   this.productsBindingSource.Sort = "UnitsInStock ASC, ProductID ASC";                         
                        

Specify Character Limit for Column

To set the maximum number of characters a user can enter for any given column, use the SetupEditor event. You must declare an external editor such as C1TextBox in the StartEdit event of the C1FlexGrid class. Then, in the SetupEditor event, you can set the maximum number of characters that are allowed in a column cell.

Use the code below to set the character limit for a WinForms FlexGrid column.

private void C1FlexGrid1_StartEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
{
    c1FlexGrid1.Editor = c1TextBox;
}
                                                        
private void C1FlexGrid1_SetupEditor(object sender, RowColEventArgs e)
{
 
   // Set the 3rd column to allow 20 characters and the rest only 10.
   if (e.Col == 2)
     c1TextBox.MaxLength = 20;
   else
     c1TextBox.MaxLength = 10;
}