From f3dbf18e1a88997a1b76220c67e71ad0f8d50f34 Mon Sep 17 00:00:00 2001 From: Sreemon Premkumar M Date: Tue, 19 Aug 2025 17:20:02 +0530 Subject: [PATCH 1/3] ES-975464 - Resolve the ReadMe file length issue in this sample repository --- README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be0ee7b..4f64d84 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,21 @@ -# How to create custom column in winforms datagrid? -This repositories contains the samples to create custom column in winforms datagrid +# How to create custom column in winforms datagrid + +This repositories contains the samples to create custom column in [WinForms DataGrid](https://www.syncfusion.com/winforms-ui-controls/datagrid). + +You can create a new column by deriving [GridColumn](https://help.syncfusion.com/cr/windowsforms/Syncfusion.WinForms.DataGrid.GridColumn.html) and create new a cell renderer by overriding the predefined renderer in `SfDataGrid`. The following steps describe how to create a sparkline column as a custom column. + +### Creating custom column + +You can create a custom column by overriding a new class from the `GridColumn` class. + +### Creating renderer + +After creating a custom column, you need to create renderer for the custom column. You can create custom renderer by deriving the [GridCellRendererBase](https://help.syncfusion.com/cr/windowsforms/Syncfusion.Windows.Forms.Grid.GridCellRendererBase.html) class. + +### Adding the custom renderer to CellRenderers collection + +By using the following code, you can add the previous created custom renderer to the [SfDataGrid.CellRenderers](https://help.syncfusion.com/cr/windowsforms/Syncfusion.Windows.Forms.Grid.GridCellRendererCollection.html) collection. + +### Loading custom column + +By using the following code, you can define the custom column in SfDataGrid. \ No newline at end of file From b0b1451362390ba862e2071847db3e71e636eca7 Mon Sep 17 00:00:00 2001 From: SreemonPremkumarMuthukrishnan Date: Wed, 5 Nov 2025 01:08:18 +0530 Subject: [PATCH 2/3] ES-975464 - Addressed the concerns --- README.md | 411 +++++++++++++++++++++++++++++++++++++++++++- SparklineColumn.png | Bin 0 -> 62359 bytes 2 files changed, 406 insertions(+), 5 deletions(-) create mode 100644 SparklineColumn.png diff --git a/README.md b/README.md index 4f64d84..612959c 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,422 @@ -# How to create custom column in winforms datagrid +# How to Create Custom Column in WinForms DataGrid? -This repositories contains the samples to create custom column in [WinForms DataGrid](https://www.syncfusion.com/winforms-ui-controls/datagrid). +This repositories contains the samples to create custom column in [WinForms DataGrid](https://www.syncfusion.com/winforms-ui-controls/datagrid) (SfDataGrid). -You can create a new column by deriving [GridColumn](https://help.syncfusion.com/cr/windowsforms/Syncfusion.WinForms.DataGrid.GridColumn.html) and create new a cell renderer by overriding the predefined renderer in `SfDataGrid`. The following steps describe how to create a sparkline column as a custom column. +You can create a new column by deriving [GridColumn](https://help.syncfusion.com/cr/windowsforms/Syncfusion.WinForms.DataGrid.GridColumn.html) and create new a cell renderer by overriding the predefined renderer in DataGrid. The following steps describe how to create a sparkline column as a custom column. ### Creating custom column -You can create a custom column by overriding a new class from the `GridColumn` class. +You can create a custom column by overriding a new class from the **GridColumn** class. + +#### C# +``` csharp +public class GridSparklineColumn : GridColumn +{ + /// + /// Initializes a new instance of the class. + /// + public GridSparklineColumn() + { + SetCellType("Sparkline"); + this.SparklineType = SparkLineType.Line; + } + + /// + /// Gets or sets the type of the sparkline control. + /// + public SparkLineType SparklineType { get; set; } +} +``` +#### VB +``` vb +Public Class GridSparklineColumn + Inherits GridColumn + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + SetCellType("Sparkline") + Me.SparklineType = SparkLineType.Line + End Sub + + ''' + ''' Gets or sets the type of the sparkline control. + ''' + Public Property SparklineType() As SparkLineType +End Class +``` ### Creating renderer After creating a custom column, you need to create renderer for the custom column. You can create custom renderer by deriving the [GridCellRendererBase](https://help.syncfusion.com/cr/windowsforms/Syncfusion.Windows.Forms.Grid.GridCellRendererBase.html) class. +#### C# +``` csharp +/// +/// Represents a class that used for drawing the spark line cell. +/// +public class GridSparklineCellRenderer : GridCellRendererBase +{ +/// +/// Initializes a new instance of the class. +/// +/// The sparkline. +/// The DataGrid. +public GridSparklineCellRenderer(Syncfusion.Windows.Forms.Chart.SparkLine sparkline, SfDataGrid dataGrid) +{ + Sparkline = sparkline; + DataGrid = dataGrid; + IsEditable = false; +} + +/// +/// Gets or sets to specify the datagrid. +/// +protected SfDataGrid DataGrid { get; set; } + +/// +/// Gets the sparkline control used to draw the sparkline. +/// +protected SparkLine Sparkline { get; set; } + +/// +///Renders the line type sparkline. +/// +///The instance containing the event data. +///The Sparkline. +public void DrawSparkline(Graphics graphics, Syncfusion.Windows.Forms.Chart.SparkLine sparkline) +{ + SparkLineSource sparkLineSource = new SparkLineSource(); + int areaMarginX = 3; + int areaMarginY = 3; + double firstPointX = 0, firstPointY = 0, secondPointX = 0, secondPointY = 0; + double areaWidth = sparkline.ControlWidth - areaMarginX * areaMarginX; + double areaHeight = sparkline.ControlHeight - areaMarginY * areaMarginY; + + var sourceList = (List)sparkLineSource.GetSourceList(sparkline.Source, sparkline); + + if (sourceList.Count == 0) + return; + + double lineInterval = areaWidth / (sourceList.Count); + double lineRange = sparkline.HighPoint - sparkline.LowPoint; + + for (int i = 0; i < sourceList.Count; i++) + { + double Value = Convert.ToDouble(sourceList[i]) - sparkline.LowPoint; + + secondPointX = firstPointX; + secondPointY = firstPointY; + + firstPointX = this.Sparkline.Location.X + (lineInterval * i + (lineInterval / 2)); + firstPointY = this.Sparkline.Location.Y + (areaHeight - (areaHeight * (Value / lineRange))); + + if (i > 0) + graphics.DrawLine(new Pen(sparkline.LineStyle.LineColor, 1), (float)(areaMarginX + firstPointX), (float)(areaMarginY + firstPointY), (float)(areaMarginX + secondPointX), (float)(areaMarginY + secondPointY)); + + if (sparkline.Markers.ShowMarker) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.MarkerColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + if (Convert.ToDouble(sourceList[i]) == sparkline.StartPoint && sparkline.Markers.ShowStartPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.StartPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + if (Convert.ToDouble(sourceList[i]) == sparkline.EndPoint && sparkline.Markers.ShowEndPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.EndPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + + if (sparkline.GetNegativePoint() != null) + { + int count = sparkline.GetNegativePoint().GetUpperBound(0); + for (int k = 0; k <= count; k++) + { + if (Convert.ToDouble(sourceList[i]) == (double)sparkline.GetNegativePoint().GetValue(k) && sparkline.Markers.ShowNegativePoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.NegativePointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + } + } + + if (Convert.ToDouble(sourceList[i]) == sparkline.HighPoint && sparkline.Markers.ShowHighPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.HighPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + if (Convert.ToDouble(sourceList[i]) == sparkline.LowPoint && sparkline.Markers.ShowLowPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.LowPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + } +} + +/// +/// Override to draw the spark line of the cell. +/// +/// The that used to draw the spark line. +/// The cell rectangle. +/// The cell value. +/// The CellStyleInfo of the cell. +/// The DataColumnBase of the cell. +/// The row and column index of the cell. +protected override void OnRender(Graphics graphics, Rectangle cellRect, string cellValue, CellStyleInfo style, DataColumnBase column, RowColumnIndex rowColumnIndex) +{ + using (SolidBrush brush = new SolidBrush(style.BackColor)) + graphics.FillRectangle(brush, cellRect); + + var sparklineColumn = column.GridColumn as GridSparklineColumn; + this.Sparkline = new Syncfusion.Windows.Forms.Chart.SparkLine(); + var record = this.DataGrid.GetRecordAtRowIndex(rowColumnIndex.RowIndex); + + this.Sparkline.Source = GetSparklineSource(column.GridColumn.MappingName, record); + this.Sparkline.Type = sparklineColumn.SparklineType; + this.Sparkline.Markers.ShowEndPoint = true; + this.Sparkline.Markers.ShowHighPoint = true; + this.Sparkline.Markers.ShowLowPoint = true; + this.Sparkline.Markers.ShowMarker = true; + this.Sparkline.Markers.ShowNegativePoint = true; + this.Sparkline.Markers.ShowStartPoint = true; + this.Sparkline.Size = cellRect.Size; + this.Sparkline.Location = cellRect.Location; + + var smoothingMode = graphics.SmoothingMode; + var clipBounds = graphics.VisibleClipBounds; + graphics.SetClip(cellRect); + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + if (this.Sparkline.Type == SparkLineType.Line) + DrawSparkline(graphics, Sparkline); + else if (this.Sparkline.Type == SparkLineType.Column) + DrawSparkColumn(graphics, Sparkline); + else + DrawSparkWinLossColumn(graphics, Sparkline); + + graphics.SmoothingMode = smoothingMode; + graphics.SetClip(clipBounds); +} + +/// +/// Occurs when a key is pressed while the cell has focus. +/// +/// The DataColumnBase of the cell. +/// The row and column index of the cell. +/// The that contains the event data. +protected override void OnKeyDown(DataColumnBase dataColumn, RowColumnIndex rowColumnIndex, KeyEventArgs e) +{ + var selectionController = this.DataGrid.SelectionController as CustomSelectionController; + switch (e.KeyCode) + { + case Keys.Space: + case Keys.Down: + case Keys.Up: + case Keys.Left: + case Keys.Right: + case Keys.Enter: + case Keys.PageDown: + case Keys.PageUp: + case Keys.Tab: + case Keys.Home: + case Keys.End: + selectionController.HandleKeyOperations(e); + break; + } + + base.OnKeyDown(dataColumn, rowColumnIndex, e); +} + +/// +/// Gets data to the sparkline column. +/// +/// The mapping name of the column. +/// Data of the SparkLine. +/// returns collection. +private double[] GetSparklineSource(string mappingName, object record) +{ + var salesCollection = record as System.Data.DataRowView; + var item = salesCollection.Row.ItemArray[5]; + return item as double[]; +} +``` +#### VB +``` vb +''' +''' Represents a class used for drawing the sparkline cell. +''' +Public Class GridSparklineCellRenderer + Inherits GridCellRendererBase +''' +''' Initializes a new instance of the class. +''' +''' The sparkline. +''' The DataGrid. +Public Sub New(ByVal sparkline As Syncfusion.Windows.Forms.Chart.SparkLine, ByVal dataGrid As SfDataGrid) + Me.Sparkline = sparkline + Me.DataGrid = dataGrid + IsEditable = False +End Sub + +''' +''' Gets or sets to specify the datagrid. +''' +Protected Property DataGrid() As SfDataGrid + +''' +''' Gets the sparkline control used to draw the sparkline. +''' +Protected Property Sparkline() As SparkLine + +''' +'''Renders the line type sparkline. +''' +'''The instance containing the event data. +'''The Sparkline. +Public Sub DrawSparkline(ByVal graphics As Graphics, ByVal sparkline As Syncfusion.Windows.Forms.Chart.SparkLine) + Dim sparkLineSource As New SparkLineSource() + Dim areaMarginX As Integer = 3 + Dim areaMarginY As Integer = 3 + Dim firstPointX As Double = 0, firstPointY As Double = 0, secondPointX As Double = 0, secondPointY As Double = 0 + Dim areaWidth As Double = sparkline.ControlWidth - areaMarginX * areaMarginX + Dim areaHeight As Double = sparkline.ControlHeight - areaMarginY * areaMarginY + + Dim sourceList = CType(sparkLineSource.GetSourceList(sparkline.Source, sparkline), List(Of Object)) + + If sourceList.Count = 0 Then + Return + End If + + Dim lineInterval As Double = areaWidth / (sourceList.Count) + Dim lineRange As Double = sparkline.HighPoint - sparkline.LowPoint + + For i As Integer = 0 To sourceList.Count - 1 + Dim Value As Double = Convert.ToDouble(sourceList(i)) - sparkline.LowPoint + + secondPointX = firstPointX + secondPointY = firstPointY + + firstPointX = Me.Sparkline.Location.X + (lineInterval * i + (lineInterval / 2)) + firstPointY = Me.Sparkline.Location.Y + (areaHeight - (areaHeight * (Value / lineRange))) + + If i > 0 Then + graphics.DrawLine(New Pen(sparkline.LineStyle.LineColor, 1), CSng(areaMarginX + firstPointX), CSng(areaMarginY + firstPointY), CSng(areaMarginX + secondPointX), CSng(areaMarginY + secondPointY)) + End If + + If sparkline.Markers.ShowMarker Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.MarkerColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + If Convert.ToDouble(sourceList(i)) = sparkline.StartPoint AndAlso sparkline.Markers.ShowStartPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.StartPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + If Convert.ToDouble(sourceList(i)) = sparkline.EndPoint AndAlso sparkline.Markers.ShowEndPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.EndPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + + If sparkline.GetNegativePoint() IsNot Nothing Then + Dim count As Integer = sparkline.GetNegativePoint().GetUpperBound(0) + For k As Integer = 0 To count + If Convert.ToDouble(sourceList(i)) = CDbl(sparkline.GetNegativePoint().GetValue(k)) AndAlso sparkline.Markers.ShowNegativePoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.NegativePointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + Next k + End If + + If Convert.ToDouble(sourceList(i)) = sparkline.HighPoint AndAlso sparkline.Markers.ShowHighPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.HighPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + If Convert.ToDouble(sourceList(i)) = sparkline.LowPoint AndAlso sparkline.Markers.ShowLowPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.LowPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + Next i +End Sub + +''' +''' Overrides to draw the sparkline of the cell. +''' +''' The that used to draw the spark line. +''' The cell rectangle. +''' The cell value. +''' The CellStyleInfo of the cell. +''' The DataColumnBase of the cell. +''' The row and column index of the cell. +Protected Overrides Sub OnRender(ByVal graphics As Graphics, ByVal cellRect As Rectangle, ByVal cellValue As String, ByVal style As CellStyleInfo, ByVal column As DataColumnBase, ByVal rowColumnIndex As RowColumnIndex) + Using brush As New SolidBrush(style.BackColor) + graphics.FillRectangle(brush, cellRect) + End Using + + Dim sparklineColumn = TryCast(column.GridColumn, GridSparklineColumn) + Me.Sparkline = New Syncfusion.Windows.Forms.Chart.SparkLine() + Dim record = Me.DataGrid.GetRecordAtRowIndex(rowColumnIndex.RowIndex) + + Me.Sparkline.Source = GetSparklineSource(column.GridColumn.MappingName, record) + Me.Sparkline.Type = sparklineColumn.SparklineType + Me.Sparkline.Markers.ShowEndPoint = True + Me.Sparkline.Markers.ShowHighPoint = True + Me.Sparkline.Markers.ShowLowPoint = True + Me.Sparkline.Markers.ShowMarker = True + Me.Sparkline.Markers.ShowNegativePoint = True + Me.Sparkline.Markers.ShowStartPoint = True + Me.Sparkline.Size = cellRect.Size + Me.Sparkline.Location = cellRect.Location + + Dim smoothingMode = graphics.SmoothingMode + Dim clipBounds = graphics.VisibleClipBounds + graphics.SetClip(cellRect) + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality + If Me.Sparkline.Type = SparkLineType.Line Then + DrawSparkline(graphics, Sparkline) + ElseIf Me.Sparkline.Type = SparkLineType.Column Then + DrawSparkColumn(graphics, Sparkline) + Else + DrawSparkWinLossColumn(graphics, Sparkline) + End If + + graphics.SmoothingMode = smoothingMode + graphics.SetClip(clipBounds) +End Sub + +''' +''' Occurs when the key is pressed while the cell has focus. +''' +''' The DataColumnBase of the cell. +''' The row and column index of the cell. +''' The that contains the event data. +Protected Overrides Sub OnKeyDown(ByVal dataColumn As DataColumnBase, ByVal rowColumnIndex As RowColumnIndex, ByVal e As KeyEventArgs) + Dim selectionController = TryCast(Me.DataGrid.SelectionController, CustomSelectionController) + Select Case e.KeyCode + Case Keys.Space, Keys.Down, Keys.Up, Keys.Left, Keys.Right, Keys.Enter, Keys.PageDown, Keys.PageUp, Keys.Tab, Keys.Home, Keys.End + selectionController.HandleKeyOperations(e) + End Select + + MyBase.OnKeyDown(dataColumn, rowColumnIndex, e) +End Sub + +''' +''' Gets data to the sparkline column. +''' +''' The mapping name of the column. +''' Data of the SparkLine. +''' returns collection. +Private Function GetSparklineSource(ByVal mappingName As String, ByVal record As Object) As Double() + Dim salesCollection = TryCast(record, System.Data.DataRowView) + Dim item = salesCollection.Row.ItemArray(5) + Return TryCast(item, Double()) +End Function +``` + ### Adding the custom renderer to CellRenderers collection By using the following code, you can add the previous created custom renderer to the [SfDataGrid.CellRenderers](https://help.syncfusion.com/cr/windowsforms/Syncfusion.Windows.Forms.Grid.GridCellRendererCollection.html) collection. +#### C# +``` csharp +this.sfDataGrid1.CellRenderers.Add("Sparkline", new GridSparklineCellRenderer(new Syncfusion.Windows.Forms.Chart.SparkLine(), this.sfDataGrid1)); +``` + +#### VB +``` vb +Me.sfDataGrid1.CellRenderers.Add("Sparkline", New GridSparklineCellRenderer(New Syncfusion.Windows.Forms.Chart.SparkLine(), Me.sfDataGrid1)) +``` + ### Loading custom column -By using the following code, you can define the custom column in SfDataGrid. \ No newline at end of file +By using the following code, you can define the custom column in DataGrid. + +#### C# +``` csharp +this.sfDataGrid1.Columns.Add(new GridSparklineColumn() { MappingName = "Sparkline", HeaderText = "Analysis Report", Width = 150, AllowFiltering = false }); +``` + +#### VB +``` vb +Me.sfDataGrid1.Columns.Add(New GridSparklineColumn() With {.MappingName = "Sparkline", .HeaderText = "Analysis Report", .Width = 150, .AllowFiltering = False}) +``` + +![DataGrid with Sparkline column](SparklineColumn.png) + +Here, a rating column has been created as a custom column. A sample for this is available in this repository. \ No newline at end of file diff --git a/SparklineColumn.png b/SparklineColumn.png new file mode 100644 index 0000000000000000000000000000000000000000..ed6472aba7b05a282da10b40445722bcf4763b8a GIT binary patch literal 62359 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

