391 lines
12 KiB
C#
391 lines
12 KiB
C#
using DevExpress.Blazor;
|
||
using Microsoft.AspNetCore.Components;
|
||
using Microsoft.JSInterop;
|
||
|
||
namespace AyCode.Blazor.Components.Components.Grids;
|
||
|
||
/// <summary>
|
||
/// Interface for InfoPanel to support grid access
|
||
/// </summary>
|
||
public interface IInfoPanelBase
|
||
{
|
||
void ClearEditMode();
|
||
void SetEditMode(object editModel);
|
||
void RefreshData(IMgGridBase grid, object? dataItem, int visibleIndex = -1);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Non-generic version of the InfoPanel component
|
||
/// </summary>
|
||
public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPanelBase
|
||
{
|
||
[Inject] private IJSRuntime JSRuntime { get; set; } = null!;
|
||
|
||
/// <summary>
|
||
/// Whether to show readonly fields when in edit mode. Default is false.
|
||
/// </summary>
|
||
[Parameter] public bool ShowReadOnlyFieldsInEditMode { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// Custom header template. If not set, default header is used.
|
||
/// </summary>
|
||
[Parameter] public RenderFragment? HeaderTemplate { get; set; }
|
||
|
||
/// <summary>
|
||
/// Custom columns template. If not set, columns are auto-generated.
|
||
/// </summary>
|
||
[Parameter] public RenderFragment? ColumnsTemplate { get; set; }
|
||
|
||
/// <summary>
|
||
/// Custom footer template. If not set, no footer is rendered.
|
||
/// </summary>
|
||
[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
|
||
|
||
private IMgGridBase? _currentGrid;
|
||
private object? _currentDataItem;
|
||
private int _focusedRowVisibleIndex = -1;
|
||
private List<DxGridDataColumn> _allDataColumns = [];
|
||
|
||
// Edit mode state
|
||
private bool _isEditMode;
|
||
private object? _editModel;
|
||
|
||
// Cache for edit settings to avoid repeated lookups
|
||
private readonly Dictionary<string, IEditSettings?> _editSettingsCache = [];
|
||
|
||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||
{
|
||
if (firstRender)
|
||
{
|
||
await InitializeStickyAsync();
|
||
}
|
||
}
|
||
|
||
private async Task InitializeStickyAsync()
|
||
{
|
||
try
|
||
{
|
||
await JSRuntime.InvokeVoidAsync(
|
||
"MgGridInfoPanel.initSticky",
|
||
_panelElement,
|
||
DefaultTopOffset);
|
||
_isJsInitialized = true;
|
||
}
|
||
catch (JSException)
|
||
{
|
||
// JS might not be loaded yet, ignore
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Refreshes the InfoPanel with data from the specified grid row (view mode)
|
||
/// </summary>
|
||
public void RefreshData(IMgGridBase grid, object? dataItem, int visibleIndex = -1)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(grid);
|
||
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData called - dataItem type: {dataItem?.GetType().Name ?? "null"}, visibleIndex: {visibleIndex}");
|
||
|
||
_currentGrid = grid;
|
||
_currentDataItem = dataItem;
|
||
_focusedRowVisibleIndex = visibleIndex;
|
||
_editSettingsCache.Clear();
|
||
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - _currentDataItem is null: {_currentDataItem == null}, cast success: {dataItem != null && _currentDataItem != null}");
|
||
|
||
// Ha nem vagyunk edit m<>dban, friss<73>tj<74>k az oszlopokat
|
||
if (!_isEditMode)
|
||
{
|
||
if (_currentGrid != null && _currentDataItem != null)
|
||
{
|
||
_allDataColumns = GetAllDataColumns(_currentGrid);
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - loaded {_allDataColumns.Count} columns");
|
||
}
|
||
else
|
||
{
|
||
_allDataColumns = [];
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - cleared columns (grid or dataItem is null)");
|
||
}
|
||
}
|
||
|
||
StateHasChanged();
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - StateHasChanged called");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets the InfoPanel to edit mode with the given edit model
|
||
/// </summary>
|
||
public void SetEditMode(object editModel)
|
||
{
|
||
_editModel = editModel;
|
||
_isEditMode = true;
|
||
_currentDataItem = _editModel;
|
||
|
||
if (_currentGrid != null)
|
||
{
|
||
_allDataColumns = GetAllDataColumns(_currentGrid);
|
||
}
|
||
|
||
StateHasChanged();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Clears edit mode and returns to view mode
|
||
/// </summary>
|
||
public void ClearEditMode()
|
||
{
|
||
_isEditMode = false;
|
||
_editModel = null;
|
||
_editSettingsCache.Clear();
|
||
StateHasChanged();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Clears the InfoPanel completely
|
||
/// </summary>
|
||
public void Clear()
|
||
{
|
||
_currentGrid = null;
|
||
_currentDataItem = null;
|
||
_focusedRowVisibleIndex = -1;
|
||
_allDataColumns = [];
|
||
_editSettingsCache.Clear();
|
||
_isEditMode = false;
|
||
_editModel = null;
|
||
StateHasChanged();
|
||
}
|
||
|
||
public async ValueTask DisposeAsync()
|
||
{
|
||
if (_isJsInitialized)
|
||
{
|
||
try
|
||
{
|
||
await JSRuntime.InvokeVoidAsync("MgGridInfoPanel.disposeSticky", _panelElement);
|
||
}
|
||
catch
|
||
{
|
||
// Ignore disposal errors
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the data item to display/edit (EditModel in edit mode, otherwise CurrentDataItem)
|
||
/// </summary>
|
||
private object? GetActiveDataItem() => _isEditMode && _editModel != null ? _editModel : _currentDataItem;
|
||
|
||
/// <summary>
|
||
/// Gets the display text for a field using the grid's internal formatting.
|
||
/// For ComboBox columns, tries to get the text from the lookup data source.
|
||
/// </summary>
|
||
private string GetDisplayTextFromGrid(DxGridDataColumn column)
|
||
{
|
||
var dataItem = GetActiveDataItem();
|
||
if (_currentGrid == null || dataItem == null || string.IsNullOrWhiteSpace(column.FieldName))
|
||
return string.Empty;
|
||
|
||
try
|
||
{
|
||
var value = _currentGrid.GetDataItemValue(dataItem, column.FieldName);
|
||
|
||
if (value == null)
|
||
return string.Empty;
|
||
|
||
// Try to resolve display text from EditSettings
|
||
var editSettings = GetEditSettings(column.FieldName);
|
||
if (editSettings is DxComboBoxSettings comboSettings)
|
||
{
|
||
var displayText = ResolveComboBoxDisplayText(comboSettings, value);
|
||
if (!string.IsNullOrEmpty(displayText))
|
||
return displayText;
|
||
}
|
||
|
||
// Apply column's DisplayFormat if available
|
||
if (!string.IsNullOrEmpty(column.DisplayFormat))
|
||
{
|
||
try
|
||
{
|
||
return string.Format(column.DisplayFormat, value);
|
||
}
|
||
catch
|
||
{
|
||
// If format fails, fall through to default formatting
|
||
}
|
||
}
|
||
|
||
return FormatValue(value);
|
||
}
|
||
catch
|
||
{
|
||
return string.Empty;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets edit settings for the specified field (with caching)
|
||
/// </summary>
|
||
private IEditSettings? GetEditSettings(string fieldName)
|
||
{
|
||
if (_currentGrid == null || string.IsNullOrEmpty(fieldName))
|
||
return null;
|
||
|
||
if (_editSettingsCache.TryGetValue(fieldName, out var cached))
|
||
return cached;
|
||
|
||
IEditSettings? settings = null;
|
||
try
|
||
{
|
||
// Try each EditSettings type
|
||
settings = _currentGrid.GetColumnEditSettings<DxComboBoxSettings>(fieldName)
|
||
?? _currentGrid.GetColumnEditSettings<DxDateEditSettings>(fieldName)
|
||
?? _currentGrid.GetColumnEditSettings<DxTimeEditSettings>(fieldName)
|
||
?? _currentGrid.GetColumnEditSettings<DxSpinEditSettings>(fieldName)
|
||
?? _currentGrid.GetColumnEditSettings<DxCheckBoxSettings>(fieldName)
|
||
?? _currentGrid.GetColumnEditSettings<DxMemoSettings>(fieldName)
|
||
?? (IEditSettings?)_currentGrid.GetColumnEditSettings<DxTextBoxSettings>(fieldName);
|
||
}
|
||
catch
|
||
{
|
||
// Ignore errors
|
||
}
|
||
|
||
_editSettingsCache[fieldName] = settings;
|
||
return settings;
|
||
}
|
||
|
||
private string? ResolveComboBoxDisplayText(DxComboBoxSettings settings, object value)
|
||
{
|
||
if (settings.Data == null || string.IsNullOrEmpty(settings.ValueFieldName) || string.IsNullOrEmpty(settings.TextFieldName))
|
||
return null;
|
||
|
||
try
|
||
{
|
||
foreach (var item in (System.Collections.IEnumerable)settings.Data)
|
||
{
|
||
if (item == null) continue;
|
||
|
||
var itemType = item.GetType();
|
||
var valueProperty = itemType.GetProperty(settings.ValueFieldName);
|
||
var textProperty = itemType.GetProperty(settings.TextFieldName);
|
||
|
||
if (valueProperty == null || textProperty == null) continue;
|
||
|
||
var itemValue = valueProperty.GetValue(item);
|
||
if (itemValue != null && itemValue.Equals(value))
|
||
{
|
||
return textProperty.GetValue(item)?.ToString();
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// If lookup fails, return null and fall back to default formatting
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
private static string FormatValue(object? value)
|
||
{
|
||
if (value == null)
|
||
return string.Empty;
|
||
|
||
return value switch
|
||
{
|
||
DateTime dateTime => dateTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
||
DateOnly dateOnly => dateOnly.ToString("yyyy-MM-dd"),
|
||
TimeOnly timeOnly => timeOnly.ToString("HH:mm:ss"),
|
||
TimeSpan timeSpan => timeSpan.ToString(@"hh\:mm\:ss"),
|
||
bool boolValue => boolValue ? "Igen" : "Nem",
|
||
decimal decValue => decValue.ToString("N2"),
|
||
double dblValue => dblValue.ToString("N2"),
|
||
float fltValue => fltValue.ToString("N2"),
|
||
int or long or short or byte => $"{value:N0}",
|
||
_ => value.ToString() ?? string.Empty
|
||
};
|
||
}
|
||
|
||
private static List<DxGridDataColumn> GetAllDataColumns(IMgGridBase grid)
|
||
{
|
||
var columns = new List<DxGridDataColumn>();
|
||
|
||
try
|
||
{
|
||
var allColumns = grid.GetDataColumns();
|
||
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] GetAllDataColumns - grid type: {grid.GetType().Name}, columns count: {allColumns?.Count() ?? 0}");
|
||
|
||
if (allColumns != null)
|
||
{
|
||
foreach (var column in allColumns)
|
||
{
|
||
if (column is DxGridDataColumn dataColumn &&
|
||
!string.IsNullOrWhiteSpace(dataColumn.FieldName))
|
||
{
|
||
columns.Add(dataColumn);
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] - Column: {dataColumn.FieldName}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] GetAllDataColumns error: {ex.Message}");
|
||
}
|
||
|
||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] GetAllDataColumns result: {columns.Count} columns");
|
||
return columns;
|
||
}
|
||
|
||
private object? GetCellValue(DxGridDataColumn column)
|
||
{
|
||
var dataItem = GetActiveDataItem();
|
||
if (_currentGrid == null || dataItem == null || string.IsNullOrWhiteSpace(column.FieldName))
|
||
return null;
|
||
|
||
try
|
||
{
|
||
return _currentGrid.GetDataItemValue(dataItem, column.FieldName);
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the EditSettings type for rendering logic
|
||
/// </summary>
|
||
private EditSettingsType GetEditSettingsType(DxGridDataColumn column)
|
||
{
|
||
var settings = GetEditSettings(column.FieldName);
|
||
|
||
return settings switch
|
||
{
|
||
DxComboBoxSettings => EditSettingsType.ComboBox,
|
||
DxDateEditSettings => EditSettingsType.DateEdit,
|
||
DxTimeEditSettings => EditSettingsType.TimeEdit,
|
||
DxSpinEditSettings => EditSettingsType.SpinEdit,
|
||
DxCheckBoxSettings => EditSettingsType.CheckBox,
|
||
DxMemoSettings => EditSettingsType.Memo,
|
||
_ => EditSettingsType.None
|
||
};
|
||
}
|
||
|
||
private enum EditSettingsType
|
||
{
|
||
None,
|
||
ComboBox,
|
||
DateEdit,
|
||
TimeEdit,
|
||
SpinEdit,
|
||
CheckBox,
|
||
Memo
|
||
}
|
||
}
|