我在一个页面上有两个自定义组件;一个月选择器和一个网格。这两个组件各自都能很好地工作。网格正在显示来自API的项目,我可以通过提供开始和结束日期来请求日期范围之间的项目。我已经实现了一个月选择器模块,这将允许我按月导航所有项目。MonthPicker picker实现了一个Event Callback(事件回调),它将在每次请求发生变化时执行请求。
下面是我所拥有的,它当前有效。
Index.razor:
<MonthPicker @ref="MonthPicker1" DefaultMonth=07 DefaultYear=2021 OnMonthPickerChange="OnMonthPickerChange"></MonthPicker>
@if (listResponse is null || transactionClasses is null)
{
Loading...
}
else
{
<Grid Items="listResponse.Transactions" @ref="MyGrid" PageSize=40>
<GridBody Context="row">
<GridCell>@row.Item.Id</GridCell>
<GridCell>@row.Item.Description</GridCell>
</GridBody>
</Grid>
}
Index.razor.cs:
namespace Accounting.Web.Pages.Transactions
{
public partial class List : ComponentBase
{
[Inject]
private IHttpService HttpService { get; set; }
private Request.ListDto listRequest { get; set; } = new();
[Parameter]
public ResponseContext.ListDto listResponse { get; set; } = default!;
private MonthPicker MonthPicker1 { get; set; } = default!;
private Grid<ResponseContext.ItemDto> MyGrid { get; set; } = default!;
protected async override Task OnInitializedAsync()
{
listRequest.DateStart = DateTime.Parse("2021-07-01", new CultureInfo("en-GB", true));
listRequest.DateEnd = DateTime.Parse("2021-07-30", new CultureInfo("en-GB", true));
listResponse = await HttpService.Post<ResponseContext.ListDto>("http://localhost:4000/transactions/list", listRequest, true);
}
public async Task OnMonthPickerChange()
{
listResponse = null;
listRequest.DateStart = DateTime.Parse("2021-07-01", new CultureInfo("en-GB", true));
listRequest.DateEnd = DateTime.Parse("2021-07-30", new CultureInfo("en-GB", true));
listResponse = await HttpService.Post<ResponseContext.ListDto>("http://localhost:4000/transactions/list", listRequest, true);
System.Console.WriteLine(MonthPicker1.Month + " : " + MonthPicker1.Year);
}
}
}
然而,对于事件回调方法OnMonthPickerChange,最初我有以下内容:
public async void OnMonthPickerChange()
换句话说,我使用async void而不是Task。使用void会导致模板中的listResponse保持为空(用于呈现),因此当使用MonthPicker时,列表将显示为空。只是运气好,我决定尝试Task而不是void来解决这个问题,但我不知道为什么一个能工作,为什么另一个不能。
我希望有人能帮我解开这个谜团。
这是处理ComponentBase
中所有UI事件的实际代码。你的处理程序是callback
。
如果你不提供Task
,那么task
是空的,没有什么可等待的。只要你的处理程序是同步的,那就可以了。
然而,一旦你的处理程序产生,HandleEventAsync
在你的处理程序完成之前运行到完成。在更新数据之前,渲染已经发生了。一切都落后一步,
Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg)
{
var task = callback.InvokeAsync(arg);
var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion &&
task.Status != TaskStatus.Canceled;
// After each event, we synchronously re-render (unless !ShouldRender())
// This just saves the developer the trouble of putting "StateHasChanged();"
// at the end of every event callback.
StateHasChanged();
return shouldAwaitTask ?
CallStateHasChangedOnAsyncCompletion(task) :
Task.CompletedTask;
}
// Only called if the original task yields and is therefore still running
private async Task CallStateHasChangedOnAsyncCompletion(Task task)
{
try
{
await task;
}
catch // avoiding exception filters for AOT runtime support
{
// Ignore exceptions from task cancellations, but don't bother issuing a state change.
if (task.IsCanceled)
{
return;
}
throw;
}
StateHasChanged();
}