Refactor grid logic into BandGridBase<TItem> base class

Move shared state and methods from CatalogsGrid and MassDataGrid into BandGridBase<TItem>. This centralizes edit context handling, validation, popup header logic, row editing/deleting, and layout feedback, reducing duplication and improving maintainability. Individual grid components now only override OnEditFieldChanged for custom validation.
This commit is contained in:
OlgunR
2026-04-20 10:52:05 +02:00
parent 0008fac1d2
commit cd0a824064
3 changed files with 61 additions and 104 deletions

View File

@@ -2,6 +2,7 @@
using DbFirst.BlazorWebApp.Services; using DbFirst.BlazorWebApp.Services;
using DevExpress.Blazor; using DevExpress.Blazor;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Rendering; using Microsoft.AspNetCore.Components.Rendering;
namespace DbFirst.BlazorWebApp.Components; namespace DbFirst.BlazorWebApp.Components;
@@ -27,6 +28,15 @@ public abstract class BandGridBase<TItem> : ComponentBase
protected SizeMode _sizeMode = SizeMode.Medium; protected SizeMode _sizeMode = SizeMode.Medium;
protected static readonly List<SizeMode> _sizeModes = Enum.GetValues<SizeMode>().ToList(); protected static readonly List<SizeMode> _sizeModes = Enum.GetValues<SizeMode>().ToList();
protected string? errorMessage;
protected string? infoMessage;
protected bool isLoading;
protected bool hasLoaded;
protected EditContext? editContext;
protected ValidationMessageStore? validationMessageStore;
protected string popupHeaderText = "Edit";
protected int _focusedVisibleIndex;
private const string LayoutType = "GRID_BANDS"; private const string LayoutType = "GRID_BANDS";
// --- Lifecycle --- // --- Lifecycle ---
@@ -216,4 +226,53 @@ public abstract class BandGridBase<TItem> : ComponentBase
builder.AddAttribute(seq++, "ReadOnly", true); builder.AddAttribute(seq++, "ReadOnly", true);
builder.CloseComponent(); builder.CloseComponent();
} }
protected void SetEditContext(EditContext context)
{
if (editContext == context) return;
if (editContext != null)
editContext.OnFieldChanged -= OnEditFieldChanged;
editContext = context;
validationMessageStore = new ValidationMessageStore(editContext);
editContext.OnFieldChanged += OnEditFieldChanged;
}
protected virtual void OnEditFieldChanged(object? sender, FieldChangedEventArgs e)
{
validationMessageStore?.Clear();
editContext?.NotifyValidationStateChanged();
}
protected void SetPopupHeaderText(bool isNew) => popupHeaderText = isNew ? "Neu" : "Edit";
protected async Task EditFocusedRow()
=> await gridRef!.StartEditRowAsync(_focusedVisibleIndex);
protected Task DeleteFocusedRow()
{
gridRef!.ShowRowDeleteConfirmation(_focusedVisibleIndex);
return Task.CompletedTask;
}
protected async Task SaveLayoutWithFeedbackAsync()
{
try
{
await SaveLayoutAsync();
infoMessage = "Layout gespeichert.";
errorMessage = null;
}
catch (Exception ex)
{
errorMessage = $"Layout konnte nicht gespeichert werden: {ex.Message}";
}
}
protected async Task ResetLayoutWithFeedbackAsync()
{
await ResetLayoutAsync();
infoMessage = "Layout zurückgesetzt.";
errorMessage = null;
}
} }

View File

