@attribute [CascadingTypeParameter(nameof(T))] @typeparam T @ChildContent @code { [Parameter] public RenderFragment? ChildContent { get; set; } [Parameter] public required Func> DataSource { private get; set; } public T Data { get; private set; } public ComponentState ComponentState { get; private set; } = ComponentState.Loading; public event EventHandler? OnStateChanged; private bool reloadRequested = false; private Task? loadTask = null; private object loadLock = new(); protected override void OnInitialized() => Load(); public void Load() { lock(loadLock) { reloadRequested = true; if(loadTask is null || loadTask.IsCompleted) { //loadTask = Task.Run(LoadInternalAsync); loadTask = LoadInternalAsync(); } } } private async Task LoadInternalAsync() { while(true) { lock(loadLock) { if(!reloadRequested) break; reloadRequested = false; } //ComponentState = ComponentState.Loading; //await InvokeAsync(() => OnStateChanged?.Invoke(this, EventArgs.Empty)); //await InvokeAsync(() => StateHasChanged()); try { Data = await DataSource.Invoke(); ComponentState = ComponentState.Loaded; } catch { ComponentState = ComponentState.Error; } await InvokeAsync(() => OnStateChanged?.Invoke(this, EventArgs.Empty)); await InvokeAsync(() => StateHasChanged()); } } }