Cell Types in Windows Forms GridGrouping (GridGroupingControl)

28 Apr 2021 / 21 minutes to read

GridGroupingControl allows the inclusion of some special controls in the grid cells. This attribute of a grid cell is referred to as its Cell Type. This section explains about the built in cell types and how to create a custom cell types in GridGroupingControl.
In grid each cell has been created by using GridCellModelBase and GridCellRendererBase class. GridCellModelBase defines the data or model part of a cell type. It holds all the data information of a cell. Rendering generally refers to the process of creating a visual representation on a user’s screen. GridCellRendererBase acts a base class for all the renderer part of the cell type.

NOTE

The GridGroupingControl supports all the basic cell types used in GridControl.

Setting cell type

The cell type of a cell can be specified by using the CellType property. There are two ways to assign the value for CellType property, by string format or by using the GridCellTypeName static class which contains all the built-in cell type names in it.

//Setting checkbox as the CellType for the column
this.gridGroupingControl1.TableDescriptor.Columns[2].Appearance.AnyRecordFieldCell.CellType = GridCellTypeName.CheckBox;

//Adding the Description for the checkbox column
this.gridGroupingControl1.TableDescriptor.Columns[2].Appearance.AnyRecordFieldCell.Description = "Included";
'Setting checkbox as the CellType for the column
Me.gridGroupingControl1.TableDescriptor.Columns(2).Appearance.AnyRecordFieldCell.CellType = GridCellTypeName.CheckBox

'Adding the Description for the checkbox column
Me.gridGroupingControl1.TableDescriptor.Columns(2).Appearance.AnyRecordFieldCell.Description = "Included"

CellTypes_img1

Enhanced cell types

GridGroupingControl supports more than 10 enhanced cell types. These enhanced cell types are listed in the CustomCellTypes enumerator which can be found in Syncfusion.GridHelperClasses.Windows library.

Registering helper cell types

Before setting any enhanced cell type to the particular cell, it is needed to be registered in the GridGroupingControl. This can be achieved by using the GridGroupingCellType static method of the RegisterCellModel class.

//Registering the custom cell type to the GridGroupingControl
RegisterCellModel.GridGroupingCellType(this.gridGroupingControl1, CustomCellTypes.PercentTextBox);
'Registering the custom cell type to the GridGroupingControl
RegisterCellModel.GridGroupingCellType(Me.gridGroupingControl1, CustomCellTypes.PercentTextBox)

CellTypes_img2

NOTE

The above code shows how to register a PercentTextBox custom cell type to a GridGroupingControl.

The following sample shows how to include the helper cell types to the grid cell,
<Installation_Location>\Syncfusion\EssentialStudio\<version>\Windows\Grid.Windows\Samples\Custom Cell Types

Creating a custom cell type

Apart from the built-in and the enhanced helper cell types, it is also possible to create a custom cell type in grid. The following steps are used to create the custom cell types in GridGroupingControl,

Creating cell model

The custom cell model need to be derived from the GridCellModelBase class. The main function of GridCellModelBase derived class is to serialize the user control. It can hold any persistent state independent data that your control uses.
Another major function of this class is to create cell renderer object for the custom cell type. In fact, the only required override in GridCellModelBase derived class is the CreateRenderer method. In that override, it is possible to create and return GridCellRendererBase derived object that would handle the user interactions in new custom cell type.
In general, it is unlikely to derive directly from the base class. Instead of that, override an existing GridGroupingControl derived class such as GridStaticCellModel. The following code example illustrates this.

//Defines custom Cell Model by inheriting GridStaticCellModel.
public class LinkLabelCellModel : GridStaticCellModel
{

    protected LinkLabelCellModel(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }

    public LinkLabelCellModel(GridModel grid)
        : base(grid)
    {
    }

    //Overrides CreateRenderer Method to create CellRenderer object.   

    public override GridCellRendererBase CreateRenderer(GridControlBase control)
    {
        return new LinkLabelCellRenderer(control, this);
    }
}
'Defines custom Cell Model by inheriting GridStaticCellModel.

