using System.ComponentModel; using AyCode.Core; using AyCode.Core.Enums; using AyCode.Core.Extensions; using AyCode.Core.Helpers; using AyCode.Core.Interfaces; using AyCode.Interfaces.Entities; using AyCode.Services.SignalRs; using AyCode.Utils.Extensions; using DevExpress.Blazor; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using TIAMWebApp.Shared.Application.Services; using TIAMWebApp.Shared.Application.Utility; namespace TIAMSharedUI.Shared.Components.Grids { public class GridDataItemChangingEventArgs : GridDataItemChangedEventArgs where TDataItem : class, IId { internal GridDataItemChangingEventArgs(TiamGrid grid, TDataItem dataItem, DataChangeMode dataChangeMode) : base(grid, dataItem, dataChangeMode) { } public bool IsCanceled { get; set; } } public class GridDataItemChangedEventArgs where TDataItem : class, IId { internal GridDataItemChangedEventArgs(TiamGrid grid, TDataItem dataItem, DataChangeMode dataChangeMode) { Grid = grid; DataItem = dataItem; DataChangeMode = dataChangeMode; } public TiamGrid Grid { get; } public TDataItem DataItem { get; } public DataChangeMode DataChangeMode { get; } } public class TiamGrid : DxGrid where TDataItem : class, IId { protected bool IsFirstInitializeParameters; private IList _dataSource = null!; private string _gridLogName; public TiamGrid() : base() { } [Parameter] public LoggerClient Logger { get; set; } [Parameter] public string GridName { get; set; } [Parameter] public Guid? ContextId { get; set; } [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 OnDataItemDeleting { get; set; } protected new EventCallback EditModelSaving { get; set; } [Parameter] public EventCallback OnEditModelSaving { get; set; } [Parameter] public EventCallback> OnDataSourceChanged { get; set; } [Parameter] public EventCallback> OnDataItemChanging { get; set; } [Parameter] public EventCallback> OnDataItemChanged { 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 { if (value == null) throw new ArgumentNullException(nameof(value)); var equals = Equals(_dataSource, value); _dataSource = value; Data = _dataSource; if (!equals) OnDataSourceChanged.InvokeAsync(_dataSource); } } protected override void OnInitialized() { if (Logger == null) throw new NullReferenceException($"[{GetType().Name}] Logger == null"); if (SignalRClient == null) Logger.Error($"[{GetType().Name}] SignalRClient == null"); base.OnInitialized(); } protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (firstRender) { if (_dataSource == null || _dataSource.Count == 0) RefreshDataSourceAsync().Forget(); //AutoFitColumnWidths(); } } public Task AddDataItem(TDataItem dataItem) => AddDataItem(dataItem, AddMessageTag); public Task AddDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Add); public Task UpdateDataItem(TDataItem dataItem) => UpdateDataItem(dataItem, UpdateMessageTag); public Task UpdateDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Update); public Task RemoveDataItem(TDataItem dataItem) => RemoveDataItem(dataItem, RemoveMessageTag); public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Remove); public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag); public Task RemoveDataItem(Guid id, int messageTag) { var dataItem = _dataSource.FirstOrDefault(x => x.Id == id); return dataItem == null ? Task.CompletedTask : RemoveDataItem(dataItem); } private async Task OnItemSaving(GridEditModelSavingEventArgs e) { var dataItem = (e.EditModel as TDataItem)!; var logText = e.IsNew ? "add" : "update"; Logger.Info($"{_gridLogName} OnItemSaving {logText}; Id: {dataItem.Id}"); await OnEditModelSaving.InvokeAsync(e); if (e.Cancel) { Logger.Debug($"{_gridLogName} OnItemSaving {logText} canceled; Id: {dataItem.Id}"); return; } if (e.IsNew) await AddDataItem(dataItem); else await UpdateDataItem(dataItem); } private async Task OnItemDeleting(GridDataItemDeletingEventArgs e) { Logger.Info($"{_gridLogName} OnItemDeleting"); await OnDataItemDeleting.InvokeAsync(e); if (e.Cancel) { Logger.Debug($"{_gridLogName} OnItemDeleting canceled"); return; } var dataItem = (e.DataItem as TDataItem)!; await RemoveDataItem(dataItem); } public virtual Task RefreshDataSourceAsync() { if (GetAllMessageTag == 0) return Task.CompletedTask; Logger.Info($"{_gridLogName} RefreshDataSourceAsync called"); return SignalRClient.GetAllAsync>(GetAllMessageTag, ContextId, response => { if (response.Status == SignalResponseStatus.Error) return; BeginUpdate(); DataSource = response.ResponseData ?? []; EndUpdate(); InvokeAsync(StateHasChanged).Forget(); }); } protected virtual async Task PostDataToServerAsync(TDataItem dataItem, int messageTag, DataChangeMode dataChangeMode) { var changingEventArgs = new GridDataItemChangingEventArgs(this, dataItem, dataChangeMode); await OnDataItemChanging.InvokeAsync(changingEventArgs); if (changingEventArgs.IsCanceled) { Logger.Debug($"{_gridLogName} OnDataItemChanging canceled"); return; } if (messageTag == 0) return; Logger.Info($"{_gridLogName} PostDataToServerAsync called; transferId " + dataItem.Id); if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid(); _dataSource.UpdateCollection(dataItem, dataChangeMode == DataChangeMode.Remove); //egyből látszódik a változás a grid-ben, nem csak a callback lefutásakor! felhasználóbarátabb... - J. SignalRClient.PostDataAsync(messageTag, dataItem, async response => { if (response.Status != SignalResponseStatus.Success || response.ResponseData == null) { RefreshDataSourceAsync().Forget(); return; } _dataSource.UpdateCollection(response.ResponseData, dataChangeMode == DataChangeMode.Remove); var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, dataChangeMode); await OnDataItemChanged.InvokeAsync(changedEventArgs); InvokeAsync(StateHasChanged).Forget(); }).Forget(); //transfer = await devAdminSignalClient.PostDataAsync(SignalRTags.UpdateTransferAsync, transfer); } 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) { 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; //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}]"; } } }