Refactor MgGridInfoPanel for theme, UX, and PDF perf
- Refactored MgGridInfoPanel for DevExpress theme compatibility and improved usability; streamlined HTML/CSS, added OnDataItemChanged event, and enhanced empty state handling. - Updated CSS to use theme variables, improved responsive grid and table styling, and enhanced integration with DevExpress components. - GridShippingDocumentInfoPanel now uses OnDataItemChanged to load a random PDF per row selection; table layout and totals improved. - Optimized pdfViewer.js to cache rendered PDFs, skip redundant renders, and improve logging and error handling. - Added empty helper classes for future extensibility. - Minor: MainLayout now uses RefreshMainLayout for UI refresh after auto-login.
This commit is contained in:
parent
4c86914884
commit
017eb16c4b
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AyCode.Blazor.Components.Components.Grids
|
||||||
|
{
|
||||||
|
internal class MgGridHelper
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,24 +2,21 @@
|
||||||
@using Microsoft.AspNetCore.Components.Rendering
|
@using Microsoft.AspNetCore.Components.Rendering
|
||||||
@using System.Reflection
|
@using System.Reflection
|
||||||
|
|
||||||
<div @ref="_panelElement" class="mg-grid-info-panel @(_isEditMode ? "edit-mode" : "view-mode") @GetColumnCountClass()"
|
<div @ref="_panelElement" class="mg-grid-info-panel @(_isEditMode ? "edit-mode" : "") @GetColumnCountClass()">
|
||||||
style="@GetBreakpointStyles()">
|
|
||||||
@* Header *@
|
@* Header *@
|
||||||
@if (HeaderTemplate != null)
|
@if (HeaderTemplate != null)
|
||||||
{
|
{
|
||||||
@HeaderTemplate(GetActiveDataItem())
|
@HeaderTemplate(GetActiveDataItem())
|
||||||
}
|
}
|
||||||
else
|
else if (_currentGrid != null)
|
||||||
{
|
{
|
||||||
<div class="dxbl-grid-header-panel px-3 py-2 border-bottom">
|
<div class="mg-info-panel-header">@_currentGrid.Caption</div>
|
||||||
<span class="fw-semibold">@(_currentGrid?.Caption ?? "")</span>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@* Toolbar *@
|
@* Toolbar *@
|
||||||
@if (_currentGrid != null)
|
@if (_currentGrid != null)
|
||||||
{
|
{
|
||||||
<div class="mg-info-panel-toolbar border-bottom">
|
<div class="mg-info-panel-toolbar">
|
||||||
<MgGridToolbarTemplate Grid="_currentGrid" OnlyGridEditTools="true" ShowOnlyIcon="true" />
|
<MgGridToolbarTemplate Grid="_currentGrid" OnlyGridEditTools="true" ShowOnlyIcon="true" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -28,13 +25,11 @@
|
||||||
<div class="mg-info-panel-content">
|
<div class="mg-info-panel-content">
|
||||||
@if (GetActiveDataItem() != null && _currentGrid != null)
|
@if (GetActiveDataItem() != null && _currentGrid != null)
|
||||||
{
|
{
|
||||||
@* Before Columns *@
|
|
||||||
@if (BeforeColumnsTemplate != null)
|
@if (BeforeColumnsTemplate != null)
|
||||||
{
|
{
|
||||||
@BeforeColumnsTemplate(GetActiveDataItem())
|
@BeforeColumnsTemplate(GetActiveDataItem())
|
||||||
}
|
}
|
||||||
|
|
||||||
@* Columns *@
|
|
||||||
@if (ColumnsTemplate != null)
|
@if (ColumnsTemplate != null)
|
||||||
{
|
{
|
||||||
@ColumnsTemplate(GetActiveDataItem())
|
@ColumnsTemplate(GetActiveDataItem())
|
||||||
|
|
@ -44,7 +39,6 @@
|
||||||
@RenderDefaultColumns()
|
@RenderDefaultColumns()
|
||||||
}
|
}
|
||||||
|
|
||||||
@* After Columns *@
|
|
||||||
@if (AfterColumnsTemplate != null)
|
@if (AfterColumnsTemplate != null)
|
||||||
{
|
{
|
||||||
@AfterColumnsTemplate(GetActiveDataItem())
|
@AfterColumnsTemplate(GetActiveDataItem())
|
||||||
|
|
@ -52,7 +46,7 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="text-center text-muted py-5">
|
<div class="mg-info-panel-empty">
|
||||||
<p>Válasszon ki egy sort az adatok megtekintéséhez</p>
|
<p>Válasszon ki egy sort az adatok megtekintéséhez</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -66,55 +60,31 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
/// <summary>
|
|
||||||
/// Custom header template. Receives the current data item.
|
|
||||||
/// </summary>
|
|
||||||
[Parameter] public RenderFragment<object?>? HeaderTemplate { get; set; }
|
[Parameter] public RenderFragment<object?>? HeaderTemplate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content to render before the columns.
|
|
||||||
/// </summary>
|
|
||||||
[Parameter] public RenderFragment<object?>? BeforeColumnsTemplate { get; set; }
|
[Parameter] public RenderFragment<object?>? BeforeColumnsTemplate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom columns template. If not set, columns are auto-generated.
|
|
||||||
/// </summary>
|
|
||||||
[Parameter] public RenderFragment<object?>? ColumnsTemplate { get; set; }
|
[Parameter] public RenderFragment<object?>? ColumnsTemplate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content to render after the columns.
|
|
||||||
/// </summary>
|
|
||||||
[Parameter] public RenderFragment<object?>? AfterColumnsTemplate { get; set; }
|
[Parameter] public RenderFragment<object?>? AfterColumnsTemplate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom footer template.
|
|
||||||
/// </summary>
|
|
||||||
[Parameter] public RenderFragment<object?>? FooterTemplate { get; set; }
|
[Parameter] public RenderFragment<object?>? FooterTemplate { get; set; }
|
||||||
|
|
||||||
private string GetColumnCountClass()
|
/// <summary>
|
||||||
{
|
/// Called when the data item changes (row selection changed)
|
||||||
if (FixedColumnCount.HasValue)
|
/// </summary>
|
||||||
{
|
[Parameter] public EventCallback<object?> OnDataItemChanged { get; set; }
|
||||||
return FixedColumnCount.Value switch
|
|
||||||
{
|
|
||||||
1 => "mg-columns-1",
|
|
||||||
2 => "mg-columns-2",
|
|
||||||
3 => "mg-columns-3",
|
|
||||||
4 => "mg-columns-4",
|
|
||||||
_ => ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetBreakpointStyles()
|
private string GetColumnCountClass() => FixedColumnCount switch
|
||||||
{
|
{
|
||||||
return $"--mg-bp-2col: {TwoColumnBreakpoint}px; --mg-bp-3col: {ThreeColumnBreakpoint}px; --mg-bp-4col: {FourColumnBreakpoint}px;";
|
1 => "mg-columns-1",
|
||||||
}
|
2 => "mg-columns-2",
|
||||||
|
3 => "mg-columns-3",
|
||||||
|
4 => "mg-columns-4",
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
|
|
||||||
private RenderFragment RenderDefaultColumns() => builder =>
|
private RenderFragment RenderDefaultColumns() => builder =>
|
||||||
{
|
{
|
||||||
var dataItem = GetActiveDataItem()!;
|
var dataItem = GetActiveDataItem();
|
||||||
|
if (dataItem == null) return;
|
||||||
|
|
||||||
var dataItemType = dataItem.GetType();
|
var dataItemType = dataItem.GetType();
|
||||||
var seq = 0;
|
var seq = 0;
|
||||||
|
|
||||||
|
|
@ -126,134 +96,92 @@
|
||||||
var displayText = GetDisplayTextFromGrid(column);
|
var displayText = GetDisplayTextFromGrid(column);
|
||||||
var value = GetCellValue(column);
|
var value = GetCellValue(column);
|
||||||
var settingsType = GetEditSettingsType(column);
|
var settingsType = GetEditSettingsType(column);
|
||||||
var isReadOnly = !_isEditMode || column.ReadOnly;
|
var isEditable = _isEditMode && !column.ReadOnly;
|
||||||
|
|
||||||
builder.OpenElement(seq++, "div");
|
builder.OpenElement(seq++, "div");
|
||||||
builder.AddAttribute(seq++, "class", "mg-info-panel-item");
|
builder.AddAttribute(seq++, "class", "mg-info-panel-item");
|
||||||
|
|
||||||
builder.OpenElement(seq++, "div");
|
|
||||||
builder.AddAttribute(seq++, "class", "dxbl-form-layout-item");
|
|
||||||
|
|
||||||
builder.OpenElement(seq++, "label");
|
builder.OpenElement(seq++, "label");
|
||||||
builder.AddAttribute(seq++, "class", $"dxbl-fl-lc {GetCaptionCssClass(isReadOnly)} d-block mb-1 small");
|
builder.AddAttribute(seq++, "class", isEditable ? "mg-info-panel-label editable" : "mg-info-panel-label");
|
||||||
builder.AddContent(seq++, GetColumnCaption(column));
|
builder.AddContent(seq++, GetColumnCaption(column));
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
|
|
||||||
builder.OpenElement(seq++, "div");
|
builder.OpenElement(seq++, "div");
|
||||||
builder.AddAttribute(seq++, "class", "dxbl-fl-ec");
|
if (isEditable)
|
||||||
|
|
||||||
if (_isEditMode && !column.ReadOnly)
|
|
||||||
{
|
{
|
||||||
RenderEditableCell(column, dataItem, dataItemType, value, displayText, settingsType)(builder);
|
RenderEditableCell(column, dataItem, dataItemType, value, displayText, settingsType)(builder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RenderCellContent(column, value, displayText, settingsType)(builder);
|
RenderCellContent(value, displayText)(builder);
|
||||||
}
|
}
|
||||||
|
builder.CloseElement();
|
||||||
|
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
builder.CloseElement();
|
|
||||||
builder.CloseElement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string GetColumnCaption(DxGridDataColumn column)
|
private static string GetColumnCaption(DxGridDataColumn column) =>
|
||||||
{
|
!string.IsNullOrWhiteSpace(column.Caption) ? column.Caption : column.FieldName;
|
||||||
return !string.IsNullOrWhiteSpace(column.Caption) ? column.Caption : column.FieldName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetCaptionCssClass(bool isReadOnly)
|
|
||||||
{
|
|
||||||
return isReadOnly ? "fw-semibold" : "fw-semibold text-primary";
|
|
||||||
}
|
|
||||||
|
|
||||||
private RenderFragment RenderEditableCell(DxGridDataColumn column, object dataItem, Type dataItemType, object? value, string displayText, EditSettingsType settingsType)
|
private RenderFragment RenderEditableCell(DxGridDataColumn column, object dataItem, Type dataItemType, object? value, string displayText, EditSettingsType settingsType)
|
||||||
{
|
{
|
||||||
return builder =>
|
return builder =>
|
||||||
{
|
{
|
||||||
var seq = 0;
|
var seq = 0;
|
||||||
var fieldName = column.FieldName;
|
var propertyInfo = dataItemType.GetProperty(column.FieldName);
|
||||||
var propertyInfo = dataItemType.GetProperty(fieldName);
|
|
||||||
|
|
||||||
if (propertyInfo == null)
|
if (propertyInfo == null)
|
||||||
{
|
{
|
||||||
RenderCellContent(column, value, displayText, settingsType)(builder);
|
RenderCellContent(value, displayText)(builder);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var propertyType = propertyInfo.PropertyType;
|
var underlyingType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
|
||||||
var underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
|
|
||||||
|
|
||||||
// ComboBox
|
if (settingsType == EditSettingsType.ComboBox && GetEditSettings(column.FieldName) is DxComboBoxSettings comboSettings)
|
||||||
if (settingsType == EditSettingsType.ComboBox)
|
|
||||||
{
|
{
|
||||||
var comboSettings = GetEditSettings(column.FieldName) as DxComboBoxSettings;
|
RenderComboBoxEditor(builder, ref seq, dataItem, propertyInfo, comboSettings);
|
||||||
if (comboSettings != null)
|
return;
|
||||||
{
|
|
||||||
RenderComboBoxEditor(builder, ref seq, dataItem, propertyInfo, comboSettings);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render based on type
|
if (underlyingType == typeof(bool)) RenderCheckBoxEditor(builder, ref seq, dataItem, propertyInfo);
|
||||||
if (underlyingType == typeof(bool))
|
else if (underlyingType == typeof(DateTime)) RenderDateTimeEditor(builder, ref seq, dataItem, propertyInfo, column.DisplayFormat);
|
||||||
RenderCheckBoxEditor(builder, ref seq, dataItem, propertyInfo);
|
else if (underlyingType == typeof(DateOnly)) RenderDateOnlyEditor(builder, ref seq, dataItem, propertyInfo, column.DisplayFormat);
|
||||||
else if (underlyingType == typeof(DateTime))
|
else if (underlyingType == typeof(int)) RenderSpinIntEditor(builder, ref seq, dataItem, propertyInfo);
|
||||||
RenderDateTimeEditor(builder, ref seq, dataItem, propertyInfo, column.DisplayFormat);
|
else if (underlyingType == typeof(decimal)) RenderSpinDecimalEditor(builder, ref seq, dataItem, propertyInfo);
|
||||||
else if (underlyingType == typeof(DateOnly))
|
else if (underlyingType == typeof(double)) RenderSpinDoubleEditor(builder, ref seq, dataItem, propertyInfo);
|
||||||
RenderDateOnlyEditor(builder, ref seq, dataItem, propertyInfo, column.DisplayFormat);
|
else if (settingsType == EditSettingsType.Memo) RenderMemoEditor(builder, ref seq, dataItem, propertyInfo);
|
||||||
else if (underlyingType == typeof(int))
|
else RenderTextBoxEditor(builder, ref seq, dataItem, propertyInfo);
|
||||||
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)
|
|
||||||
RenderMemoEditor(builder, ref seq, dataItem, propertyInfo);
|
|
||||||
else
|
|
||||||
RenderTextBoxEditor(builder, ref seq, dataItem, propertyInfo);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderCheckBoxEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
private void RenderCheckBoxEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
var currentValue = (bool)(propertyInfo.GetValue(dataItem) ?? false);
|
|
||||||
builder.OpenComponent<DxCheckBox<bool>>(seq++);
|
builder.OpenComponent<DxCheckBox<bool>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Checked", currentValue);
|
builder.AddAttribute(seq++, "Checked", (bool)(propertyInfo.GetValue(dataItem) ?? false));
|
||||||
builder.AddAttribute(seq++, "CheckedChanged", EventCallback.Factory.Create<bool>(this, newValue =>
|
builder.AddAttribute(seq++, "CheckedChanged", EventCallback.Factory.Create<bool>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderDateTimeEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, string? displayFormat)
|
private void RenderDateTimeEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, string? displayFormat)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var currentValue = propertyInfo.GetValue(dataItem);
|
var value = propertyInfo.GetValue(dataItem);
|
||||||
|
|
||||||
if (isNullable)
|
if (isNullable)
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxDateEdit<DateTime?>>(seq++);
|
builder.OpenComponent<DxDateEdit<DateTime?>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Date", (DateTime?)currentValue);
|
builder.AddAttribute(seq++, "Date", (DateTime?)value);
|
||||||
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateTime?>(this, newValue =>
|
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateTime?>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxDateEdit<DateTime>>(seq++);
|
builder.OpenComponent<DxDateEdit<DateTime>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Date", (DateTime)(currentValue ?? DateTime.MinValue));
|
builder.AddAttribute(seq++, "Date", (DateTime)(value ?? DateTime.MinValue));
|
||||||
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateTime>(this, newValue =>
|
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateTime>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd HH:mm");
|
builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd HH:mm");
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
|
|
@ -262,27 +190,19 @@
|
||||||
private void RenderDateOnlyEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, string? displayFormat)
|
private void RenderDateOnlyEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, string? displayFormat)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var currentValue = propertyInfo.GetValue(dataItem);
|
var value = propertyInfo.GetValue(dataItem);
|
||||||
|
|
||||||
if (isNullable)
|
if (isNullable)
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxDateEdit<DateOnly?>>(seq++);
|
builder.OpenComponent<DxDateEdit<DateOnly?>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Date", (DateOnly?)currentValue);
|
builder.AddAttribute(seq++, "Date", (DateOnly?)value);
|
||||||
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateOnly?>(this, newValue =>
|
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateOnly?>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxDateEdit<DateOnly>>(seq++);
|
builder.OpenComponent<DxDateEdit<DateOnly>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Date", (DateOnly)(currentValue ?? DateOnly.MinValue));
|
builder.AddAttribute(seq++, "Date", (DateOnly)(value ?? DateOnly.MinValue));
|
||||||
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateOnly>(this, newValue =>
|
builder.AddAttribute(seq++, "DateChanged", EventCallback.Factory.Create<DateOnly>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd");
|
builder.AddAttribute(seq++, "DisplayFormat", displayFormat ?? "yyyy-MM-dd");
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
|
|
@ -291,27 +211,19 @@
|
||||||
private void RenderSpinIntEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
private void RenderSpinIntEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var currentValue = propertyInfo.GetValue(dataItem);
|
var value = propertyInfo.GetValue(dataItem);
|
||||||
|
|
||||||
if (isNullable)
|
if (isNullable)
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxSpinEdit<int?>>(seq++);
|
builder.OpenComponent<DxSpinEdit<int?>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Value", (int?)currentValue);
|
builder.AddAttribute(seq++, "Value", (int?)value);
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<int?>(this, newValue =>
|
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<int?>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxSpinEdit<int>>(seq++);
|
builder.OpenComponent<DxSpinEdit<int>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Value", (int)(currentValue ?? 0));
|
builder.AddAttribute(seq++, "Value", (int)(value ?? 0));
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<int>(this, newValue =>
|
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<int>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
@ -319,27 +231,19 @@
|
||||||
private void RenderSpinDecimalEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
private void RenderSpinDecimalEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var currentValue = propertyInfo.GetValue(dataItem);
|
var value = propertyInfo.GetValue(dataItem);
|
||||||
|
|
||||||
if (isNullable)
|
if (isNullable)
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxSpinEdit<decimal?>>(seq++);
|
builder.OpenComponent<DxSpinEdit<decimal?>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Value", (decimal?)currentValue);
|
builder.AddAttribute(seq++, "Value", (decimal?)value);
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<decimal?>(this, newValue =>
|
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<decimal?>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxSpinEdit<decimal>>(seq++);
|
builder.OpenComponent<DxSpinEdit<decimal>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Value", (decimal)(currentValue ?? 0m));
|
builder.AddAttribute(seq++, "Value", (decimal)(value ?? 0m));
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<decimal>(this, newValue =>
|
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<decimal>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
@ -347,84 +251,56 @@
|
||||||
private void RenderSpinDoubleEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
private void RenderSpinDoubleEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var currentValue = propertyInfo.GetValue(dataItem);
|
var value = propertyInfo.GetValue(dataItem);
|
||||||
|
|
||||||
if (isNullable)
|
if (isNullable)
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxSpinEdit<double?>>(seq++);
|
builder.OpenComponent<DxSpinEdit<double?>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Value", (double?)currentValue);
|
builder.AddAttribute(seq++, "Value", (double?)value);
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<double?>(this, newValue =>
|
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<double?>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.OpenComponent<DxSpinEdit<double>>(seq++);
|
builder.OpenComponent<DxSpinEdit<double>>(seq++);
|
||||||
builder.AddAttribute(seq++, "Value", (double)(currentValue ?? 0d));
|
builder.AddAttribute(seq++, "Value", (double)(value ?? 0d));
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<double>(this, newValue =>
|
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<double>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderTextBoxEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
private void RenderTextBoxEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
var currentValue = propertyInfo.GetValue(dataItem)?.ToString() ?? string.Empty;
|
|
||||||
builder.OpenComponent<DxTextBox>(seq++);
|
builder.OpenComponent<DxTextBox>(seq++);
|
||||||
builder.AddAttribute(seq++, "Text", currentValue);
|
builder.AddAttribute(seq++, "Text", propertyInfo.GetValue(dataItem)?.ToString() ?? "");
|
||||||
builder.AddAttribute(seq++, "TextChanged", EventCallback.Factory.Create<string>(this, newValue =>
|
builder.AddAttribute(seq++, "TextChanged", EventCallback.Factory.Create<string>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderMemoEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
private void RenderMemoEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
var currentValue = propertyInfo.GetValue(dataItem)?.ToString() ?? string.Empty;
|
|
||||||
builder.OpenComponent<DxMemo>(seq++);
|
builder.OpenComponent<DxMemo>(seq++);
|
||||||
builder.AddAttribute(seq++, "Text", currentValue);
|
builder.AddAttribute(seq++, "Text", propertyInfo.GetValue(dataItem)?.ToString() ?? "");
|
||||||
builder.AddAttribute(seq++, "TextChanged", EventCallback.Factory.Create<string>(this, newValue =>
|
builder.AddAttribute(seq++, "TextChanged", EventCallback.Factory.Create<string>(this, v => { propertyInfo.SetValue(dataItem, v); InvokeAsync(StateHasChanged); }));
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}));
|
|
||||||
builder.AddAttribute(seq++, "Rows", 3);
|
builder.AddAttribute(seq++, "Rows", 3);
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderComboBoxEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings)
|
private void RenderComboBoxEditor(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings)
|
||||||
{
|
{
|
||||||
var currentValue = propertyInfo.GetValue(dataItem);
|
var value = propertyInfo.GetValue(dataItem);
|
||||||
var propertyType = propertyInfo.PropertyType;
|
var underlyingType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
|
||||||
var underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
|
var itemType = settings.Data?.GetType().GetGenericArguments().FirstOrDefault() ?? typeof(object);
|
||||||
|
|
||||||
var dataType = settings.Data?.GetType();
|
|
||||||
var itemType = typeof(object);
|
|
||||||
if (dataType?.IsGenericType == true)
|
|
||||||
{
|
|
||||||
var genericArgs = dataType.GetGenericArguments();
|
|
||||||
if (genericArgs.Length > 0)
|
|
||||||
itemType = genericArgs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (underlyingType == typeof(int))
|
if (underlyingType == typeof(int))
|
||||||
RenderComboBoxInt(builder, ref seq, dataItem, propertyInfo, settings, itemType, currentValue);
|
RenderComboBoxInt(builder, ref seq, dataItem, propertyInfo, settings, itemType, value);
|
||||||
else if (underlyingType == typeof(long))
|
else if (underlyingType == typeof(long))
|
||||||
RenderComboBoxLong(builder, ref seq, dataItem, propertyInfo, settings, itemType, currentValue);
|
RenderComboBoxLong(builder, ref seq, dataItem, propertyInfo, settings, itemType, value);
|
||||||
else if (underlyingType == typeof(Guid))
|
else if (underlyingType == typeof(Guid))
|
||||||
RenderComboBoxGuid(builder, ref seq, dataItem, propertyInfo, settings, itemType, currentValue);
|
RenderComboBoxGuid(builder, ref seq, dataItem, propertyInfo, settings, itemType, value);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var displayText = ResolveComboBoxDisplayText(settings, currentValue ?? new object()) ?? currentValue?.ToString() ?? string.Empty;
|
|
||||||
builder.OpenComponent<DxTextBox>(seq++);
|
builder.OpenComponent<DxTextBox>(seq++);
|
||||||
builder.AddAttribute(seq++, "Text", displayText);
|
builder.AddAttribute(seq++, "Text", ResolveComboBoxDisplayText(settings, value ?? new object()) ?? value?.ToString() ?? "");
|
||||||
builder.AddAttribute(seq++, "ReadOnly", true);
|
builder.AddAttribute(seq++, "ReadOnly", true);
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
@ -433,33 +309,16 @@
|
||||||
private void RenderComboBoxInt(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue)
|
private void RenderComboBoxInt(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var comboType = isNullable
|
var comboType = isNullable ? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(int?)) : typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(int));
|
||||||
? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(int?))
|
|
||||||
: typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(int));
|
|
||||||
|
|
||||||
builder.OpenComponent(seq++, comboType);
|
builder.OpenComponent(seq++, comboType);
|
||||||
builder.AddAttribute(seq++, "Data", settings.Data);
|
builder.AddAttribute(seq++, "Data", settings.Data);
|
||||||
builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName);
|
builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName);
|
||||||
builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName);
|
builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName);
|
||||||
|
builder.AddAttribute(seq++, "Value", isNullable ? currentValue as int? : (currentValue is int intVal ? intVal : 0));
|
||||||
if (isNullable)
|
builder.AddAttribute(seq++, "ValueChanged", isNullable
|
||||||
{
|
? EventCallback.Factory.Create<int?>(this, v => { propertyInfo.SetValue(dataItem, v); StateHasChanged(); })
|
||||||
builder.AddAttribute(seq++, "Value", currentValue as int?);
|
: EventCallback.Factory.Create<int>(this, v => { propertyInfo.SetValue(dataItem, v); StateHasChanged(); }));
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<int?>(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<int>(this, newValue =>
|
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
StateHasChanged();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto);
|
builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto);
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
@ -467,33 +326,16 @@
|
||||||
private void RenderComboBoxLong(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue)
|
private void RenderComboBoxLong(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var comboType = isNullable
|
var comboType = isNullable ? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(long?)) : typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(long));
|
||||||
? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(long?))
|
|
||||||
: typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(long));
|
|
||||||
|
|
||||||
builder.OpenComponent(seq++, comboType);
|
builder.OpenComponent(seq++, comboType);
|
||||||
builder.AddAttribute(seq++, "Data", settings.Data);
|
builder.AddAttribute(seq++, "Data", settings.Data);
|
||||||
builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName);
|
builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName);
|
||||||
builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName);
|
builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName);
|
||||||
|
builder.AddAttribute(seq++, "Value", isNullable ? currentValue as long? : (currentValue is long longVal ? longVal : 0L));
|
||||||
if (isNullable)
|
builder.AddAttribute(seq++, "ValueChanged", isNullable
|
||||||
{
|
? EventCallback.Factory.Create<long?>(this, v => { propertyInfo.SetValue(dataItem, v); StateHasChanged(); })
|
||||||
builder.AddAttribute(seq++, "Value", currentValue as long?);
|
: EventCallback.Factory.Create<long>(this, v => { propertyInfo.SetValue(dataItem, v); StateHasChanged(); }));
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<long?>(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<long>(this, newValue =>
|
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
StateHasChanged();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto);
|
builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto);
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
@ -501,53 +343,33 @@
|
||||||
private void RenderComboBoxGuid(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue)
|
private void RenderComboBoxGuid(RenderTreeBuilder builder, ref int seq, object dataItem, PropertyInfo propertyInfo, DxComboBoxSettings settings, Type itemType, object? currentValue)
|
||||||
{
|
{
|
||||||
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
var isNullable = Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null;
|
||||||
var comboType = isNullable
|
var comboType = isNullable ? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(Guid?)) : typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(Guid));
|
||||||
? typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(Guid?))
|
|
||||||
: typeof(DxComboBox<,>).MakeGenericType(itemType, typeof(Guid));
|
|
||||||
|
|
||||||
builder.OpenComponent(seq++, comboType);
|
builder.OpenComponent(seq++, comboType);
|
||||||
builder.AddAttribute(seq++, "Data", settings.Data);
|
builder.AddAttribute(seq++, "Data", settings.Data);
|
||||||
builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName);
|
builder.AddAttribute(seq++, "ValueFieldName", settings.ValueFieldName);
|
||||||
builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName);
|
builder.AddAttribute(seq++, "TextFieldName", settings.TextFieldName);
|
||||||
|
builder.AddAttribute(seq++, "Value", isNullable ? currentValue as Guid? : (currentValue is Guid guidVal ? guidVal : Guid.Empty));
|
||||||
if (isNullable)
|
builder.AddAttribute(seq++, "ValueChanged", isNullable
|
||||||
{
|
? EventCallback.Factory.Create<Guid?>(this, v => { propertyInfo.SetValue(dataItem, v); StateHasChanged(); })
|
||||||
builder.AddAttribute(seq++, "Value", currentValue as Guid?);
|
: EventCallback.Factory.Create<Guid>(this, v => { propertyInfo.SetValue(dataItem, v); StateHasChanged(); }));
|
||||||
builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create<Guid?>(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<Guid>(this, newValue =>
|
|
||||||
{
|
|
||||||
propertyInfo.SetValue(dataItem, newValue);
|
|
||||||
StateHasChanged();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto);
|
builder.AddAttribute(seq++, "ClearButtonDisplayMode", DataEditorClearButtonDisplayMode.Auto);
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private RenderFragment RenderCellContent(DxGridDataColumn column, object? value, string displayText, EditSettingsType settingsType)
|
private RenderFragment RenderCellContent(object? value, string displayText)
|
||||||
{
|
{
|
||||||
return builder =>
|
return builder =>
|
||||||
{
|
{
|
||||||
var seq = 0;
|
var seq = 0;
|
||||||
|
|
||||||
// View mode: simple span display with DevExpress theme styling
|
|
||||||
builder.OpenElement(seq++, "span");
|
builder.OpenElement(seq++, "span");
|
||||||
builder.AddAttribute(seq++, "class", GetViewModeCssClass(value, settingsType));
|
builder.AddAttribute(seq++, "class", "mg-info-panel-value");
|
||||||
builder.AddAttribute(seq++, "title", displayText);
|
builder.AddAttribute(seq++, "title", displayText);
|
||||||
|
|
||||||
// Special handling for boolean - show checkbox icon
|
|
||||||
if (value is bool boolValue)
|
if (value is bool boolValue)
|
||||||
{
|
{
|
||||||
builder.OpenElement(seq++, "span");
|
builder.OpenElement(seq++, "span");
|
||||||
builder.AddAttribute(seq++, "class", boolValue ? "dx-icon dx-icon-check text-success" : "dx-icon dx-icon-close text-muted");
|
builder.AddAttribute(seq++, "class", boolValue ? "dx-icon dx-icon-check" : "dx-icon dx-icon-close");
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -558,17 +380,4 @@
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetViewModeCssClass(object? value, EditSettingsType settingsType)
|
|
||||||
{
|
|
||||||
var baseCss = "mg-info-panel-value text-body";
|
|
||||||
|
|
||||||
return value switch
|
|
||||||
{
|
|
||||||
bool => $"{baseCss} mg-info-panel-value-bool",
|
|
||||||
decimal or double or float or int or long or short => $"{baseCss} mg-info-panel-value-numeric",
|
|
||||||
DateTime or DateOnly or TimeOnly => $"{baseCss} mg-info-panel-value-date",
|
|
||||||
_ => baseCss
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public interface IInfoPanelBase
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Non-generic version of the InfoPanel component
|
/// InfoPanel component for displaying and editing grid row details
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPanelBase
|
public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPanelBase
|
||||||
{
|
{
|
||||||
|
|
@ -102,8 +102,6 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(grid);
|
ArgumentNullException.ThrowIfNull(grid);
|
||||||
|
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData called - dataItem type: {dataItem?.GetType().Name ?? "null"}, visibleIndex: {visibleIndex}");
|
|
||||||
|
|
||||||
_currentGrid = grid;
|
_currentGrid = grid;
|
||||||
_currentDataItem = dataItem;
|
_currentDataItem = dataItem;
|
||||||
_focusedRowVisibleIndex = visibleIndex;
|
_focusedRowVisibleIndex = visibleIndex;
|
||||||
|
|
@ -113,21 +111,19 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
_isEditMode = false;
|
_isEditMode = false;
|
||||||
_editModel = null;
|
_editModel = null;
|
||||||
|
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - _currentDataItem is null: {_currentDataItem == null}, cast success: {dataItem != null && _currentDataItem != null}");
|
|
||||||
|
|
||||||
if (_currentGrid != null && _currentDataItem != null)
|
if (_currentGrid != null && _currentDataItem != null)
|
||||||
{
|
{
|
||||||
_allDataColumns = GetAllDataColumns(_currentGrid);
|
_allDataColumns = GetAllDataColumns(_currentGrid);
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - loaded {_allDataColumns.Count} columns");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_allDataColumns = [];
|
_allDataColumns = [];
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - cleared columns (grid or dataItem is null)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] RefreshData - StateHasChanged called");
|
|
||||||
|
// Notify subscribers that data item changed
|
||||||
|
_ = OnDataItemChanged.InvokeAsync(dataItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -135,8 +131,6 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetEditMode(object editModel)
|
public void SetEditMode(object editModel)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] SetEditMode called - editModel type: {editModel?.GetType().Name ?? "null"}, grid.GridEditState: {_currentGrid?.GridEditState}");
|
|
||||||
|
|
||||||
_editModel = editModel;
|
_editModel = editModel;
|
||||||
_isEditMode = true;
|
_isEditMode = true;
|
||||||
_currentDataItem = _editModel;
|
_currentDataItem = _editModel;
|
||||||
|
|
@ -147,7 +141,6 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
}
|
}
|
||||||
|
|
||||||
InvokeAsync(StateHasChanged);
|
InvokeAsync(StateHasChanged);
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] SetEditMode - InvokeAsync(StateHasChanged) called, _isEditMode: {_isEditMode}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -155,13 +148,10 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ClearEditMode()
|
public void ClearEditMode()
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] ClearEditMode called, grid.GridEditState: {_currentGrid?.GridEditState}");
|
|
||||||
|
|
||||||
_isEditMode = false;
|
_isEditMode = false;
|
||||||
_editModel = null;
|
_editModel = null;
|
||||||
_editSettingsCache.Clear();
|
_editSettingsCache.Clear();
|
||||||
InvokeAsync(StateHasChanged);
|
InvokeAsync(StateHasChanged);
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] ClearEditMode - InvokeAsync(StateHasChanged) called");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -368,8 +358,6 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
{
|
{
|
||||||
var allColumns = grid.GetDataColumns();
|
var allColumns = grid.GetDataColumns();
|
||||||
|
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] GetAllDataColumns - grid type: {grid.GetType().Name}, columns count: {allColumns?.Count() ?? 0}");
|
|
||||||
|
|
||||||
if (allColumns != null)
|
if (allColumns != null)
|
||||||
{
|
{
|
||||||
foreach (var column in allColumns)
|
foreach (var column in allColumns)
|
||||||
|
|
@ -378,17 +366,15 @@ public partial class MgGridInfoPanel : ComponentBase, IAsyncDisposable, IInfoPan
|
||||||
!string.IsNullOrWhiteSpace(dataColumn.FieldName))
|
!string.IsNullOrWhiteSpace(dataColumn.FieldName))
|
||||||
{
|
{
|
||||||
columns.Add(dataColumn);
|
columns.Add(dataColumn);
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] - Column: {dataColumn.FieldName}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] GetAllDataColumns error: {ex.Message}");
|
// Ignore errors
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Diagnostics.Debug.WriteLine($"[InfoPanel] GetAllDataColumns result: {columns.Count} columns");
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace AyCode.Blazor.Components.Components.Grids;
|
||||||
|
|
||||||
|
public class MgGridInfoPanelHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace AyCode.Blazor.Components.Components.Grids;
|
||||||
|
|
||||||
|
public class MgGridToolbarHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace AyCode.Blazor.Components.Components;
|
||||||
|
|
||||||
|
public class MgComponentsHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,99 +1,105 @@
|
||||||
/* MgGridInfoPanel styles - Global CSS for proper container query support */
|
/* MgGridInfoPanel styles - DevExpress theme compatible */
|
||||||
|
|
||||||
/* Main panel - contained within splitter pane */
|
/* Main panel - uses DevExpress theme variables */
|
||||||
.mg-grid-info-panel {
|
.mg-grid-info-panel {
|
||||||
container-type: inline-size;
|
container-type: inline-size;
|
||||||
container-name: infopanel;
|
container-name: infopanel;
|
||||||
background-color: var(--dxbl-bg-secondary, #f8f9fa);
|
background-color: var(--dxbl-bg-secondary);
|
||||||
transition: background-color 0.3s ease, border-color 0.3s ease;
|
color: var(--dxbl-text);
|
||||||
|
font-family: var(--dxbl-font-family);
|
||||||
|
font-size: var(--dxbl-font-size);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
border-left: 1px solid var(--dxbl-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mg-grid-info-panel.edit-mode {
|
.mg-grid-info-panel.edit-mode {
|
||||||
background-color: #fffbeb !important;
|
background-color: var(--dxbl-warning-bg, #fffbeb);
|
||||||
border-left: 3px solid #f59e0b !important;
|
border-left: 3px solid var(--dxbl-warning, #f59e0b);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mg-grid-info-panel.view-mode {
|
/* Header styling */
|
||||||
background-color: #f8f9fa !important;
|
.mg-grid-info-panel .mg-info-panel-header {
|
||||||
border-left: 3px solid transparent !important;
|
padding: var(--dxbl-spacer-sm) var(--dxbl-spacer);
|
||||||
|
background-color: var(--dxbl-bg);
|
||||||
|
border-bottom: 1px solid var(--dxbl-border-color);
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Content area - scrollable, takes remaining space */
|
/* Toolbar styling */
|
||||||
|
.mg-info-panel-toolbar {
|
||||||
|
padding: var(--dxbl-spacer-xs) var(--dxbl-spacer-sm);
|
||||||
|
background-color: var(--dxbl-bg);
|
||||||
|
border-bottom: 1px solid var(--dxbl-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content area - scrollable */
|
||||||
.mg-info-panel-content {
|
.mg-info-panel-content {
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
padding: 1rem;
|
padding: var(--dxbl-spacer);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grid layout with responsive column wrapping based on panel width */
|
/* Grid layout for columns */
|
||||||
.mg-info-panel-grid {
|
.mg-info-panel-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 0.75rem;
|
gap: var(--dxbl-spacer-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fixed column count classes - override responsive behavior */
|
/* Fixed column count classes */
|
||||||
.mg-columns-1 .mg-info-panel-grid {
|
.mg-columns-1 .mg-info-panel-grid { grid-template-columns: 1fr !important; }
|
||||||
grid-template-columns: 1fr !important;
|
.mg-columns-2 .mg-info-panel-grid { grid-template-columns: repeat(2, 1fr) !important; }
|
||||||
}
|
.mg-columns-3 .mg-info-panel-grid { grid-template-columns: repeat(3, 1fr) !important; }
|
||||||
|
.mg-columns-4 .mg-info-panel-grid { grid-template-columns: repeat(4, 1fr) !important; }
|
||||||
.mg-columns-2 .mg-info-panel-grid {
|
|
||||||
grid-template-columns: repeat(2, 1fr) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mg-columns-3 .mg-info-panel-grid {
|
|
||||||
grid-template-columns: repeat(3, 1fr) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mg-columns-4 .mg-info-panel-grid {
|
|
||||||
grid-template-columns: repeat(4, 1fr) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive layouts using container queries */
|
/* Responsive layouts using container queries */
|
||||||
/* 2 columns for medium width (>= 400px) */
|
|
||||||
@container infopanel (min-width: 400px) {
|
@container infopanel (min-width: 400px) {
|
||||||
.mg-grid-info-panel:not(.mg-columns-1):not(.mg-columns-2):not(.mg-columns-3):not(.mg-columns-4) .mg-info-panel-grid {
|
.mg-grid-info-panel:not(.mg-columns-1):not(.mg-columns-2):not(.mg-columns-3):not(.mg-columns-4) .mg-info-panel-grid {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3 columns for wider panels (>= 800px) */
|
|
||||||
@container infopanel (min-width: 800px) {
|
@container infopanel (min-width: 800px) {
|
||||||
.mg-grid-info-panel:not(.mg-columns-1):not(.mg-columns-2):not(.mg-columns-3):not(.mg-columns-4) .mg-info-panel-grid {
|
.mg-grid-info-panel:not(.mg-columns-1):not(.mg-columns-2):not(.mg-columns-3):not(.mg-columns-4) .mg-info-panel-grid {
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4 columns for very wide panels (>= 1300px) */
|
|
||||||
@container infopanel (min-width: 1300px) {
|
@container infopanel (min-width: 1300px) {
|
||||||
.mg-grid-info-panel:not(.mg-columns-1):not(.mg-columns-2):not(.mg-columns-3):not(.mg-columns-4) .mg-info-panel-grid {
|
.mg-grid-info-panel:not(.mg-columns-1):not(.mg-columns-2):not(.mg-columns-3):not(.mg-columns-4) .mg-info-panel-grid {
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Grid item */
|
||||||
.mg-info-panel-item {
|
.mg-info-panel-item {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toolbar styling */
|
/* Label styling */
|
||||||
.mg-info-panel-toolbar {
|
.mg-info-panel-label {
|
||||||
padding: 0.25rem 0.5rem;
|
display: block;
|
||||||
background-color: var(--dxbl-bg, #fff);
|
margin-bottom: var(--dxbl-spacer-xs);
|
||||||
|
font-size: calc(var(--dxbl-font-size) * 0.875);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--dxbl-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* View mode value styling - simple span with DevExpress theme */
|
.mg-info-panel-label.editable {
|
||||||
|
color: var(--dxbl-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* View mode value styling */
|
||||||
.mg-info-panel-value {
|
.mg-info-panel-value {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0.25rem 0;
|
padding: var(--dxbl-spacer-xs) 0;
|
||||||
font-size: var(--dxbl-font-size, 0.875rem);
|
color: var(--dxbl-text);
|
||||||
color: var(--dxbl-text, #212529);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
@ -107,13 +113,59 @@
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Empty state */
|
||||||
|
.mg-info-panel-empty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
color: var(--dxbl-text-muted);
|
||||||
|
padding: var(--dxbl-spacer-lg);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables inside info panel */
|
||||||
|
.mg-info-panel-content table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: var(--dxbl-font-size);
|
||||||
|
color: var(--dxbl-text);
|
||||||
|
margin-bottom: var(--dxbl-spacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mg-info-panel-content table th,
|
||||||
|
.mg-info-panel-content table td {
|
||||||
|
padding: var(--dxbl-spacer-xs) var(--dxbl-spacer-sm);
|
||||||
|
border: 1px solid var(--dxbl-border-color);
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mg-info-panel-content table th {
|
||||||
|
background-color: var(--dxbl-bg-secondary);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--dxbl-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mg-info-panel-content table tbody tr:nth-child(odd) {
|
||||||
|
background-color: var(--dxbl-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mg-info-panel-content table tbody tr:nth-child(even) {
|
||||||
|
background-color: var(--dxbl-bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mg-info-panel-content table tbody tr:hover {
|
||||||
|
background-color: var(--dxbl-row-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
/* Splitter pane styling */
|
/* Splitter pane styling */
|
||||||
.mg-grid-with-info-panel {
|
.mg-grid-with-info-panel {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mg-info-panel-pane {
|
.mg-info-panel-pane {
|
||||||
background-color: var(--dxbl-bg-secondary, #f8f9fa);
|
background-color: var(--dxbl-bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fullscreen window styling */
|
/* Fullscreen window styling */
|
||||||
|
|
@ -140,15 +192,12 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mg-fullscreen-content .mg-grid-with-info-panel {
|
.mg-fullscreen-content .mg-grid-with-info-panel,
|
||||||
|
.mg-fullscreen-content .dxbl-grid {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mg-fullscreen-content .dxbl-grid {
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fullscreen icon classes */
|
/* Fullscreen icon classes */
|
||||||
.grid-fullscreen::before {
|
.grid-fullscreen::before {
|
||||||
content: "\e90c";
|
content: "\e90c";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue