@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;
@if (_isEditMode && !column.ReadOnly)
{
@RenderEditableCell(column, dataItem, value, displayText, settingsType)
}
else
{
@RenderCellContent(column, value, displayText, settingsType)
}
}
}
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;
}
}
}