From 9d0ee493ac4c0dfa6dcf6debcbb95edbc4a5998d Mon Sep 17 00:00:00 2001 From: Loretta Date: Thu, 6 Nov 2025 15:06:10 +0100 Subject: [PATCH] MgGridBase... --- .../Components/Grids/MgGridBase.cs | 367 ++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 AyCode.Blazor.Components/Components/Grids/MgGridBase.cs diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs b/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs new file mode 100644 index 0000000..84db1bc --- /dev/null +++ b/AyCode.Blazor.Components/Components/Grids/MgGridBase.cs @@ -0,0 +1,367 @@ +using System.ComponentModel; +using AyCode.Core; +using AyCode.Core.Enums; +using AyCode.Core.Extensions; +using AyCode.Core.Helpers; +using AyCode.Core.Interfaces; +using AyCode.Core.Loggers; +using AyCode.Services.Server.SignalRs; +using AyCode.Services.SignalRs; +using AyCode.Utils.Extensions; +using DevExpress.Blazor; +using Microsoft.AspNetCore.Components; + +namespace AyCode.Blazor.Components.Components.Grids; + +public interface IMgGridBase +{ + +} + +public abstract class MgGridBase : DxGrid, IMgGridBase + where TSignalRDataSource : AcSignalRDataSource where TDataItem : class, IId where TLoggerClient : AcLoggerBase +{ + protected bool IsFirstInitializeParameters; + private TSignalRDataSource _dataSource = null!; + private IList _dataSourceParam = []; + private string _gridLogName; + + public MgGridBase() : base() + { + } + + [Parameter] public TLoggerClient Logger { get; set; } + [Parameter] public string GridName { get; set; } + [Parameter] public object[]? ContextIds { get; set; } + + private string? _filterText = null; + + [Parameter] + public string? FilterText + { + get => _filterText; + set + { + _filterText = value; + + if (_dataSource != null! && _dataSource.FilterText != value) + { + _dataSource.FilterText = value; + ReloadDataSourceAsync().Forget(); + } + } + } + + [Parameter] public AcSignalRClientBase SignalRClient { get; set; } + + [Parameter] public int GetAllMessageTag { get; set; } + [Parameter] public int GetItemMessageTag { get; set; } + [Parameter] public int AddMessageTag { get; set; } + [Parameter] public int UpdateMessageTag { get; set; } + [Parameter] public int RemoveMessageTag { get; set; } + + protected new EventCallback DataItemDeleting { get; set; } + [Parameter] public EventCallback OnGridItemDeleting { get; set; } + + protected new EventCallback EditModelSaving { get; set; } + [Parameter] public EventCallback OnGridEditModelSaving { get; set; } + + [Parameter] public EventCallback> OnDataSourceChanged { get; set; } + [Parameter] public EventCallback> OnGridItemChanging { get; set; } + + /// + /// After the server has responded! + /// + [Parameter] + public EventCallback> OnGridItemChanged { get; set; } + + [Parameter] + [DefaultValue(null)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "BL0007:Component parameters should be auto properties", Justification = "")] + public IList DataSource + { + get + { + if (_dataSource == null && Data != null) + { + Logger.Error($"{_gridLogName} Use the DataSource parameter instead of Data!"); + throw new NullReferenceException($"{_gridLogName} Use the DataSource parameter instead of Data!"); + } + + return _dataSource!; + } + set + { + _dataSourceParam = value; + + if (_dataSource != null! && _dataSourceParam is List workingReferenceList) + _dataSource.SetWorkingReferenceList(workingReferenceList); + } + } + + protected override async Task OnInitializedAsync() + { + if (Logger == null) + throw new NullReferenceException($"[{GetType().Name}] Logger == null"); + + if (SignalRClient == null) + { + Logger.Error($"[{GetType().Name}] SignalRClient == null"); + throw new NullReferenceException($"[{GetType().Name}] SignalRClient == null"); + } + + var crudTags = new SignalRCrudTags(GetAllMessageTag, GetItemMessageTag, AddMessageTag, UpdateMessageTag, RemoveMessageTag); + + _dataSource =(TSignalRDataSource)Activator.CreateInstance(typeof(TSignalRDataSource), SignalRClient, crudTags, ContextIds)!; + _dataSource.FilterText = FilterText; + //_dataSource = new SignalRDataSource(SignalRClient, crudTags, ContextIds) { FilterText = FilterText }; + + Data = _dataSource; + + _dataSource.OnDataSourceLoaded += OnDataSourceLoaded; + _dataSource.OnDataSourceItemChanged += OnDataSourceItemChanged; + + await base.OnInitializedAsync(); + } + + private async Task OnDataSourceItemChanged(ItemChangedEventArgs args) + { + if (args.TrackingState is TrackingState.GetAll or TrackingState.None) return; + + Logger.Debug($"{_gridLogName} OnDataSourceItemChanged; trackingState: {args.TrackingState}"); + + var changedEventArgs = new GridDataItemChangedEventArgs(this, args.Item, args.TrackingState); + await OnGridItemChanged.InvokeAsync(changedEventArgs); + + if (!changedEventArgs.CancelStateChangeInvoke) + { + //BeginUpdate(); + await InvokeAsync(StateHasChanged); //TODO: bezárja a DetailRow-t! pl: az email-nél IsReaded=true update... - J. + //EndUpdate(); + } + } + + private Task OnDataSourceLoaded() + { + Logger.Debug($"{_gridLogName} OnDataSourceLoaded; Count: {_dataSource.Count}"); + + Reload(); + //_dataSource.LoadItem(_dataSource.First().Id).Forget(); + return OnDataSourceChanged.InvokeAsync(_dataSource); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + if (_dataSourceParam != null!) await _dataSource.LoadDataSource(_dataSourceParam, true, true); + else _dataSource.LoadDataSourceAsync(true).Forget(); + } + + await base.OnAfterRenderAsync(firstRender); + } + + public Task AddDataItem(TDataItem dataItem) + { + if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid(); + return _dataSource.Add(dataItem, true); + } + + public Task AddDataItemAsync(TDataItem dataItem) + { + if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid(); + _dataSource.Add(dataItem); + + return SaveChangesToServerAsync(); + } + + private async Task OnItemSaving(GridEditModelSavingEventArgs e) + { + var dataItem = (e.EditModel as TDataItem)!; + + if (e.IsNew && dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid(); + + var logText = e.IsNew ? "add" : "update"; + Logger.Debug($"{_gridLogName} OnItemSaving {logText}; Id: {dataItem.Id}"); + + await OnGridEditModelSaving.InvokeAsync(e); + + if (e.Cancel) + { + Logger.Debug($"{_gridLogName} OnItemSaving {logText} canceled; Id: {dataItem.Id}"); + return; + } + + if (e.IsNew) await AddDataItemAsync(dataItem); + else await UpdateDataItemAsync(dataItem); + + _dataSource.UpdateCollection(dataItem, false); + } + + private Task SaveChangesToServerAsync() + { + try + { + return _dataSource.SaveChangesAsync(); + } + catch (Exception ex) + { + Logger.Error($"{_gridLogName} SaveChangesToServerAsync->SaveChangesAsync error!", ex); + } + + return Task.CompletedTask; + } + + private async Task SaveChangesToServer() + { + var result = false; + + try + { + var unsavedItems = await _dataSource.SaveChanges(); + + if ((result = unsavedItems.Count == 0) == false) + Logger.Error($"{_gridLogName} SaveChangesToServer->SaveChanges error! unsavedCount: {unsavedItems.Count}"); + } + catch (Exception ex) + { + Logger.Error($"{_gridLogName} OnItemSaving", ex); + } + + return result; + } + + private async Task OnItemDeleting(GridDataItemDeletingEventArgs e) + { + Logger.Debug($"{_gridLogName} OnItemDeleting"); + + await OnGridItemDeleting.InvokeAsync(e); + + if (e.Cancel) + { + Logger.Debug($"{_gridLogName} OnItemDeleting canceled"); + return; + } + + var dataItem = (e.DataItem as TDataItem)!; + await RemoveDataItem(dataItem); + } + + private void OnCustomizeElement(GridCustomizeElementEventArgs e) + { + if (e.ElementType == GridElementType.DetailCell) + { + e.Style = "padding: 0.5rem; opacity: 0.75"; + } + else if (false && e.ElementType == GridElementType.DataCell && e.Column.Name == nameof(IId.Id)) + { + e.Column.Visible = AcDomain.IsDeveloperVersion; + e.Column.ShowInColumnChooser = AcDomain.IsDeveloperVersion; + } + } + + protected override Task SetParametersAsyncCore(ParameterView parameters) + { + if (!IsFirstInitializeParameters) + { + //if (typeof(TDataItem) is IId || typeof(TDataItem) is IId) + KeyFieldName = "Id"; + + base.DataItemDeleting = EventCallback.Factory.Create(this, OnItemDeleting); + base.EditModelSaving = EventCallback.Factory.Create(this, OnItemSaving); + + CustomizeElement += OnCustomizeElement; + + //ShowFilterRow = true; + //PageSize = 4; + //ShowGroupPanel = true; + //AllowSort = false; + + TextWrapEnabled = false; + AllowSelectRowByClick = true; + HighlightRowOnHover = true; + AutoCollapseDetailRow = true; + AutoExpandAllGroupRows = false; + //KeyboardNavigationEnabled = true; + + //var dataColumns = GetDataColumns(); + + //var idColumn = dataColumns.FirstOrDefault(x => x.FieldName == nameof(IId.Id)); + //if (idColumn != null) + //{ + // idColumn.ShowInColumnChooser = AcDomain.IsDeveloperVersion; + // idColumn.Visible = !AcDomain.IsDeveloperVersion; + //} + + IsFirstInitializeParameters = true; + } + + return base.SetParametersAsyncCore(parameters); + } + + + protected override void OnParametersSet() + { + base.OnParametersSet(); + + if (GridName.IsNullOrWhiteSpace()) GridName = $"{typeof(TDataItem).Name}Grid"; + + _gridLogName = $"[{GridName}]"; + + } + + //public Task AddDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Add); + + public Task UpdateDataItem(TDataItem dataItem) => _dataSource.Update(dataItem, true); + + public Task UpdateDataItemAsync(TDataItem dataItem) + { + _dataSource.Update(dataItem, false); + return SaveChangesToServerAsync(); + } + //public Task UpdateDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Update); + + public Task AddOrUpdateDataItem(TDataItem dataItem) => _dataSource.AddOrUpdate(dataItem, true); + + public Task RemoveDataItem(TDataItem dataItem) => _dataSource.Remove(dataItem, true); + //public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Remove); + + public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag); + + public Task RemoveDataItem(Guid id, int messageTag) + { + var dataItem = _dataSource.FirstOrDefault(x => x.Id == id); + if (dataItem == null) return Task.CompletedTask; + + return _dataSource.Remove(dataItem, true); + } + + public Task ReloadDataSourceAsync() + { + return _dataSource.LoadDataSourceAsync(false); + } +} + +public class GridDataItemChangingEventArgs : GridDataItemChangedEventArgs where TDataItem : class, IId +{ + internal GridDataItemChangingEventArgs(IMgGridBase grid, TDataItem dataItem, TrackingState trackingState) : base(grid, dataItem, trackingState) + { + } + + public bool IsCanceled { get; set; } +} + +public class GridDataItemChangedEventArgs where TDataItem : class, IId +{ + internal GridDataItemChangedEventArgs(IMgGridBase grid, TDataItem dataItem, TrackingState trackingState) + { + Grid = grid ?? throw new ArgumentNullException(nameof(grid)); + DataItem = dataItem; + TrackingState = trackingState; + } + + public IMgGridBase Grid { get; } + public TDataItem DataItem { get; } + public TrackingState TrackingState { get; } + public bool CancelStateChangeInvoke { get; set; } +} \ No newline at end of file