@using DevExpress.Blazor @using Microsoft.AspNetCore.Components.Rendering @using System.Reflection @typeparam TDataItem where TDataItem : class
@if (GetActiveDataItem() != null && _currentGrid != null) { var colSpan = _allDataColumns.Count > 10 ? 6 : 12; var dataItem = GetActiveDataItem()!; @foreach (var column in _allDataColumns) { var displayText = GetDisplayTextFromGrid(column); var value = GetCellValue(column); var settingsType = GetEditSettingsType(column); var isReadOnly = !_isEditMode || column.ReadOnly; } } else {

Válasszon ki egy sort az adatok megtekintéséhez

}
@code { private string GetColumnCaption(DxGridDataColumn column) { return !string.IsNullOrWhiteSpace(column.Caption) ? column.Caption : column.FieldName; } private string GetCaptionCssClass(bool isReadOnly) { return isReadOnly ? "fw-semibold" : "fw-semibold text-primary"; } /// /// Renders an editable cell with two-way binding to the EditModel /// private RenderFragment RenderEditableCell(DxGridDataColumn column, TDataItem dataItem, object? value, string displayText, EditSettingsType settingsType) { return builder => { var seq = 0; var fieldName = column.FieldName; var propertyInfo = typeof(TDataItem).GetProperty(fieldName); if (propertyInfo == null) { // Fallback to readonly if property not found RenderCellContent(column, value, displayText, settingsType)(builder); return; } var propertyType = propertyInfo.PropertyType; var underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; // ComboBox columns if (settingsType == EditSettingsType.ComboBox) { var comboSettings = GetEditSettings(fieldName) as DxComboBoxSettings; if (comboSettings != null) { RenderComboBoxEditor(builder, ref seq, dataItem, propertyInfo, comboSettings); return; } } // Render based on property type if (underlyingType == typeof(bool)) { RenderCheckBoxEditor(builder, ref seq, dataItem, propertyInfo); } else if (underlyingType == typeof(DateTime)) { RenderDateTimeEditor(builder, ref seq, dataItem, propertyInfo, column.DisplayFormat); } else if (underlyingType == typeof(DateOnly)) { RenderDateOnlyEditor(builder, ref seq, dataItem, propertyInfo, column.DisplayFormat); } else if (underlyingType == typeof(TimeOnly)) { RenderTimeOnlyEditor(builder, ref seq, dataItem, propertyInfo); } else if (underlyingType == typeof(TimeSpan)) { RenderTimeSpanEditor(builder, ref seq, dataItem, propertyInfo); } else if (underlyingType == typeof(int)) { RenderSpinIntEditor(builder, ref seq, dataItem, propertyInfo); } else if (underlyingType == typeof(decimal)) { RenderSpinDecimalEditor(builder, ref seq, dataItem, propertyInfo); } else if (underlyingType == typeof(double)) { RenderSpinDoubleEditor(builder, ref seq, dataItem, propertyInfo); } else if (settingsType == EditSettingsType.Memo || (propertyType == typeof(string) && fieldName.Contains("Comment", StringComparison.OrdinalIgnoreCase))) { RenderMemoEditor(builder, ref seq, dataItem, propertyInfo); } else { RenderTextBoxEditor(builder, ref seq, dataItem, propertyInfo); } }; } private void RenderCheckBoxEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var currentValue = (bool)(propertyInfo.GetValue(dataItem) ?? false); builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Checked", currentValue); builder.AddAttribute(seq++, "CheckedChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); builder.CloseComponent(); } private void RenderDateTimeEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo, string? displayFormat) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", (DateTime?)currentValue); builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", (DateTime)(currentValue ?? DateTime.MinValue)); builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd HH:mm"); builder.CloseComponent(); } private void RenderDateOnlyEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo, string? displayFormat) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", (DateOnly?)currentValue); builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", (DateOnly)(currentValue ?? DateOnly.MinValue)); builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd"); builder.CloseComponent(); } private void RenderTimeOnlyEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", (TimeOnly?)currentValue); builder.AddAttribute(seq++, "TimeChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", (TimeOnly)(currentValue ?? TimeOnly.MinValue)); builder.AddAttribute(seq++, "TimeChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.CloseComponent(); } private void RenderTimeSpanEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", (TimeSpan?)currentValue); builder.AddAttribute(seq++, "TimeChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", (TimeSpan)(currentValue ?? TimeSpan.Zero)); builder.AddAttribute(seq++, "TimeChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.CloseComponent(); } private void RenderSpinIntEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (int?)currentValue); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (int)(currentValue ?? 0)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.CloseComponent(); } private void RenderSpinDecimalEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (decimal?)currentValue); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (decimal)(currentValue ?? 0m)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.CloseComponent(); } private void RenderSpinDoubleEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var currentValue = propertyInfo.GetValue(dataItem); if (isNullable) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (double?)currentValue); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } else { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (double)(currentValue ?? 0d)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); } builder.CloseComponent(); } private void RenderTextBoxEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var currentValue = propertyInfo.GetValue(dataItem)?.ToString() ?? string.Empty; builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", currentValue); builder.AddAttribute(seq++, "TextChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); builder.CloseComponent(); } private void RenderMemoEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo) { var currentValue = propertyInfo.GetValue(dataItem)?.ToString() ?? string.Empty; builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", currentValue); builder.AddAttribute(seq++, "TextChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); InvokeAsync(StateHasChanged); })); builder.AddAttribute(seq++, "Rows", 3); builder.CloseComponent(); } private void RenderComboBoxEditor(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings) { var currentValue = propertyInfo.GetValue(dataItem); var propertyType = propertyInfo.PropertyType; var underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; // Determine TData type from settings.Data var dataType = settings.Data?.GetType(); var itemType = typeof(object); if (dataType != null && dataType.IsGenericType) { var genericArgs = dataType.GetGenericArguments(); if (genericArgs.Length > 0) { itemType = genericArgs[0]; } } // Handle common value types for FK fields if (underlyingType == typeof(int)) { RenderComboBoxInt(builder, ref seq, dataItem, propertyInfo, settings, itemType, currentValue); } else if (underlyingType == typeof(long)) { RenderComboBoxLong(builder, ref seq, dataItem, propertyInfo, settings, itemType, currentValue); } else if (underlyingType == typeof(Guid)) { RenderComboBoxGuid(builder, ref seq, dataItem, propertyInfo, settings, itemType, currentValue); } else { // Fallback: render as TextBox with display text var displayText = ResolveComboBoxDisplayText(settings, currentValue ?? new object()) ?? currentValue?.ToString() ?? string.Empty; builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", displayText); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); } } private void RenderComboBoxInt(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; // Create the generic ComboBox type: DxComboBox or DxComboBox var comboType = isNullable ? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(int?)) : typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(int)); builder.OpenComponent(seq++, comboType); builder.AddAttribute(seq++, "Data", settings.Data); builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName); builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName); if (isNullable) { builder.AddAttribute(seq++, "Value", currentValue as int?); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); StateHasChanged(); })); } else { builder.AddAttribute(seq++, "Value", currentValue is int intVal ? intVal : 0); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); StateHasChanged(); })); } builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto); builder.CloseComponent(); } private void RenderComboBoxLong(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var comboType = isNullable ? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(long?)) : typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(long)); builder.OpenComponent(seq++, comboType); builder.AddAttribute(seq++, "Data", settings.Data); builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName); builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName); if (isNullable) { builder.AddAttribute(seq++, "Value", currentValue as long?); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); StateHasChanged(); })); } else { builder.AddAttribute(seq++, "Value", currentValue is long longVal ? longVal : 0L); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); StateHasChanged(); })); } builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto); builder.CloseComponent(); } private void RenderComboBoxGuid(RenderTreeBuilder builder, ref int seq, TDataItem dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue) { var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; var comboType = isNullable ? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(Guid?)) : typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(Guid)); builder.OpenComponent(seq++, comboType); builder.AddAttribute(seq++, "Data", settings.Data); builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName); builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName); if (isNullable) { builder.AddAttribute(seq++, "Value", currentValue as Guid?); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); StateHasChanged(); })); } else { builder.AddAttribute(seq++, "Value", currentValue is Guid guidVal ? guidVal : Guid.Empty); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, newValue => { propertyInfo.SetValue(dataItem, newValue); StateHasChanged(); })); } builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto); builder.CloseComponent(); } private RenderFragment RenderCellContent(DxGridDataColumn column, object? value, string displayText, EditSettingsType settingsType) { return builder => { var seq = 0; // If column has EditSettings, render based on that switch (settingsType) { case EditSettingsType.ComboBox: // ComboBox columns show resolved display text builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", displayText); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); return; case EditSettingsType.CheckBox when value is bool boolVal: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Checked", boolVal); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); return; case EditSettingsType.DateEdit: RenderDateEditor(builder, ref seq, value, column.DisplayFormat); return; case EditSettingsType.TimeEdit: RenderTimeEditor(builder, ref seq, value, column.DisplayFormat); return; case EditSettingsType.SpinEdit: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", displayText); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "CssClass", "text-end"); builder.CloseComponent(); return; case EditSettingsType.Memo: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", displayText); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "Rows", 3); builder.CloseComponent(); return; } // Default: render based on value type switch (value) { case bool boolValue: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Checked", boolValue); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; case DateTime dateValue: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", dateValue); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "DisplayFormat", column.DisplayFormat ?? "yyyy-MM-dd HH:mm"); builder.CloseComponent(); break; case DateOnly dateOnlyValue: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", dateOnlyValue); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "DisplayFormat", column.DisplayFormat ?? "yyyy-MM-dd"); builder.CloseComponent(); break; case TimeOnly timeOnlyValue: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", timeOnlyValue); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; case TimeSpan timeSpanValue: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", timeSpanValue); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; case decimal or double or float or int or long or short: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", displayText); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "CssClass", "text-end"); builder.CloseComponent(); break; default: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", displayText); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; } }; } private void RenderDateEditor(RenderTreeBuilder builder, ref int seq, object? value, string? displayFormat) { switch (value) { case DateTime dateTime: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", dateTime); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd HH:mm"); builder.CloseComponent(); break; case DateOnly dateOnly: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", dateOnly); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd"); builder.CloseComponent(); break; case DateTimeOffset dateTimeOffset: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Date", dateTimeOffset); builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd HH:mm"); builder.CloseComponent(); break; default: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", value?.ToString() ?? string.Empty); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; } } private void RenderTimeEditor(RenderTreeBuilder builder, ref int seq, object? value, string? displayFormat) { switch (value) { case TimeOnly timeOnly: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", timeOnly); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; case TimeSpan timeSpan: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", timeSpan); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; case DateTime dateTime: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Time", dateTime); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; default: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Text", value?.ToString() ?? string.Empty); builder.AddAttribute(seq++, "ReadOnly", true); builder.CloseComponent(); break; } } }