为什么 'InvokeAsync' 在 Blazor 组件中显示为错误?
Why does 'InvokeAsync' show as an error in a Blazor component?
我最近开始在我的 ASP.Net 核心网络应用程序中包含 Blazor 组件。我决定使用模式 [ComponentName].razor 和 [ComponentName].razor.cs 将我的组件拆分为多个文件,用于所有 C# 编码。
令人讨厌的是,我所有的状态更改通知调用都显示为错误。现在,当我构建和 运行 应用程序时,这些错误消失了,但它们仍然占据了我的错误列表 window。如果我关闭然后打开 Visual Studio 2019,它们就会消失,但它们会在几分钟后恢复。这是怎么回事,我该如何解决这些错误?
干杯!
InvokeAsync highlighted as an error
编辑:这是请求的一些代码。有问题的行在 TransactionTableView.razor.cs 中。 'await InvokeAsync(StateHasChanged)' 显示为错误。
TransactionTableView.razor
<table class="table data-table" id="taskstable">
<thead>
<tr>
@if (ShowSelect)
{
<th>
<input type="checkbox" @bind="SelectAllTransactions" @bind:event="oninput" @onclick="() => CheckAllTransactions(!SelectAllTransactions)"/>
Select all
</th>
}
@if (ShowParent)
{
<th>
Parent
</th>
}
<th>
Task
</th>
<th>
Status
</th>
<th>
Due Date
</th>
<th>
Completion Date
</th>
<th>
Amount Due
</th>
<th>
Amount Paid
</th>
<th>
Comments
</th>
</tr>
</thead>
<tbody class="tasks-body">
@if (Transactions != null)
{
@foreach (var transaction in DisplayTransactions)
{
<tr class="@transaction.AlertClassDisplay()">
@if (ShowSelect)
{
<td>
<input @bind="transaction.Select" type="checkbox" @oninput="() => SelectSingleTask(transaction.TransactionId)"/>
</td>
}
@if (ShowParent)
{
<td>
@transaction.TenementKey
</td>
}
<td>
@transaction.Description
</td>
<td class="task-status">
<a asp-action="Details" asp-controller="Alerts" method="get" asp-route-transactionId="@transaction.TransactionId">
@transaction.TransactionStatus
</a>
</td>
<td>
@transaction.DueDateDisplay()
</td>
<td>
@($"{transaction.CompletionDate:dd MMM yyyy}")
</td>
<td>
@transaction.AmountDue
</td>
<td>
@transaction.AmountPaid
</td>
<td>
@transaction.Comments
</td>
</tr>
}
}
</tbody>
</table>
TransactionTableView。razor.cs
partial class TransactionTableView
{
// Injected services
[Inject]
private ApplicationDbContext _context { get; set; }
// Data
public List<int> TenementIds { get; set; }
public List<TransactionViewModel> Transactions { get; set; }
public List<TransactionViewModel> DisplayTransactions { get; set; }
public List<Filter> Filters { get; set; } = new List<Filter>();
private bool ShowParent { get; set; } = true;
private bool ShowSelect { get; set; } = true;
private bool SelectAllTransactions { get; set; } = false;
public async Task Refresh()
{
var transactions = new List<Transaction>(_context.Transactions.Where(x => x.TenementId != null && TenementIds.Contains((int)x.TenementId)));
transactions = transactions.OrderBy(x => x.DueDate).ToList();
var models = new List<TransactionViewModel>();
transactions.ForEach(x =>
{
models.Add(x.GetViewModel(_context));
});
Transactions = models;
await RefreshFilters();
}
public async Task RefreshFilters()
{
var holder = Transactions;
if (Filters != null)
{
foreach (var filter in Filters)
{
if(filter.FilteringProperty.PropertyType == typeof(string))
{
holder = holder.Where(x => ((string)filter.FilteringProperty.GetValue(x)).ToLower().Contains(filter.Values.First().ToString().ToLower())).ToList();
}
if(filter.FilteringProperty.PropertyType == typeof(DateTime) || filter.FilteringProperty.PropertyType == (typeof(DateTime?)))
{
var dFilter = (DateFilter)filter;
if (dFilter.SelectedAfterDate)
{
holder = holder.Where(x => (DateTime)dFilter.FilteringProperty.GetValue(x) > dFilter.TargetDate).ToList();
}
else if (dFilter.SelectBeforeDate)
{
holder = holder.Where(x => (DateTime)dFilter.FilteringProperty.GetValue(x) < dFilter.TargetDate).ToList();
}
else if (dFilter.SelectBetweenDates)
{
holder = holder.Where(x =>
{
var targetDate = (DateTime)dFilter.FilteringProperty.GetValue(x);
return targetDate < dFilter.TargetDate && targetDate > (DateTime)dFilter.FirstTargetDate;
}).ToList();
}
}
if(filter.FilteringProperty.PropertyType == typeof(TransactionStatus))
{
var targetStatuses = filter.Values.Select(x => (TransactionStatus)x);
holder = holder.Where(x => targetStatuses.Contains(x.TransactionStatus)).ToList();
}
}
}
DisplayTransactions = holder;
await RefreshAllTaskSelector();
await InvokeAsync(StateHasChanged);
}
private async Task CheckAllTransactions(bool checkAll)
{
foreach(var displayTask in DisplayTransactions)
{
displayTask.Select = checkAll;
}
await InvokeAsync(StateHasChanged);
}
private async Task SelectSingleTask(int transactionId)
{
var task = DisplayTransactions.SingleOrDefault(x => x.TransactionId == transactionId);
task.Select = !task.Select;
if (DisplayTransactions.Any() && DisplayTransactions.Where(x => !x.Select).Count() == 0)
{
SelectAllTransactions = true;
}
else
{
SelectAllTransactions = false;
}
await InvokeAsync(StateHasChanged);
}
private async Task RefreshAllTaskSelector()
{
if (DisplayTransactions.Any() && DisplayTransactions.Where(x => !x.Select).Count() == 0)
{
SelectAllTransactions = true;
}
else
{
SelectAllTransactions = false;
}
}
private async Task DeleteSelected()
{
if (_context.ChangeTracker.HasChanges())
{
throw new ApplicationException("DB already has changes");
}
var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));
foreach(var target in targets)
{
Transactions.Remove(target);
DisplayTransactions.Remove(target);
var transaction = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
_context.Transactions.Remove(transaction);
}
await _context.SaveChangesAsync();
await InvokeAsync(StateHasChanged);
}
private async Task CompleteSelected()
{
if (_context.ChangeTracker.HasChanges())
{
throw new ApplicationException("DB already has changes");
}
var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));
foreach (var target in targets)
{
var dbTask = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
dbTask.CompletionDate = DateTime.Now;
dbTask.TransactionStatus = TransactionStatus.Completed;
target.CompletionDate = dbTask.CompletionDate;
target.TransactionStatus = dbTask.TransactionStatus;
var orig = Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
orig.CompletionDate = dbTask.CompletionDate;
orig.TransactionStatus = dbTask.TransactionStatus;
}
await _context.SaveChangesAsync();
await RefreshFilters();
await InvokeAsync(StateHasChanged);
}
private async Task ArchiveSelected()
{
if (_context.ChangeTracker.HasChanges())
{
throw new ApplicationException("DB already has changes");
}
var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));
foreach (var target in targets)
{
var dbTask = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
dbTask.CompletionDate = DateTime.Now;
dbTask.TransactionStatus = TransactionStatus.Archived;
target.CompletionDate = dbTask.CompletionDate;
target.TransactionStatus = dbTask.TransactionStatus;
var orig = Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
orig.CompletionDate = dbTask.CompletionDate;
orig.TransactionStatus = dbTask.TransactionStatus;
}
await _context.SaveChangesAsync();
await RefreshFilters();
await InvokeAsync(StateHasChanged);
}
}
我尝试了一个小测试项目,我可以确认您可能有 2 个问题:
- 你有 created/moved 代码隐藏文件 TransactionTableView.razor.cs 在另一个文件夹而不是 TransactionTableView.razor(正如 Henk 所说)没有指定
@inherits
路径
- 您还没有从
ComponentBase
中得出您的 class
如果你想分开两个不同文件夹中的两个文件你需要添加inherits
,就像这里:
EmployeeData.razor 在 Pages 文件夹中
@page "/employee/{Id}"
@using TestMenu.Shared
@using TestMenu.Client.Services
@inherits TestMenu.Client.Pages.test.EmployeeData
<h3>Employee</h3>
Result data: <b>@employeeData</b>
EmployeeData.razor.cs 在 Pages/test 文件夹
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using TestMenu.Client.Services;
using TestMenu.Shared;
namespace TestMenu.Client.Pages.test
{
public partial class EmployeeData: ComponentBase
{
[Inject] IEmployeeService EmployeeService { get; set; }
[Parameter]
public string Id { get; set; }
protected Employee Employee = new();
protected string employeeData;
protected override async Task OnInitializedAsync()
{
Employee = (await EmployeeService.GetEmployeeById(int.Parse(Id)));
employeeData = Employee.Name;
await InvokeAsync(StateHasChanged);
}
}
}
如果您从 EmployeeData.razor.cs 后面的代码中删除 : ComponentBase
,您会收到类似于屏幕截图中的错误。
我最近开始在我的 ASP.Net 核心网络应用程序中包含 Blazor 组件。我决定使用模式 [ComponentName].razor 和 [ComponentName].razor.cs 将我的组件拆分为多个文件,用于所有 C# 编码。
令人讨厌的是,我所有的状态更改通知调用都显示为错误。现在,当我构建和 运行 应用程序时,这些错误消失了,但它们仍然占据了我的错误列表 window。如果我关闭然后打开 Visual Studio 2019,它们就会消失,但它们会在几分钟后恢复。这是怎么回事,我该如何解决这些错误?
干杯!
InvokeAsync highlighted as an error
编辑:这是请求的一些代码。有问题的行在 TransactionTableView.razor.cs 中。 'await InvokeAsync(StateHasChanged)' 显示为错误。
TransactionTableView.razor
<table class="table data-table" id="taskstable">
<thead>
<tr>
@if (ShowSelect)
{
<th>
<input type="checkbox" @bind="SelectAllTransactions" @bind:event="oninput" @onclick="() => CheckAllTransactions(!SelectAllTransactions)"/>
Select all
</th>
}
@if (ShowParent)
{
<th>
Parent
</th>
}
<th>
Task
</th>
<th>
Status
</th>
<th>
Due Date
</th>
<th>
Completion Date
</th>
<th>
Amount Due
</th>
<th>
Amount Paid
</th>
<th>
Comments
</th>
</tr>
</thead>
<tbody class="tasks-body">
@if (Transactions != null)
{
@foreach (var transaction in DisplayTransactions)
{
<tr class="@transaction.AlertClassDisplay()">
@if (ShowSelect)
{
<td>
<input @bind="transaction.Select" type="checkbox" @oninput="() => SelectSingleTask(transaction.TransactionId)"/>
</td>
}
@if (ShowParent)
{
<td>
@transaction.TenementKey
</td>
}
<td>
@transaction.Description
</td>
<td class="task-status">
<a asp-action="Details" asp-controller="Alerts" method="get" asp-route-transactionId="@transaction.TransactionId">
@transaction.TransactionStatus
</a>
</td>
<td>
@transaction.DueDateDisplay()
</td>
<td>
@($"{transaction.CompletionDate:dd MMM yyyy}")
</td>
<td>
@transaction.AmountDue
</td>
<td>
@transaction.AmountPaid
</td>
<td>
@transaction.Comments
</td>
</tr>
}
}
</tbody>
</table>
TransactionTableView。razor.cs
partial class TransactionTableView
{
// Injected services
[Inject]
private ApplicationDbContext _context { get; set; }
// Data
public List<int> TenementIds { get; set; }
public List<TransactionViewModel> Transactions { get; set; }
public List<TransactionViewModel> DisplayTransactions { get; set; }
public List<Filter> Filters { get; set; } = new List<Filter>();
private bool ShowParent { get; set; } = true;
private bool ShowSelect { get; set; } = true;
private bool SelectAllTransactions { get; set; } = false;
public async Task Refresh()
{
var transactions = new List<Transaction>(_context.Transactions.Where(x => x.TenementId != null && TenementIds.Contains((int)x.TenementId)));
transactions = transactions.OrderBy(x => x.DueDate).ToList();
var models = new List<TransactionViewModel>();
transactions.ForEach(x =>
{
models.Add(x.GetViewModel(_context));
});
Transactions = models;
await RefreshFilters();
}
public async Task RefreshFilters()
{
var holder = Transactions;
if (Filters != null)
{
foreach (var filter in Filters)
{
if(filter.FilteringProperty.PropertyType == typeof(string))
{
holder = holder.Where(x => ((string)filter.FilteringProperty.GetValue(x)).ToLower().Contains(filter.Values.First().ToString().ToLower())).ToList();
}
if(filter.FilteringProperty.PropertyType == typeof(DateTime) || filter.FilteringProperty.PropertyType == (typeof(DateTime?)))
{
var dFilter = (DateFilter)filter;
if (dFilter.SelectedAfterDate)
{
holder = holder.Where(x => (DateTime)dFilter.FilteringProperty.GetValue(x) > dFilter.TargetDate).ToList();
}
else if (dFilter.SelectBeforeDate)
{
holder = holder.Where(x => (DateTime)dFilter.FilteringProperty.GetValue(x) < dFilter.TargetDate).ToList();
}
else if (dFilter.SelectBetweenDates)
{
holder = holder.Where(x =>
{
var targetDate = (DateTime)dFilter.FilteringProperty.GetValue(x);
return targetDate < dFilter.TargetDate && targetDate > (DateTime)dFilter.FirstTargetDate;
}).ToList();
}
}
if(filter.FilteringProperty.PropertyType == typeof(TransactionStatus))
{
var targetStatuses = filter.Values.Select(x => (TransactionStatus)x);
holder = holder.Where(x => targetStatuses.Contains(x.TransactionStatus)).ToList();
}
}
}
DisplayTransactions = holder;
await RefreshAllTaskSelector();
await InvokeAsync(StateHasChanged);
}
private async Task CheckAllTransactions(bool checkAll)
{
foreach(var displayTask in DisplayTransactions)
{
displayTask.Select = checkAll;
}
await InvokeAsync(StateHasChanged);
}
private async Task SelectSingleTask(int transactionId)
{
var task = DisplayTransactions.SingleOrDefault(x => x.TransactionId == transactionId);
task.Select = !task.Select;
if (DisplayTransactions.Any() && DisplayTransactions.Where(x => !x.Select).Count() == 0)
{
SelectAllTransactions = true;
}
else
{
SelectAllTransactions = false;
}
await InvokeAsync(StateHasChanged);
}
private async Task RefreshAllTaskSelector()
{
if (DisplayTransactions.Any() && DisplayTransactions.Where(x => !x.Select).Count() == 0)
{
SelectAllTransactions = true;
}
else
{
SelectAllTransactions = false;
}
}
private async Task DeleteSelected()
{
if (_context.ChangeTracker.HasChanges())
{
throw new ApplicationException("DB already has changes");
}
var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));
foreach(var target in targets)
{
Transactions.Remove(target);
DisplayTransactions.Remove(target);
var transaction = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
_context.Transactions.Remove(transaction);
}
await _context.SaveChangesAsync();
await InvokeAsync(StateHasChanged);
}
private async Task CompleteSelected()
{
if (_context.ChangeTracker.HasChanges())
{
throw new ApplicationException("DB already has changes");
}
var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));
foreach (var target in targets)
{
var dbTask = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
dbTask.CompletionDate = DateTime.Now;
dbTask.TransactionStatus = TransactionStatus.Completed;
target.CompletionDate = dbTask.CompletionDate;
target.TransactionStatus = dbTask.TransactionStatus;
var orig = Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
orig.CompletionDate = dbTask.CompletionDate;
orig.TransactionStatus = dbTask.TransactionStatus;
}
await _context.SaveChangesAsync();
await RefreshFilters();
await InvokeAsync(StateHasChanged);
}
private async Task ArchiveSelected()
{
if (_context.ChangeTracker.HasChanges())
{
throw new ApplicationException("DB already has changes");
}
var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));
foreach (var target in targets)
{
var dbTask = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
dbTask.CompletionDate = DateTime.Now;
dbTask.TransactionStatus = TransactionStatus.Archived;
target.CompletionDate = dbTask.CompletionDate;
target.TransactionStatus = dbTask.TransactionStatus;
var orig = Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
orig.CompletionDate = dbTask.CompletionDate;
orig.TransactionStatus = dbTask.TransactionStatus;
}
await _context.SaveChangesAsync();
await RefreshFilters();
await InvokeAsync(StateHasChanged);
}
}
我尝试了一个小测试项目,我可以确认您可能有 2 个问题:
- 你有 created/moved 代码隐藏文件 TransactionTableView.razor.cs 在另一个文件夹而不是 TransactionTableView.razor(正如 Henk 所说)没有指定
@inherits
路径 - 您还没有从
ComponentBase
中得出您的 class
如果你想分开两个不同文件夹中的两个文件你需要添加inherits
,就像这里:
EmployeeData.razor 在 Pages 文件夹中
@page "/employee/{Id}"
@using TestMenu.Shared
@using TestMenu.Client.Services
@inherits TestMenu.Client.Pages.test.EmployeeData
<h3>Employee</h3>
Result data: <b>@employeeData</b>
EmployeeData.razor.cs 在 Pages/test 文件夹
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using TestMenu.Client.Services;
using TestMenu.Shared;
namespace TestMenu.Client.Pages.test
{
public partial class EmployeeData: ComponentBase
{
[Inject] IEmployeeService EmployeeService { get; set; }
[Parameter]
public string Id { get; set; }
protected Employee Employee = new();
protected string employeeData;
protected override async Task OnInitializedAsync()
{
Employee = (await EmployeeService.GetEmployeeById(int.Parse(Id)));
employeeData = Employee.Name;
await InvokeAsync(StateHasChanged);
}
}
}
如果您从 EmployeeData.razor.cs 后面的代码中删除 : ComponentBase
,您会收到类似于屏幕截图中的错误。