FlexGrid for WinForms | ComponentOne
Grid / Improve Performance
In This Topic
    Improve Performance
    In This Topic

    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());
       }
    }              
    
    Public Class VirtualModeCollectionView
        Inherits C1VirtualDataCollection(Of Customer)
    
        Public Property TotalCount As Integer = 1_000
    
        Protected Overrides Async Function GetPageAsync(ByVal pageIndex As Integer, ByVal startingIndex As Integer, ByVal count As Integer, ByVal Optional sortDescriptions As IReadOnlyList(Of SortDescription) = Nothing, ByVal Optional filterExpression As FilterExpression = Nothing, ByVal Optional cancellationToken As CancellationToken = DirectCast(Nothing, CancellationToken)) As Task(Of Tuple(Of Integer, IReadOnlyList(Of Customer)))
            Await Task.Delay(500, cancellationToken) 'Simulates network traffic.
            Return New Tuple(Of Integer, IReadOnlyList(Of Customer))(TotalCount, Enumerable.Range(CInt(startingIndex), CInt(count)).[Select](Function(i) New Customer(i)).ToList())
        End Function
    End Class 
    

    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
      }
    }  
                            
    
    Private Sub UpdateGrid(ByVal c1FlexGrid1 As C1FlexGrid)
        Try
            c1FlexGrid1.BeginUpdate() ' suspend painting to avoid flicker
            c1FlexGrid1.Rows.Count = 1
    
            For i As Integer = 1 To 10000 - 1
                c1FlexGrid1.AddItem("Row " & i.ToString())
            Next
    
        Finally
            c1FlexGrid1.EndUpdate() ' always restore painting
        End Try
    End Sub
                            
    

    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"];
            }
        }
    }       
                            
    
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            ' Fill a column with random values.
            c1FlexGrid1.Cols(1).DataType = GetType(Integer)
            Dim rnd As Random = New Random()
    
            For r As Integer = 1 To c1FlexGrid1.Rows.Count - 1
                c1FlexGrid1(r, 1) = rnd.[Next](-10000, 10000)
            Next
    
    
            ' 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(AddressOf C1FlexGrid1_OwnerDrawCell)
        End Sub
    
        Private Sub C1FlexGrid1_OwnerDrawCell(ByVal sender As Object, ByVal e As OwnerDrawCellEventArgs)
            If Not e.Measuring Then
    
                ' Check that the row and column contain integer data.
                If e.Row > 0 AndAlso c1FlexGrid1.Cols(e.Col).DataType Is GetType(Integer) Then
                    ' Apply the style "Red" 
                    e.Style = c1FlexGrid1.Styles("Red")
                End If
            End If
        End Sub     
    

    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);
    }                               
                            
    
    ' ** CORRECT APPROACH:
    Private Sub C1FlexGrid1_OwnerDrawCellMethod(ByVal sender As Object, ByVal e As C1.Win.C1FlexGrid.OwnerDrawCellEventArgs)
    ' Select style to use when painting this cell:
    e.Style = MyStyleSelector(e.Row, e.Col)
    End Sub
    
    
    ' ** WRONG APPROACH:
    Private Sub C1FlexGrid1_OwnerDrawCell(ByVal sender As Object, ByVal e As C1.Win.C1FlexGrid.OwnerDrawCellEventArgs)
    ' 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)
    End Sub         
                            
    

    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;
    
    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.";                            
    
        ' 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. " & vbCrLf & " 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";                         
                            
    
    ' Sort the data by the UnitsInStock column then by the ProductID column.
    Me.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;
    }
                                    
                            
    
        Private Sub C1FlexGrid1_StartEdit(ByVal sender As Object, ByVal e As C1.Win.C1FlexGrid.RowColEventArgs)
            c1FlexGrid1.Editor = c1TextBox
        End Sub
    
        Private Sub C1FlexGrid1_SetupEditor(ByVal sender As Object, ByVal e As RowColEventArgs)
    
            ' Set the 3rd column to allow 20 characters and the rest only 10.
            If e.Col = 2 Then
                c1TextBox.MaxLength = 20
            Else
                c1TextBox.MaxLength = 10
            End If
        End Sub