Public Class LinkLabelCellModel
	Inherits GridStaticCellModel

	Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
		MyBase.New(info, context)
	End Sub

	Public Sub New(ByVal grid As GridModel)
		MyBase.New(grid)
	End Sub

	'Overrides CreateRenderer Method to create CellRenderer object.   

	Public Overrides Function CreateRenderer(ByVal control As GridControlBase) As GridCellRendererBase
		Return New LinkLabelCellRenderer(control, Me)
	End Function
End Class

Creating cell renderer

The custom renderer is need to be inherited from the GridCellRendererBase class. This base class handles drawing of the cell and user interaction aspects of the cell architecture.
This renderer class will take care of the handling of mouse and keyboard messages, also the UI related changes. It is necessary to override the required methods and properties and modify them as per your needs.
In general, it is unlikely to derive directly from the GridCellRendererBase class. Instead of that, override an existing GridGroupingControl derived class such as GridStaticCellModel, GridGenericControlCellModel etc.

public class LinkLabelCellRenderer : GridStaticCellRenderer
{
    private bool _isMouseDown;
    private bool _drawHotLink;
    private Color _hotColor;
    private Color _visitedColor;
    private string _EXEName;

    public LinkLabelCellRenderer(GridControlBase grid, GridCellModelBase cellModel)
        : base(grid, cellModel)
    {
        _isMouseDown = false;
        _drawHotLink = false;
        _hotColor = Color.Red;
        _visitedColor = Color.Purple;
        _EXEName = "iexplore.exe";
    }

    public Color VisitedLinkColor
    {
        get { return _visitedColor; }
        set { _visitedColor = value; }
    }

    public Color ActiveLinkColor
    {
        get { return _hotColor; }
        set { _hotColor = value; }
    }

    public string EXEName
    {
        get { return _EXEName; }
        set { _EXEName = value; }
    }

    protected virtual void LaunchBrowser(GridStyleInfo style)
    {
        try
        {
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            process.StartInfo.FileName = EXEName;
            process.StartInfo.Arguments = (string)style.Tag;
            process.Start();
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: " + ex.ToString());
        }
    }

    private void DrawLink(bool useHotColor, int rowIndex, int colIndex)
    {
        if (useHotColor)
            _drawHotLink = true;
        this.Grid.RefreshRange(GridRangeInfo.Cell(rowIndex, colIndex), GridRangeOptions.None);
        _drawHotLink = false;
    }

    protected override void OnMouseDown(int rowIndex, int colIndex, System.Windows.Forms.MouseEventArgs e)
    {
        base.OnMouseDown(rowIndex, colIndex, e);
        DrawLink(true, rowIndex, colIndex);
        _isMouseDown = true;
    }

    protected override void OnMouseUp(int rowIndex, int colIndex, System.Windows.Forms.MouseEventArgs e)
    {
        base.OnMouseUp(rowIndex, colIndex, e);
        int row, col;
        this.Grid.PointToRowCol(new Point(e.X, e.Y), out row, out col);
        if (row == rowIndex && col == colIndex)
        {
            GridStyleInfo style = this.Grid.Model[row, col];
            LaunchBrowser(style);
            style.TextColor = VisitedLinkColor;
        }
        DrawLink(false, rowIndex, colIndex);
        _isMouseDown = false;
    }

    protected override void OnCancelMode(int rowIndex, int colIndex)
    {
        base.OnCancelMode(rowIndex, colIndex);
        _isMouseDown = false;
        _drawHotLink = false;
    }

    protected override System.Windows.Forms.Cursor OnGetCursor(int rowIndex, int colIndex)
    {
        
        //If over cell, return HandPointerCursor otherwise NoCursor.
        Point pt = this.Grid.PointToClient(Cursor.Position);
        int row, col;
        this.Grid.PointToRowCol(pt, out row, out col);
        return (row == rowIndex && col == colIndex) ? Cursors.Hand : (this._isMouseDown) ? Cursors.No : base.OnGetCursor(rowIndex, colIndex);
    }

