From 112d6335903a6238e7a5fb97fa92c7a499b992c5 Mon Sep 17 00:00:00 2001 From: Loretta Date: Thu, 18 Dec 2025 10:03:32 +0100 Subject: [PATCH] Add extensible InfoPanel system with custom templates Introduce a flexible InfoPanel architecture for grid components, allowing per-grid customization via a new InfoPanelType parameter. Add MgInfoPanelTemplateBase for code-based InfoPanel templates with overridable header, content, and footer sections. Support custom templates in MgGridInfoPanel via new RenderFragment parameters. Add MgGridDataColumn for InfoPanel-specific column settings. Demonstrate usage with a custom InfoPanel for ShippingDocument grid. Maintains backward compatibility with default InfoPanel behavior. --- .../Components/Grids/MgGridBase.cs | 13 ++- .../Components/Grids/MgGridDataColumn.cs | 28 +++++++ .../Components/Grids/MgGridInfoPanel.razor | 84 ++++++++++++------- .../Components/Grids/MgGridInfoPanel.razor.cs | 15 ++++ .../Grids/MgGridToolbarTemplate.razor | 48 +++++------ .../Grids/MgInfoPanelTemplateBase.cs | 47 +++++++++++ 6 files changed, 177 insertions(+), 58 deletions(-) create mode 100644 AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs create mode 100644 AyCode.Blazor.Components/Components/Grids/MgInfoPanelTemplateBase.cs diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs b/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs index 8c95de8..2a03c8c 100644 --- a/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs +++ b/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs @@ -99,6 +99,12 @@ public abstract class MgGridBase + /// Custom InfoPanel component type. Must inherit from MgInfoPanelTemplateBase. + /// If not set, the default MgGridInfoPanel is used. + /// + [Parameter] public Type? InfoPanelType { get; set; } + private object _focusedDataItem; /// @@ -222,10 +228,13 @@ public abstract class MgGridBase { var infoPanelSeq = 0; - infoPanelBuilder.OpenComponent(infoPanelSeq++); + + // Use custom InfoPanel type if provided, otherwise use default MgGridInfoPanel + var panelType = InfoPanelType ?? typeof(MgGridInfoPanel); + infoPanelBuilder.OpenComponent(infoPanelSeq++, panelType); infoPanelBuilder.AddComponentReferenceCapture(infoPanelSeq++, instance => { - InfoPanelInstance = (MgGridInfoPanel)instance; + InfoPanelInstance = instance as IInfoPanelBase; }); infoPanelBuilder.CloseComponent(); })); diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs b/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs new file mode 100644 index 0000000..5f0541f --- /dev/null +++ b/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs @@ -0,0 +1,28 @@ +using DevExpress.Blazor; +using Microsoft.AspNetCore.Components; + +namespace AyCode.Blazor.Components.Components.Grids; + +/// +/// Extended DxGridDataColumn with additional parameters for InfoPanel support. +/// +public class MgGridDataColumn : DxGridDataColumn +{ + /// + /// Whether this column should be visible in the InfoPanel. Default is true. + /// + [Parameter] + public bool ShowInInfoPanel { get; set; } = true; + + /// + /// Custom display format for InfoPanel (overrides DisplayFormat if set). + /// + [Parameter] + public string? InfoPanelDisplayFormat { get; set; } + + /// + /// Column order in InfoPanel (lower = earlier). Default is int.MaxValue. + /// + [Parameter] + public int InfoPanelOrder { get; set; } = int.MaxValue; +} diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor b/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor index b46480c..88d4f0b 100644 --- a/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor +++ b/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor @@ -4,16 +4,23 @@
@* Header *@ -
- @((_currentGrid as IMgGridBase)?.Caption ?? "") -
- - @* Toolbar *@ - @if (_currentGrid != null) + @if (HeaderTemplate != null) { -
- + @HeaderTemplate + } + else + { +
+ @((_currentGrid as IMgGridBase)?.Caption ?? "")
+ + @* Toolbar *@ + @if (_currentGrid != null) + { +
+ +
+ } } @* Content *@ @@ -23,33 +30,40 @@ var dataItem = GetActiveDataItem()!; var dataItemType = dataItem.GetType(); -
- @foreach (var column in GetVisibleColumns()) - { - var displayText = GetDisplayTextFromGrid(column); - var value = GetCellValue(column); - var settingsType = GetEditSettingsType(column); - var isReadOnly = !_isEditMode || column.ReadOnly; + @if (ColumnsTemplate != null) + { + @ColumnsTemplate + } + else + { +
+ @foreach (var column in GetVisibleColumns()) + { + var displayText = GetDisplayTextFromGrid(column); + var value = GetCellValue(column); + var settingsType = GetEditSettingsType(column); + var isReadOnly = !_isEditMode || column.ReadOnly; -
-
- -
- @if (_isEditMode && !column.ReadOnly) - { - @RenderEditableCell(column, dataItem, dataItemType, value, displayText, settingsType) - } - else - { - @RenderCellContent(column, value, displayText, settingsType) - } +
+
+ +
+ @if (_isEditMode && !column.ReadOnly) + { + @RenderEditableCell(column, dataItem, dataItemType, value, displayText, settingsType) + } + else + { + @RenderCellContent(column, value, displayText, settingsType) + } +
-
- } -
+ } +
+ } } else { @@ -58,6 +72,12 @@
}
+ + @* Footer *@ + @if (FooterTemplate != null) + { + @FooterTemplate + }
@code { diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor.cs b/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor.cs index 400666b..e8e7a4f 100644 --- a/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor.cs +++ b/AyCode.Blazor.Components/Components/Grids/MgGridInfoPanel.razor.cs @@ -26,6 +26,21 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan ///
[Parameter] public bool ShowReadOnlyFieldsInEditMode { get; set; } = false; + /// + /// Custom header template. If not set, default header is used. + /// + [Parameter] public RenderFragment? HeaderTemplate { get; set; } + + /// + /// Custom columns template. If not set, columns are auto-generated. + /// + [Parameter] public RenderFragment? ColumnsTemplate { get; set; } + + /// + /// Custom footer template. If not set, no footer is rendered. + /// + [Parameter] public RenderFragment? FooterTemplate { get; set; } + private ElementReference _panelElement; private bool _isJsInitialized; private const int DefaultTopOffset = 300; // Increased from 180 to account for header + tabs + toolbar diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridToolbarTemplate.razor b/AyCode.Blazor.Components/Components/Grids/MgGridToolbarTemplate.razor index 1350c1d..f9f3115 100644 --- a/AyCode.Blazor.Components/Components/Grids/MgGridToolbarTemplate.razor +++ b/AyCode.Blazor.Components/Components/Grids/MgGridToolbarTemplate.razor @@ -1,32 +1,32 @@ @using AyCode.Blazor.Components.Components.Grids - - - - + + + + - - + + - - + + - @if (!OnlyGridEditTools) - { - - - - - - - - - - - - @ToolbarItemsExtended - } - + @if (!OnlyGridEditTools) + { + + + + + + + + + + + + @ToolbarItemsExtended + } + @code { [Parameter] public bool OnlyGridEditTools { get; set; } = false; diff --git a/AyCode.Blazor.Components/Components/Grids/MgInfoPanelTemplateBase.cs b/AyCode.Blazor.Components/Components/Grids/MgInfoPanelTemplateBase.cs new file mode 100644 index 0000000..d314f46 --- /dev/null +++ b/AyCode.Blazor.Components/Components/Grids/MgInfoPanelTemplateBase.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Components; + +namespace AyCode.Blazor.Components.Components.Grids; + +/// +/// Base class for custom InfoPanel templates. +/// Inherit from this class to create a custom InfoPanel for a specific grid. +/// +public abstract class MgInfoPanelTemplateBase : MgGridInfoPanel +{ + /// + /// Override this to provide custom header content. + /// Return null to use default header. + /// + protected virtual RenderFragment? GetHeaderTemplate() => null; + + /// + /// Override this to provide custom columns/content. + /// Return null to use auto-generated columns. + /// + protected virtual RenderFragment? GetColumnsTemplate() => null; + + /// + /// Override this to provide custom footer content. + /// Return null to hide footer. + /// + protected virtual RenderFragment? GetFooterTemplate() => null; + + protected override void OnInitialized() + { + SetTemplates(); + base.OnInitialized(); + } + + protected override void OnParametersSet() + { + SetTemplates(); + base.OnParametersSet(); + } + + private void SetTemplates() + { + HeaderTemplate = GetHeaderTemplate(); + ColumnsTemplate = GetColumnsTemplate(); + FooterTemplate = GetFooterTemplate(); + } +}