@@ -149,14 +149,7 @@ else
@code { @code {
private List<CatalogReadDto> items = new(); private List<CatalogReadDto> items = new();
private bool isLoading;
private bool hasLoaded;
private string? errorMessage;
private string? infoMessage;
private EditContext? editContext;
private ValidationMessageStore? validationMessageStore;
private int? focusedRowKey; private int? focusedRowKey;
private string popupHeaderText = "Edit";
protected override string LayoutKey => "CatalogsGrid"; protected override string LayoutKey => "CatalogsGrid";
protected override bool ShowCommandColumn => false; protected override bool ShowCommandColumn => false;
@@ -209,17 +202,7 @@ else
} }
} }
private void SetEditContext(EditContext context) protected override void OnEditFieldChanged(object? sender, FieldChangedEventArgs e)
{
if (editContext == context) return;
if (editContext != null)
editContext.OnFieldChanged -= OnEditFieldChanged;
editContext = context;
validationMessageStore = new ValidationMessageStore(editContext);
editContext.OnFieldChanged += OnEditFieldChanged;
}
private void OnEditFieldChanged(object? sender, FieldChangedEventArgs e)
{ {
if (validationMessageStore == null || editContext == null) return; if (validationMessageStore == null || editContext == null) return;
@@ -237,8 +220,6 @@ else
} }
} }
private void SetPopupHeaderText(bool isNew) => popupHeaderText = isNew ? "Neu" : "Edit";
private void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e) private void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e)
{ {
popupHeaderText = e.IsNew ? "Neu" : "Edit"; popupHeaderText = e.IsNew ? "Neu" : "Edit";
@@ -378,36 +359,4 @@ else
public int Value { get; set; } public int Value { get; set; }
public string Text { get; set; } = string.Empty; public string Text { get; set; } = string.Empty;
} }
private int _focusedVisibleIndex;
private async Task EditFocusedRow()
=> await gridRef!.StartEditRowAsync(_focusedVisibleIndex);
private Task DeleteFocusedRow()
{
gridRef!.ShowRowDeleteConfirmation(_focusedVisibleIndex);
return Task.CompletedTask;
}
private async Task SaveLayoutWithFeedbackAsync()
{
try
{
await SaveLayoutAsync();
infoMessage = "Layout gespeichert.";
errorMessage = null;
}
catch (Exception ex)
{
errorMessage = $"Layout konnte nicht gespeichert werden: {ex.Message}";
}
}
private async Task ResetLayoutWithFeedbackAsync()
{
await ResetLayoutAsync();
infoMessage = "Layout zurückgesetzt.";
errorMessage = null;
}
} }

View File

@@ -175,16 +175,9 @@ else
@code { @code {
private List<MassDataReadDto> items = new(); private List<MassDataReadDto> items = new();
private bool isLoading;
private bool hasLoaded;
private string? errorMessage;
private string? infoMessage;
private int pageIndex; private int pageIndex;
private int pageCount = 1; private int pageCount = 1;
private int? pageSize = 100; private int? pageSize = 100;
private string popupHeaderText = "Edit";
private EditContext? editContext;
private ValidationMessageStore? validationMessageStore;
private int? focusedRowKey; private int? focusedRowKey;
protected override string LayoutKey => "MassDataGrid"; protected override string LayoutKey => "MassDataGrid";
@@ -259,17 +252,7 @@ else
await LoadPage(0); await LoadPage(0);
} }
private void SetEditContext(EditContext context) protected override void OnEditFieldChanged(object? sender, FieldChangedEventArgs e)
{
if (editContext == context) return;
if (editContext != null)
editContext.OnFieldChanged -= OnEditFieldChanged;
editContext = context;
validationMessageStore = new ValidationMessageStore(editContext);
editContext.OnFieldChanged += OnEditFieldChanged;
}
private void OnEditFieldChanged(object? sender, FieldChangedEventArgs e)
{ {
if (validationMessageStore == null || editContext == null) return; if (validationMessageStore == null || editContext == null) return;
if (e.FieldIdentifier.FieldName == nameof(MassDataEditModel.UpdateProcedure)) if (e.FieldIdentifier.FieldName == nameof(MassDataEditModel.UpdateProcedure))
@@ -285,8 +268,6 @@ else
} }
} }
private void SetPopupHeaderText(bool isNew) => popupHeaderText = isNew ? "Neu" : "Edit";
private void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e) private void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e)
{ {
if (e.IsNew) if (e.IsNew)
@@ -391,36 +372,4 @@ else
public int? Value { get; set; } public int? Value { get; set; }
public string Text { get; set; } = string.Empty; public string Text { get; set; } = string.Empty;
} }
private int _focusedVisibleIndex;
private async Task EditFocusedRow()
=> await gridRef!.StartEditRowAsync(_focusedVisibleIndex);
private Task DeleteFocusedRow()
{
gridRef!.ShowRowDeleteConfirmation(_focusedVisibleIndex);
return Task.CompletedTask;
}
private async Task SaveLayoutWithFeedbackAsync()
{
try
{
await SaveLayoutAsync();
infoMessage = "Layout gespeichert.";
errorMessage = null;
}
catch (Exception ex)
{
errorMessage = $"Layout konnte nicht gespeichert werden: {ex.Message}";
}
}
private async Task ResetLayoutWithFeedbackAsync()
{
await ResetLayoutAsync();
infoMessage = "Layout zurückgesetzt.";
errorMessage = null;
}
} }