    protected override int OnHitTest(int rowIndex, int colIndex, MouseEventArgs e, IMouseController controller)
    {

        //Return a nonzero so the mouse messages will be forwarded to the cell render

        //But don't include the cell borders so D&D can be handled
        if (controller != null && controller.Name == "OleDataSource")
            
            // Other controllers have higher priority than me
            return 0;

        return 1;

    }

    protected override void OnDraw(System.Drawing.Graphics g, System.Drawing.Rectangle clientRectangle, int rowIndex, int colIndex, Syncfusion.Windows.Forms.Grid.GridStyleInfo style)
    {
        style.Font.Underline = true;

        if (_drawHotLink)
        {
            style.TextColor = ActiveLinkColor;
        }
        base.OnDraw(g, clientRectangle, rowIndex, colIndex, style);
   }

    protected override void OnMouseHoverEnter(int rowIndex, int colIndex)
    {
        base.OnMouseHoverEnter(rowIndex, colIndex);
        DrawLink(true, rowIndex, colIndex);
    }

    protected override void OnMouseHoverLeave(int rowIndex, int colIndex, System.EventArgs e)
    {
        base.OnMouseHoverLeave(rowIndex, colIndex, e);
        DrawLink(false, rowIndex, colIndex);
    }
}
Public Class LinkLabelCellRenderer
	Inherits GridStaticCellRenderer
	Private _isMouseDown As Boolean
	Private _drawHotLink As Boolean
	Private _hotColor As Color
	Private _visitedColor As Color
	Private _EXEName As String

	Public Sub New(ByVal grid As GridControlBase, ByVal cellModel As GridCellModelBase)
		MyBase.New(grid, cellModel)
		_isMouseDown = False
		_drawHotLink = False
		_hotColor = Color.Red
		_visitedColor = Color.Purple
		_EXEName = "iexplore.exe"
	End Sub

	Public Property VisitedLinkColor() As Color
		Get
			Return _visitedColor
		End Get
		Set(ByVal value As Color)
			_visitedColor = value
		End Set
	End Property

	Public Property ActiveLinkColor() As Color
		Get
			Return _hotColor
		End Get
		Set(ByVal value As Color)
			_hotColor = value
		End Set
	End Property

	Public Property EXEName() As String
		Get
			Return _EXEName
		End Get
		Set(ByVal value As String)
			_EXEName = value
		End Set
	End Property

	Protected Overridable Sub LaunchBrowser(ByVal style As GridStyleInfo)
		Try
			Dim process As New System.Diagnostics.Process()
			process.StartInfo.FileName = EXEName
			process.StartInfo.Arguments = CStr(style.Tag)
			process.Start()
		Catch ex As Exception
			MessageBox.Show("Error: " & ex.ToString())
		End Try
	End Sub

	Private Sub DrawLink(ByVal useHotColor As Boolean, ByVal rowIndex As Integer, ByVal colIndex As Integer)
		If useHotColor Then
			_drawHotLink = True
		End If
		Me.Grid.RefreshRange(GridRangeInfo.Cell(rowIndex, colIndex), GridRangeOptions.None)
		_drawHotLink = False
		End Sub

	Protected Overrides Sub OnMouseDown(ByVal rowIndex As Integer, ByVal colIndex As Integer, ByVal e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseDown(rowIndex, colIndex, e)
		DrawLink(True, rowIndex, colIndex)
		_isMouseDown = True
	End Sub

	Protected Overrides Sub OnMouseUp(ByVal rowIndex As Integer, ByVal colIndex As Integer, ByVal e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseUp(rowIndex, colIndex, e)
		Dim row, col As Integer
		Me.Grid.PointToRowCol(New Point(e.X, e.Y), row, col)
		If row = rowIndex AndAlso col = colIndex Then
			Dim style As GridStyleInfo = Me.Grid.Model(row, col)
			LaunchBrowser(style)
			style.TextColor = VisitedLinkColor
		End If
		DrawLink(False, rowIndex, colIndex)
		_isMouseDown = False
	End Sub

	Protected Overrides Sub OnCancelMode(ByVal rowIndex As Integer, ByVal colIndex As Integer)
		MyBase.OnCancelMode(rowIndex, colIndex)
		_isMouseDown = False
		_drawHotLink = False
	End Sub

	Protected Overrides Function OnGetCursor(ByVal rowIndex As Integer, ByVal colIndex As Integer) As System.Windows.Forms.Cursor
		'if over cell, return HandPointerCursor otherwise NoCursor.
		Dim pt As Point = Me.Grid.PointToClient(Cursor.Position)
		Dim row, col As Integer
		Me.Grid.PointToRowCol(pt, row, col)

		Return If((row = rowIndex AndAlso col = colIndex), Cursors.Hand, If((Me._isMouseDown), Cursors.No, MyBase.OnGetCursor(rowIndex, colIndex)))
	End Function

	Protected Overrides Function OnHitTest(ByVal rowIndex As Integer, ByVal colIndex As Integer, ByVal e As MouseEventArgs, ByVal controller As IMouseController) As Integer
		'return a nonzero so the mouse messages will be forwarded to the cell render
		'but don't include the cell borders so D&D can be handled
		If controller IsNot Nothing AndAlso controller.Name = "OleDataSource" Then
			' other controllers have higher priority than me
			Return 0
		End If
		Return 1
	End Function

	Protected Overrides Sub OnDraw(ByVal g As System.Drawing.Graphics, ByVal clientRectangle As System.Drawing.Rectangle, ByVal rowIndex As Integer, ByVal colIndex As Integer, ByVal style As Syncfusion.Windows.Forms.Grid.GridStyleInfo)
		style.Font.Underline = True

		If _drawHotLink Then
			style.TextColor = ActiveLinkColor
		End If
		MyBase.OnDraw(g, clientRectangle, rowIndex, colIndex, style)
	End Sub

	Protected Overrides Sub OnMouseHoverEnter(ByVal rowIndex As Integer, ByVal colIndex As Integer)
		MyBase.OnMouseHoverEnter(rowIndex, colIndex)
		DrawLink(True, rowIndex, colIndex)
	End Sub

	Protected Overrides Sub OnMouseHoverLeave(ByVal rowIndex As Integer, ByVal colIndex As Integer, ByVal e As System.EventArgs)
		MyBase.OnMouseHoverLeave(rowIndex, colIndex, e)
		DrawLink(False, rowIndex, colIndex)
	End Sub
End Class

Registering cell model

After creating the Cell Model and Cell Renderer for the custom cell type it is necessary to register that custom cell type to the GridGroupingControl.

//Register the custom cell model to the GridGroupingControl
this.gridGroupingControl1.TableModel.CellModels.Add("LinkLabelCell", new LinkLabelCellModel(this.gridGroupingControl1.TableModel));
'Register the custom cell model to the GridGroupingControl
Me.gridGroupingControl1.TableModel.CellModels.Add("LinkLabelCell", New LinkLabelCellModel(Me.gridGroupingControl1.TableModel))

Assigning cell type

Assign the registered cell type to a GridGroupingControl like a normal cell type. The custom cell type LinkLabelCell acts as a hyperlink. The link for the LinkLabelCell will be assigned in the Tag property of that cell. This cell displays the ordinary text, but on clicking it will relocate to the link given in the Tag.

//Setting Custom cell types as the CellType for the column
this.gridGroupingControl1.TableDescriptor.Columns[2].Appearance.AnyRecordFieldCell.CellType = "LinkLabelCell";
'Setting Custom cell types as the CellType for the column
Me.gridGroupingControl1.TableDescriptor.Columns(2).Appearance.AnyRecordFieldCell.CellType = "LinkLabelCell"

CellTypes_img3