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.
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();
}
}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 ClassSamples:
C#: Custom table
VB: Custom table