%U3APS?CfKq2c19i)s8jta2 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 JC21V|zW_n97AXJ# literal 0 HcmV?d00001 From 7bc058e6d600c9a14d96ce3323b67cf4ab86cf03 Mon Sep 17 00:00:00 2001 From: SreemonPremkumarM Date: Wed, 5 Nov 2025 01:10:52 +0530 Subject: [PATCH 3/3] Update README.md --- README.md | 641 +++++++++++++++++++++++++++--------------------------- 1 file changed, 321 insertions(+), 320 deletions(-) diff --git a/README.md b/README.md index 612959c..66844f1 100644 --- a/README.md +++ b/README.md @@ -57,171 +57,172 @@ After creating a custom column, you need to create renderer for the custom colum /// public class GridSparklineCellRenderer : GridCellRendererBase { -///

-/// Initializes a new instance of the class. -/// -/// The sparkline. -/// The DataGrid. -public GridSparklineCellRenderer(Syncfusion.Windows.Forms.Chart.SparkLine sparkline, SfDataGrid dataGrid) -{ - Sparkline = sparkline; - DataGrid = dataGrid; - IsEditable = false; -} - -/// -/// Gets or sets to specify the datagrid. -/// -protected SfDataGrid DataGrid { get; set; } - -/// -/// Gets the sparkline control used to draw the sparkline. -/// -protected SparkLine Sparkline { get; set; } - -/// -///Renders the line type sparkline. -/// -///The instance containing the event data. -///The Sparkline. -public void DrawSparkline(Graphics graphics, Syncfusion.Windows.Forms.Chart.SparkLine sparkline) -{ - SparkLineSource sparkLineSource = new SparkLineSource(); - int areaMarginX = 3; - int areaMarginY = 3; - double firstPointX = 0, firstPointY = 0, secondPointX = 0, secondPointY = 0; - double areaWidth = sparkline.ControlWidth - areaMarginX * areaMarginX; - double areaHeight = sparkline.ControlHeight - areaMarginY * areaMarginY; - - var sourceList = (List)sparkLineSource.GetSourceList(sparkline.Source, sparkline); - - if (sourceList.Count == 0) - return; - - double lineInterval = areaWidth / (sourceList.Count); - double lineRange = sparkline.HighPoint - sparkline.LowPoint; - - for (int i = 0; i < sourceList.Count; i++) - { - double Value = Convert.ToDouble(sourceList[i]) - sparkline.LowPoint; - - secondPointX = firstPointX; - secondPointY = firstPointY; - - firstPointX = this.Sparkline.Location.X + (lineInterval * i + (lineInterval / 2)); - firstPointY = this.Sparkline.Location.Y + (areaHeight - (areaHeight * (Value / lineRange))); - - if (i > 0) - graphics.DrawLine(new Pen(sparkline.LineStyle.LineColor, 1), (float)(areaMarginX + firstPointX), (float)(areaMarginY + firstPointY), (float)(areaMarginX + secondPointX), (float)(areaMarginY + secondPointY)); - - if (sparkline.Markers.ShowMarker) - graphics.FillEllipse(new SolidBrush(sparkline.Markers.MarkerColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); - if (Convert.ToDouble(sourceList[i]) == sparkline.StartPoint && sparkline.Markers.ShowStartPoint) - graphics.FillEllipse(new SolidBrush(sparkline.Markers.StartPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); - if (Convert.ToDouble(sourceList[i]) == sparkline.EndPoint && sparkline.Markers.ShowEndPoint) - graphics.FillEllipse(new SolidBrush(sparkline.Markers.EndPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); - - if (sparkline.GetNegativePoint() != null) - { - int count = sparkline.GetNegativePoint().GetUpperBound(0); - for (int k = 0; k <= count; k++) - { - if (Convert.ToDouble(sourceList[i]) == (double)sparkline.GetNegativePoint().GetValue(k) && sparkline.Markers.ShowNegativePoint) - graphics.FillEllipse(new SolidBrush(sparkline.Markers.NegativePointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); - } - } - - if (Convert.ToDouble(sourceList[i]) == sparkline.HighPoint && sparkline.Markers.ShowHighPoint) - graphics.FillEllipse(new SolidBrush(sparkline.Markers.HighPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); - if (Convert.ToDouble(sourceList[i]) == sparkline.LowPoint && sparkline.Markers.ShowLowPoint) - graphics.FillEllipse(new SolidBrush(sparkline.Markers.LowPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); - } -} - -/// -/// Override to draw the spark line of the cell. -/// -/// The that used to draw the spark line. -/// The cell rectangle. -/// The cell value. -/// The CellStyleInfo of the cell. -/// The DataColumnBase of the cell. -/// The row and column index of the cell. -protected override void OnRender(Graphics graphics, Rectangle cellRect, string cellValue, CellStyleInfo style, DataColumnBase column, RowColumnIndex rowColumnIndex) -{ - using (SolidBrush brush = new SolidBrush(style.BackColor)) - graphics.FillRectangle(brush, cellRect); - - var sparklineColumn = column.GridColumn as GridSparklineColumn; - this.Sparkline = new Syncfusion.Windows.Forms.Chart.SparkLine(); - var record = this.DataGrid.GetRecordAtRowIndex(rowColumnIndex.RowIndex); - - this.Sparkline.Source = GetSparklineSource(column.GridColumn.MappingName, record); - this.Sparkline.Type = sparklineColumn.SparklineType; - this.Sparkline.Markers.ShowEndPoint = true; - this.Sparkline.Markers.ShowHighPoint = true; - this.Sparkline.Markers.ShowLowPoint = true; - this.Sparkline.Markers.ShowMarker = true; - this.Sparkline.Markers.ShowNegativePoint = true; - this.Sparkline.Markers.ShowStartPoint = true; - this.Sparkline.Size = cellRect.Size; - this.Sparkline.Location = cellRect.Location; - - var smoothingMode = graphics.SmoothingMode; - var clipBounds = graphics.VisibleClipBounds; - graphics.SetClip(cellRect); - graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; - if (this.Sparkline.Type == SparkLineType.Line) - DrawSparkline(graphics, Sparkline); - else if (this.Sparkline.Type == SparkLineType.Column) - DrawSparkColumn(graphics, Sparkline); - else - DrawSparkWinLossColumn(graphics, Sparkline); - - graphics.SmoothingMode = smoothingMode; - graphics.SetClip(clipBounds); -} - -/// -/// Occurs when a key is pressed while the cell has focus. -/// -/// The DataColumnBase of the cell. -/// The row and column index of the cell. -/// The that contains the event data. -protected override void OnKeyDown(DataColumnBase dataColumn, RowColumnIndex rowColumnIndex, KeyEventArgs e) -{ - var selectionController = this.DataGrid.SelectionController as CustomSelectionController; - switch (e.KeyCode) - { - case Keys.Space: - case Keys.Down: - case Keys.Up: - case Keys.Left: - case Keys.Right: - case Keys.Enter: - case Keys.PageDown: - case Keys.PageUp: - case Keys.Tab: - case Keys.Home: - case Keys.End: - selectionController.HandleKeyOperations(e); - break; - } - - base.OnKeyDown(dataColumn, rowColumnIndex, e); -} - -/// -/// Gets data to the sparkline column. -/// -/// The mapping name of the column. -/// Data of the SparkLine. -/// returns collection. -private double[] GetSparklineSource(string mappingName, object record) -{ - var salesCollection = record as System.Data.DataRowView; - var item = salesCollection.Row.ItemArray[5]; - return item as double[]; + /// + /// Initializes a new instance of the class. + /// + /// The sparkline. + /// The DataGrid. + public GridSparklineCellRenderer(Syncfusion.Windows.Forms.Chart.SparkLine sparkline, SfDataGrid dataGrid) + { + Sparkline = sparkline; + DataGrid = dataGrid; + IsEditable = false; + } + + /// + /// Gets or sets to specify the datagrid. + /// + protected SfDataGrid DataGrid { get; set; } + + /// + /// Gets the sparkline control used to draw the sparkline. + /// + protected SparkLine Sparkline { get; set; } + + /// + ///Renders the line type sparkline. + /// + ///The instance containing the event data. + ///The Sparkline. + public void DrawSparkline(Graphics graphics, Syncfusion.Windows.Forms.Chart.SparkLine sparkline) + { + SparkLineSource sparkLineSource = new SparkLineSource(); + int areaMarginX = 3; + int areaMarginY = 3; + double firstPointX = 0, firstPointY = 0, secondPointX = 0, secondPointY = 0; + double areaWidth = sparkline.ControlWidth - areaMarginX * areaMarginX; + double areaHeight = sparkline.ControlHeight - areaMarginY * areaMarginY; + + var sourceList = (List)sparkLineSource.GetSourceList(sparkline.Source, sparkline); + + if (sourceList.Count == 0) + return; + + double lineInterval = areaWidth / (sourceList.Count); + double lineRange = sparkline.HighPoint - sparkline.LowPoint; + + for (int i = 0; i < sourceList.Count; i++) + { + double Value = Convert.ToDouble(sourceList[i]) - sparkline.LowPoint; + + secondPointX = firstPointX; + secondPointY = firstPointY; + + firstPointX = this.Sparkline.Location.X + (lineInterval * i + (lineInterval / 2)); + firstPointY = this.Sparkline.Location.Y + (areaHeight - (areaHeight * (Value / lineRange))); + + if (i > 0) + graphics.DrawLine(new Pen(sparkline.LineStyle.LineColor, 1), (float)(areaMarginX + firstPointX), (float)(areaMarginY + firstPointY), (float)(areaMarginX + secondPointX), (float)(areaMarginY + secondPointY)); + + if (sparkline.Markers.ShowMarker) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.MarkerColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + if (Convert.ToDouble(sourceList[i]) == sparkline.StartPoint && sparkline.Markers.ShowStartPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.StartPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + if (Convert.ToDouble(sourceList[i]) == sparkline.EndPoint && sparkline.Markers.ShowEndPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.EndPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + + if (sparkline.GetNegativePoint() != null) + { + int count = sparkline.GetNegativePoint().GetUpperBound(0); + for (int k = 0; k <= count; k++) + { + if (Convert.ToDouble(sourceList[i]) == (double)sparkline.GetNegativePoint().GetValue(k) && sparkline.Markers.ShowNegativePoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.NegativePointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + } + } + + if (Convert.ToDouble(sourceList[i]) == sparkline.HighPoint && sparkline.Markers.ShowHighPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.HighPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + if (Convert.ToDouble(sourceList[i]) == sparkline.LowPoint && sparkline.Markers.ShowLowPoint) + graphics.FillEllipse(new SolidBrush(sparkline.Markers.LowPointColor.BackColor), (float)(areaMarginX + firstPointX - 2), (float)(areaMarginY + firstPointY - 2), 5, 5); + } + } + + /// + /// Override to draw the spark line of the cell. + /// + /// The that used to draw the spark line. + /// The cell rectangle. + /// The cell value. + /// The CellStyleInfo of the cell. + /// The DataColumnBase of the cell. + /// The row and column index of the cell. + protected override void OnRender(Graphics graphics, Rectangle cellRect, string cellValue, CellStyleInfo style, DataColumnBase column, RowColumnIndex rowColumnIndex) + { + using (SolidBrush brush = new SolidBrush(style.BackColor)) + graphics.FillRectangle(brush, cellRect); + + var sparklineColumn = column.GridColumn as GridSparklineColumn; + this.Sparkline = new Syncfusion.Windows.Forms.Chart.SparkLine(); + var record = this.DataGrid.GetRecordAtRowIndex(rowColumnIndex.RowIndex); + + this.Sparkline.Source = GetSparklineSource(column.GridColumn.MappingName, record); + this.Sparkline.Type = sparklineColumn.SparklineType; + this.Sparkline.Markers.ShowEndPoint = true; + this.Sparkline.Markers.ShowHighPoint = true; + this.Sparkline.Markers.ShowLowPoint = true; + this.Sparkline.Markers.ShowMarker = true; + this.Sparkline.Markers.ShowNegativePoint = true; + this.Sparkline.Markers.ShowStartPoint = true; + this.Sparkline.Size = cellRect.Size; + this.Sparkline.Location = cellRect.Location; + + var smoothingMode = graphics.SmoothingMode; + var clipBounds = graphics.VisibleClipBounds; + graphics.SetClip(cellRect); + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + if (this.Sparkline.Type == SparkLineType.Line) + DrawSparkline(graphics, Sparkline); + else if (this.Sparkline.Type == SparkLineType.Column) + DrawSparkColumn(graphics, Sparkline); + else + DrawSparkWinLossColumn(graphics, Sparkline); + + graphics.SmoothingMode = smoothingMode; + graphics.SetClip(clipBounds); + } + + /// + /// Occurs when a key is pressed while the cell has focus. + /// + /// The DataColumnBase of the cell. + /// The row and column index of the cell. + /// The that contains the event data. + protected override void OnKeyDown(DataColumnBase dataColumn, RowColumnIndex rowColumnIndex, KeyEventArgs e) + { + var selectionController = this.DataGrid.SelectionController as CustomSelectionController; + switch (e.KeyCode) + { + case Keys.Space: + case Keys.Down: + case Keys.Up: + case Keys.Left: + case Keys.Right: + case Keys.Enter: + case Keys.PageDown: + case Keys.PageUp: + case Keys.Tab: + case Keys.Home: + case Keys.End: + selectionController.HandleKeyOperations(e); + break; + } + + base.OnKeyDown(dataColumn, rowColumnIndex, e); + } + + /// + /// Gets data to the sparkline column. + /// + /// The mapping name of the column. + /// Data of the SparkLine. + /// returns collection. + private double[] GetSparklineSource(string mappingName, object record) + { + var salesCollection = record as System.Data.DataRowView; + var item = salesCollection.Row.ItemArray[5]; + return item as double[]; + } } ``` #### VB @@ -231,162 +232,162 @@ private double[] GetSparklineSource(string mappingName, object record) ''' Public Class GridSparklineCellRenderer Inherits GridCellRendererBase -''' -''' Initializes a new instance of the class. -''' -''' The sparkline. -''' The DataGrid. -Public Sub New(ByVal sparkline As Syncfusion.Windows.Forms.Chart.SparkLine, ByVal dataGrid As SfDataGrid) - Me.Sparkline = sparkline - Me.DataGrid = dataGrid - IsEditable = False -End Sub - -''' -''' Gets or sets to specify the datagrid. -''' -Protected Property DataGrid() As SfDataGrid - -''' -''' Gets the sparkline control used to draw the sparkline. -''' -Protected Property Sparkline() As SparkLine - -''' -'''Renders the line type sparkline. -''' -'''The instance containing the event data. -'''The Sparkline. -Public Sub DrawSparkline(ByVal graphics As Graphics, ByVal sparkline As Syncfusion.Windows.Forms.Chart.SparkLine) - Dim sparkLineSource As New SparkLineSource() - Dim areaMarginX As Integer = 3 - Dim areaMarginY As Integer = 3 - Dim firstPointX As Double = 0, firstPointY As Double = 0, secondPointX As Double = 0, secondPointY As Double = 0 - Dim areaWidth As Double = sparkline.ControlWidth - areaMarginX * areaMarginX - Dim areaHeight As Double = sparkline.ControlHeight - areaMarginY * areaMarginY - - Dim sourceList = CType(sparkLineSource.GetSourceList(sparkline.Source, sparkline), List(Of Object)) - - If sourceList.Count = 0 Then - Return - End If - - Dim lineInterval As Double = areaWidth / (sourceList.Count) - Dim lineRange As Double = sparkline.HighPoint - sparkline.LowPoint - - For i As Integer = 0 To sourceList.Count - 1 - Dim Value As Double = Convert.ToDouble(sourceList(i)) - sparkline.LowPoint - - secondPointX = firstPointX - secondPointY = firstPointY - - firstPointX = Me.Sparkline.Location.X + (lineInterval * i + (lineInterval / 2)) - firstPointY = Me.Sparkline.Location.Y + (areaHeight - (areaHeight * (Value / lineRange))) - - If i > 0 Then - graphics.DrawLine(New Pen(sparkline.LineStyle.LineColor, 1), CSng(areaMarginX + firstPointX), CSng(areaMarginY + firstPointY), CSng(areaMarginX + secondPointX), CSng(areaMarginY + secondPointY)) - End If - - If sparkline.Markers.ShowMarker Then - graphics.FillEllipse(New SolidBrush(sparkline.Markers.MarkerColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) - End If - If Convert.ToDouble(sourceList(i)) = sparkline.StartPoint AndAlso sparkline.Markers.ShowStartPoint Then - graphics.FillEllipse(New SolidBrush(sparkline.Markers.StartPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) - End If - If Convert.ToDouble(sourceList(i)) = sparkline.EndPoint AndAlso sparkline.Markers.ShowEndPoint Then - graphics.FillEllipse(New SolidBrush(sparkline.Markers.EndPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) - End If - - If sparkline.GetNegativePoint() IsNot Nothing Then - Dim count As Integer = sparkline.GetNegativePoint().GetUpperBound(0) - For k As Integer = 0 To count - If Convert.ToDouble(sourceList(i)) = CDbl(sparkline.GetNegativePoint().GetValue(k)) AndAlso sparkline.Markers.ShowNegativePoint Then - graphics.FillEllipse(New SolidBrush(sparkline.Markers.NegativePointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) - End If - Next k - End If - - If Convert.ToDouble(sourceList(i)) = sparkline.HighPoint AndAlso sparkline.Markers.ShowHighPoint Then - graphics.FillEllipse(New SolidBrush(sparkline.Markers.HighPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + ''' + ''' Initializes a new instance of the class. + ''' + ''' The sparkline. + ''' The DataGrid. + Public Sub New(ByVal sparkline As Syncfusion.Windows.Forms.Chart.SparkLine, ByVal dataGrid As SfDataGrid) + Me.Sparkline = sparkline + Me.DataGrid = dataGrid + IsEditable = False + End Sub + + ''' + ''' Gets or sets to specify the datagrid. + ''' + Protected Property DataGrid() As SfDataGrid + + ''' + ''' Gets the sparkline control used to draw the sparkline. + ''' + Protected Property Sparkline() As SparkLine + + ''' + '''Renders the line type sparkline. + ''' + '''The instance containing the event data. + '''The Sparkline. + Public Sub DrawSparkline(ByVal graphics As Graphics, ByVal sparkline As Syncfusion.Windows.Forms.Chart.SparkLine) + Dim sparkLineSource As New SparkLineSource() + Dim areaMarginX As Integer = 3 + Dim areaMarginY As Integer = 3 + Dim firstPointX As Double = 0, firstPointY As Double = 0, secondPointX As Double = 0, secondPointY As Double = 0 + Dim areaWidth As Double = sparkline.ControlWidth - areaMarginX * areaMarginX + Dim areaHeight As Double = sparkline.ControlHeight - areaMarginY * areaMarginY + + Dim sourceList = CType(sparkLineSource.GetSourceList(sparkline.Source, sparkline), List(Of Object)) + + If sourceList.Count = 0 Then + Return End If - If Convert.ToDouble(sourceList(i)) = sparkline.LowPoint AndAlso sparkline.Markers.ShowLowPoint Then - graphics.FillEllipse(New SolidBrush(sparkline.Markers.LowPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + + Dim lineInterval As Double = areaWidth / (sourceList.Count) + Dim lineRange As Double = sparkline.HighPoint - sparkline.LowPoint + + For i As Integer = 0 To sourceList.Count - 1 + Dim Value As Double = Convert.ToDouble(sourceList(i)) - sparkline.LowPoint + + secondPointX = firstPointX + secondPointY = firstPointY + + firstPointX = Me.Sparkline.Location.X + (lineInterval * i + (lineInterval / 2)) + firstPointY = Me.Sparkline.Location.Y + (areaHeight - (areaHeight * (Value / lineRange))) + + If i > 0 Then + graphics.DrawLine(New Pen(sparkline.LineStyle.LineColor, 1), CSng(areaMarginX + firstPointX), CSng(areaMarginY + firstPointY), CSng(areaMarginX + secondPointX), CSng(areaMarginY + secondPointY)) + End If + + If sparkline.Markers.ShowMarker Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.MarkerColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + If Convert.ToDouble(sourceList(i)) = sparkline.StartPoint AndAlso sparkline.Markers.ShowStartPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.StartPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + If Convert.ToDouble(sourceList(i)) = sparkline.EndPoint AndAlso sparkline.Markers.ShowEndPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.EndPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + + If sparkline.GetNegativePoint() IsNot Nothing Then + Dim count As Integer = sparkline.GetNegativePoint().GetUpperBound(0) + For k As Integer = 0 To count + If Convert.ToDouble(sourceList(i)) = CDbl(sparkline.GetNegativePoint().GetValue(k)) AndAlso sparkline.Markers.ShowNegativePoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.NegativePointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + Next k + End If + + If Convert.ToDouble(sourceList(i)) = sparkline.HighPoint AndAlso sparkline.Markers.ShowHighPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.HighPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + If Convert.ToDouble(sourceList(i)) = sparkline.LowPoint AndAlso sparkline.Markers.ShowLowPoint Then + graphics.FillEllipse(New SolidBrush(sparkline.Markers.LowPointColor.BackColor), CSng(areaMarginX + firstPointX - 2), CSng(areaMarginY + firstPointY - 2), 5, 5) + End If + Next i + End Sub + + ''' + ''' Overrides to draw the sparkline of the cell. + ''' + ''' The that used to draw the spark line. + ''' The cell rectangle. + ''' The cell value. + ''' The CellStyleInfo of the cell. + ''' The DataColumnBase of the cell. + ''' The row and column index of the cell. + Protected Overrides Sub OnRender(ByVal graphics As Graphics, ByVal cellRect As Rectangle, ByVal cellValue As String, ByVal style As CellStyleInfo, ByVal column As DataColumnBase, ByVal rowColumnIndex As RowColumnIndex) + Using brush As New SolidBrush(style.BackColor) + graphics.FillRectangle(brush, cellRect) + End Using + + Dim sparklineColumn = TryCast(column.GridColumn, GridSparklineColumn) + Me.Sparkline = New Syncfusion.Windows.Forms.Chart.SparkLine() + Dim record = Me.DataGrid.GetRecordAtRowIndex(rowColumnIndex.RowIndex) + + Me.Sparkline.Source = GetSparklineSource(column.GridColumn.MappingName, record) + Me.Sparkline.Type = sparklineColumn.SparklineType + Me.Sparkline.Markers.ShowEndPoint = True + Me.Sparkline.Markers.ShowHighPoint = True + Me.Sparkline.Markers.ShowLowPoint = True + Me.Sparkline.Markers.ShowMarker = True + Me.Sparkline.Markers.ShowNegativePoint = True + Me.Sparkline.Markers.ShowStartPoint = True + Me.Sparkline.Size = cellRect.Size + Me.Sparkline.Location = cellRect.Location + + Dim smoothingMode = graphics.SmoothingMode + Dim clipBounds = graphics.VisibleClipBounds + graphics.SetClip(cellRect) + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality + If Me.Sparkline.Type = SparkLineType.Line Then + DrawSparkline(graphics, Sparkline) + ElseIf Me.Sparkline.Type = SparkLineType.Column Then + DrawSparkColumn(graphics, Sparkline) + Else + DrawSparkWinLossColumn(graphics, Sparkline) End If - Next i -End Sub - -''' -''' Overrides to draw the sparkline of the cell. -''' -''' The that used to draw the spark line. -''' The cell rectangle. -''' The cell value. -''' The CellStyleInfo of the cell. -''' The DataColumnBase of the cell. -''' The row and column index of the cell. -Protected Overrides Sub OnRender(ByVal graphics As Graphics, ByVal cellRect As Rectangle, ByVal cellValue As String, ByVal style As CellStyleInfo, ByVal column As DataColumnBase, ByVal rowColumnIndex As RowColumnIndex) - Using brush As New SolidBrush(style.BackColor) - graphics.FillRectangle(brush, cellRect) - End Using - - Dim sparklineColumn = TryCast(column.GridColumn, GridSparklineColumn) - Me.Sparkline = New Syncfusion.Windows.Forms.Chart.SparkLine() - Dim record = Me.DataGrid.GetRecordAtRowIndex(rowColumnIndex.RowIndex) - - Me.Sparkline.Source = GetSparklineSource(column.GridColumn.MappingName, record) - Me.Sparkline.Type = sparklineColumn.SparklineType - Me.Sparkline.Markers.ShowEndPoint = True - Me.Sparkline.Markers.ShowHighPoint = True - Me.Sparkline.Markers.ShowLowPoint = True - Me.Sparkline.Markers.ShowMarker = True - Me.Sparkline.Markers.ShowNegativePoint = True - Me.Sparkline.Markers.ShowStartPoint = True - Me.Sparkline.Size = cellRect.Size - Me.Sparkline.Location = cellRect.Location - - Dim smoothingMode = graphics.SmoothingMode - Dim clipBounds = graphics.VisibleClipBounds - graphics.SetClip(cellRect) - graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality - If Me.Sparkline.Type = SparkLineType.Line Then - DrawSparkline(graphics, Sparkline) - ElseIf Me.Sparkline.Type = SparkLineType.Column Then - DrawSparkColumn(graphics, Sparkline) - Else - DrawSparkWinLossColumn(graphics, Sparkline) - End If - - graphics.SmoothingMode = smoothingMode - graphics.SetClip(clipBounds) -End Sub - -''' -''' Occurs when the key is pressed while the cell has focus. -''' -''' The DataColumnBase of the cell. -''' The row and column index of the cell. -''' The that contains the event data. -Protected Overrides Sub OnKeyDown(ByVal dataColumn As DataColumnBase, ByVal rowColumnIndex As RowColumnIndex, ByVal e As KeyEventArgs) - Dim selectionController = TryCast(Me.DataGrid.SelectionController, CustomSelectionController) - Select Case e.KeyCode - Case Keys.Space, Keys.Down, Keys.Up, Keys.Left, Keys.Right, Keys.Enter, Keys.PageDown, Keys.PageUp, Keys.Tab, Keys.Home, Keys.End - selectionController.HandleKeyOperations(e) - End Select - - MyBase.OnKeyDown(dataColumn, rowColumnIndex, e) -End Sub - -''' -''' Gets data to the sparkline column. -''' -''' The mapping name of the column. -''' Data of the SparkLine. -''' returns collection. -Private Function GetSparklineSource(ByVal mappingName As String, ByVal record As Object) As Double() - Dim salesCollection = TryCast(record, System.Data.DataRowView) - Dim item = salesCollection.Row.ItemArray(5) - Return TryCast(item, Double()) -End Function + + graphics.SmoothingMode = smoothingMode + graphics.SetClip(clipBounds) + End Sub + + ''' + ''' Occurs when the key is pressed while the cell has focus. + ''' + ''' The DataColumnBase of the cell. + ''' The row and column index of the cell. + ''' The that contains the event data. + Protected Overrides Sub OnKeyDown(ByVal dataColumn As DataColumnBase, ByVal rowColumnIndex As RowColumnIndex, ByVal e As KeyEventArgs) + Dim selectionController = TryCast(Me.DataGrid.SelectionController, CustomSelectionController) + Select Case e.KeyCode + Case Keys.Space, Keys.Down, Keys.Up, Keys.Left, Keys.Right, Keys.Enter, Keys.PageDown, Keys.PageUp, Keys.Tab, Keys.Home, Keys.End + selectionController.HandleKeyOperations(e) + End Select + + MyBase.OnKeyDown(dataColumn, rowColumnIndex, e) + End Sub + + ''' + ''' Gets data to the sparkline column. + ''' + ''' The mapping name of the column. + ''' Data of the SparkLine. + ''' returns collection. + Private Function GetSparklineSource(ByVal mappingName As String, ByVal record As Object) As Double() + Dim salesCollection = TryCast(record, System.Data.DataRowView) + Dim item = salesCollection.Row.ItemArray(5) + Return TryCast(item, Double()) + End Function ``` ### Adding the custom renderer to CellRenderers collection @@ -419,4 +420,4 @@ Me.sfDataGrid1.Columns.Add(New GridSparklineColumn() With {.MappingName = "Spark ![DataGrid with Sparkline column](SparklineColumn.png) -Here, a rating column has been created as a custom column. A sample for this is available in this repository. \ No newline at end of file +Here, a rating column has been created as a custom column. A sample for this is available in this repository.