How to efficiently customize the child table or group by using a custom engine in WinForms GridGroupingControl?
Customize the child table or group
When customizing the GridChildTable or GridGroup by deriving the GridChildTable in the custom engine, the OnInitializeVisibleCounters method and the OnEnsureInitialized method are to be overridden along with the other overrides. Otherwise the GridChildTable calls into the GridChildTable extend methods and sometimes bypasses methods like IsChildVisible, that you have overridden.
In the OnInitializeVisibleCounters override, the Total Visible Elements count, the Total Vertical Scroll Distance of elements in pixels, and the Total Custom Count of the visible elements must be calculated and set to the CachedVisibleCount, CachedYamountCount, and CachedVisibleCustomCount respectively. And the OnEnsureInitialized override method must return False, that is, when changes are detected and the object is not updated, to ensure that the object is up to date.
C#
public class GroupingEngineFactory : GridEngineFactoryBase { // Add this line in your forms ctor: // GroupingEngineFactory provides a modified GridChildTable that adds an extra section. // GridEngineFactory.Factory = new GroupingEngineFactory(); public override GridEngine CreateEngine() { return new GroupingEngine(); } } public class GroupingEngine : GridEngine { public override RecordRow CreateRecordRow(RecordRowsPart parent) { return new GroupingRecordRow(parent); } public override CaptionRow CreateCaptionRow(CaptionSection parent) { return new GroupingCaptionRow (parent); } public override ColumnHeaderRow CreateColumnHeaderRow(ColumnHeaderSection parent) { return new GroupingColumnHeaderRow (parent); } } public class GroupingRecordRow : GridRecordRow, IGridRowHeight { int rowHeight = -1; /// Initializes a new object in the specifed record part. public GroupingRecordRow(RecordRowsPart parent) : base(parent) { } #region IGridRowHeight Members /// Determines if elements supports storing row heights public bool SupportsRowHeight() { return true; } public int RowHeight { get { return rowHeight; } set { if (rowHeight != value) { rowHeight = value; this.InvalidateCounterBottomUp(); } } } // Checks if row height was modified or if default setting should be used. public bool HasRowHeight { get { return rowHeight != -1; } } #endregion /// <summary> /// This is where the row height then gets integrated with the engine. /// YAmount Counter logic. /// </summary> public override double GetYAmountCount() { // Note: whenever the value that is returned by GetYAmountCount changes, make sure you call InvalidateCounterBottomUp so that the engine is aware of the change and counters are recalculated. See the RowHeight setter. return rowHeight != -1 ? rowHeight : base.GetYAmountCount(); } } public class GroupingCaptionRow : GridCaptionRow, IGridRowHeight { int rowHeight = -1; /// <summary> /// Initializes a new object in the specifed record part. /// </summary> /// <param name="parent">The parent element.</param> public GroupingCaptionRow(CaptionSection parent) : base(parent) { } #region IGridRowHeight Members /// <summary> /// Determines if elements supports storing row heights. /// </summary> /// <returns></returns> public bool SupportsRowHeight() { return true; } /// <summary> /// The row height. /// </summary> public int RowHeight { get { return rowHeight; } set { if (rowHeight != value) { rowHeight = value; this.InvalidateCounterBottomUp(); } } } /// <summary> /// Checks if row height was modified or if default setting should be used. /// </summary> public bool HasRowHeight { get { return rowHeight != -1; } } #endregion /// <summary> /// This is where the row height then gets integrated with the engine. /// YAmount Counter logic. /// </summary> /// <returns></returns> public override double GetYAmountCount() { // Note: whenever the value that is returned by GetYAmountCount changes, make sure you call InvalidateCounterBottomUp so that the engine is aware of the change and counters are recalculated. See the RowHeight setter. return rowHeight != -1 ? rowHeight : base.GetYAmountCount(); } bool IGridRowHeight.HasRowHeight { get { throw new NotImplementedException(); } } int IGridRowHeight.RowHeight { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } bool IGridRowHeight.SupportsRowHeight() { throw new NotImplementedException(); } } public class GroupingColumnHeaderRow : GridColumnHeaderRow, IGridRowHeight { int rowHeight = -1; /// <summary> /// Initializes a new object in the specifed record part. /// </summary> /// <param name="parent">The parent element.</param> public GroupingColumnHeaderRow(ColumnHeaderSection parent) : base(parent) { } #region IGridRowHeight Members /// <summary> /// Determines if elements supports storing row heights. /// </summary> /// <returns></returns> public bool SupportsRowHeight() { return true; } /// <summary> /// The row height. /// </summary> public int RowHeight { get { return rowHeight; } set { if (rowHeight != value) { rowHeight = value; this.InvalidateCounterBottomUp(); } } } /// <summary> /// Checks if row height was modified or if default setting should be used. /// </summary> public bool HasRowHeight { get { return rowHeight != -1; } } #endregion /// <summary> /// This is where the row height then gets integrated with the engine. /// YAmount Counter logic. /// </summary> /// <returns></returns> public override double GetYAmountCount() { // Note: whenever the value that is returned by GetYAmountCount changes make sure you call InvalidateCounterBottomUp so that the engine is aware of the change and counters are recalculated. See the RowHeight setter. return rowHeight != -1 ? rowHeight : base.GetYAmountCount(); } }
VB
Public Class GroupingEngineFactory Inherits GridEngineFactoryBase ' Add this line in your forms ctor: ' GroupingEngineFactory provides a modified GridChildTable that adds an extra section ' GridEngineFactory.Factory = new GroupingEngineFactory(); Public Overrides Function CreateEngine() As GridEngine Return New GroupingEngine() End Function End Class Public Class GroupingEngine Inherits GridEngine Public Overrides Function CreateRecordRow(ByVal parent As RecordRowsPart) As RecordRow Return New GroupingRecordRow(parent) End Function Public Overrides Function CreateCaptionRow(ByVal parent As CaptionSection) As CaptionRow Return New GroupingCaptionRow (parent) End Function Public Overrides Function CreateColumnHeaderRow(ByVal parent As ColumnHeaderSection) As ColumnHeaderRow Return New GroupingColumnHeaderRow (parent) End Function End Class Public Class GroupingRecordRow Inherits GridRecordRow Implements IGridRowHeight Private rowHeight_Renamed As Integer = -1 ''' Initializes a new object in the specifed record part. Public Sub New(ByVal parent As RecordRowsPart) MyBase.New(parent) End Sub #Region "IGridRowHeight Members" ''' Determines if elements supports storing row heights. Public Function SupportsRowHeight() As Boolean Return True End Function Public Property RowHeight() As Integer Get Return rowHeight_Renamed End Get Set(ByVal value As Integer) If rowHeight_Renamed <> value Then rowHeight_Renamed = value Me.InvalidateCounterBottomUp() End If End Set End Property ' Checks if row height was modified or if default setting should be used. Public ReadOnly Property HasRowHeight() As Boolean Get Return rowHeight_Renamed <> -1 End Get End Property #End Region ''' <summary> ''' This is where the row height then gets integrated with the engine. ''' YAmount Counter logic. ''' </summary> Public Overrides Function GetYAmountCount() As Double ' Note: whenever the value that is returned by GetYAmountCount changes make sure you call InvalidateCounterBottomUp so that the engine is aware of the change and counters are recalculated. See the RowHeight setter. Return If(rowHeight_Renamed <> -1, rowHeight_Renamed, MyBase.GetYAmountCount()) End Function End Class Public Class GroupingCaptionRow Inherits GridCaptionRow Implements IGridRowHeight Private rowHeight_Renamed As Integer = -1 ''' <summary> ''' Initializes a new object in the specifed record part. ''' </summary> ''' <param name="parent">The parent element.</param> Public Sub New(ByVal parent As CaptionSection) MyBase.New(parent) End Sub #Region "IGridRowHeight Members" ''' <summary> ''' Determines if elements supports storing row heights. ''' </summary> ''' <returns></returns> Public Function SupportsRowHeight() As Boolean Return True End Function ''' <summary> ''' The row height ''' </summary> Public Property RowHeight() As Integer Get Return rowHeight_Renamed End Get Set(ByVal value As Integer) If rowHeight_Renamed <> value Then rowHeight_Renamed = value Me.InvalidateCounterBottomUp() End If End Set End Property ''' <summary> ''' Checks if row height was modified or if default setting should be used. ''' </summary> Public ReadOnly Property HasRowHeight() As Boolean Get Return rowHeight_Renamed <> -1 End Get End Property #End Region ''' <summary> ''' This is where the row height then gets integrated with the engine. ''' YAmount Counter logic. ''' </summary> ''' <returns></returns> Public Overrides Function GetYAmountCount() As Double ' Note: whenever the value that is returned by GetYAmountCount changes make sure you call InvalidateCounterBottomUp so that the engine is aware of the change and counters are recalculated. See the RowHeight setter. Return If(rowHeight_Renamed <> -1, rowHeight_Renamed, MyBase.GetYAmountCount()) End Function Private ReadOnly Property IGridRowHeight_HasRowHeight() As Boolean Implements IGridRowHeight.HasRowHeight Get Throw New NotImplementedException() End Get End Property Private Property IGridRowHeight_RowHeight() As Integer Implements IGridRowHeight.RowHeight Get Throw New NotImplementedException() End Get Set(ByVal value As Integer) Throw New NotImplementedException() End Set End Property Private Function IGridRowHeight_SupportsRowHeight() As Boolean Implements IGridRowHeight.SupportsRowHeight Throw New NotImplementedException() End Function End Class Public Class GroupingColumnHeaderRow Inherits GridColumnHeaderRow Implements IGridRowHeight Private rowHeight_Renamed As Integer = -1 ''' <summary> ''' Initializes a new object in the specifed record part. ''' </summary> ''' <param name="parent">The parent element.</param> Public Sub New(ByVal parent As ColumnHeaderSection) MyBase.New(parent) End Sub #Region "IGridRowHeight Members" ''' <summary> ''' Determines if elements supports storing row heights. ''' </summary> ''' <returns></returns> Public Function SupportsRowHeight() As Boolean Return True End Function ''' <summary> ''' The row height ''' </summary> Public Property RowHeight() As Integer Get Return rowHeight_Renamed End Get Set(ByVal value As Integer) If rowHeight_Renamed <> value Then rowHeight_Renamed = value Me.InvalidateCounterBottomUp() End If End Set End Property ''' <summary> ''' Checks if row height was modified or if default setting should be used. ''' </summary> Public ReadOnly Property HasRowHeight() As Boolean Get Return rowHeight_Renamed <> -1 End Get End Property #End Region ''' <summary> ''' This is where the row height then gets integrated with the engine. ''' YAmount Counter logic. ''' </summary> ''' <returns></returns> Public Overrides Function GetYAmountCount() As Double ' Note: whenever the value that is returned by GetYAmountCount changes make sure you call InvalidateCounterBottomUp so that the engine is aware of the change and counters are recalculated. See the RowHeight setter. Return If(rowHeight_Renamed <> -1, rowHeight_Renamed, MyBase.GetYAmountCount()) End Function End Class
Samples:
C#: Custom table
VB: Custom table