在我的开拓者应用程序中,我正在对后端服务器进行api调用,这可能需要一些时间。我需要向用户显示反馈,等待光标或“旋转”图像。在Blazor中如何完成?
我尝试使用CSS并打开和关闭CSS,但是直到调用完成,页面才会刷新。任何建议将不胜感激。
@functions {
UserModel userModel = new UserModel();
Response response = new Response();
string errorCss = "errorOff";
string cursorCSS = "cursorSpinOff";
protected void Submit()
{
//Show Sending...
cursorCSS = "";
this.StateHasChanged();
response = Service.Post(userModel);
if (response.Errors.Any())
{
errorCss = "errorOn";
}
//turn sending off
cursorCSS = "cursorSpinOff";
this.StateHasChanged();
}
}
答案 0 :(得分:2)
下面是Blazor模板中文件FetchData.razor的内容
请注意,文件包含两部分:与C#(Razor)混合的HTML,以及@code块内的C#代码,其中我们定义了WeatherForecast对象数组,称为预报。该数组将保存通过OnInitAsync方法进行的http调用返回到服务器的WeatherForecast对象。
请注意,if语句(@if (forecasts == null)
)正在检查是否已检索WeatherForecast对象。只要变量预测为null,HTML <p><em>Loading...</em></p>
被展示。您可以在此处添加任意数量的HTML,包括图像,微调框等。
一旦为天气预报分配了WeatherForecast对象 将显示一个HTML表,其中包含检索到的数据
希望这对您有帮助...
@page "/fetchdata"
@using BlazorHosted_CSharp.Shared
@inject HttpClient Http
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
WeatherForecast[] forecasts;
protected override async Task OnInitAsync()
{
forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts");
}
}
答案 1 :(得分:1)
Blazor使用虚拟dom,该框架跟踪更改并仅在未阻止主线程时发送更改。这就是我允许Blazor将更改刷新到UI的方式:
async
函数。await Task.Delay(1)
)示例
async Task AsyncLongFunc() // this is an async task
{
spinning=true;
await Task.Delay(1); // changes are flushed
LongFunc(); // usually with a wait ( is a web request)
currentCount++;
spinning=false;
await Task.CompletedTask; // just to avoid non await warning.
}
如您所见,不需要StateHasChanged
。
注意:如果有更简单的方法或更优雅的解决方案,则可以使用IDK。
效果:
整页代码(已编辑,符合netcore3 Preview6):
@page "/counter"
<h1>Counter</h1>
<p>Current count:
@(spinning?"Incrementing .... (the spinning effect)":currentCount.ToString())
</p>
<button class="btn btn-primary"
@onclick="@IncrementCount">Click me</button>
<button class="btn @(spinning?"btn-dark":"btn-primary") "
@onclick="@AsyncLongFunc">Click me Async</button>
@code {
int currentCount = 0;
bool spinning = false;
void IncrementCount()
{
currentCount++;
}
async Task AsyncLongFunc()
{
spinning=true;
await Task.Delay(1);
LongFunc();
currentCount++;
spinning=false;
await Task.CompletedTask;
}
void LongFunc() => Task.Delay(2000).Wait();
}
答案 2 :(得分:1)
要回答@daniherrera's solution中的通知,提出了三种更优雅的解决方案here。
简而言之:
INotifyPropertyChanged
到模型并在 StateHasChanged()
上调用 PropertyChangedEventHandler
模型中的事件属性。 StateHasChanged()
。 EventCallBack<T>
参数,并将其分配给应更改组件及其父级渲染的功能。 ( StateHasChanged()
在这个步骤中不是必需的`) 最后一个选项是最简单,最灵活和最高级的,但是请您选择方便。
总体而言,如果您担心应用的安全性,我建议使用其中一种解决方案,而不是await Task.Delay(1);
。
编辑:更多阅读后,this link对如何处理C#中的事件(主要是通过EventCallBack
进行了强有力的解释)。
答案 3 :(得分:0)
不要像通过使用Thread.Sleep(n)测试wait spinner一样犯同样的错误。
with recursive maxid as (
select max(id) as id from Mytable)
, cte as (
select 0 as rid
union all
select rid + 1
from cte
cross join maxid
where (rid + 1) * 2 <= maxid.id)
select max(case when m.id % 2 = 0 then name end) as even,
max(case when m.id % 2 = 1 then name end) as odd
from cte
left join Mytable m on floor(m.id / 2) = cte.rid
group by rid order by rid;
答案 4 :(得分:0)
Blazor服务器端-我需要调用 StateHasChanged()来强制前端进行更新,以便微调器可以在代码移至ajax调用之前显示出来。
/* Show spinner */
carForm.ShowSpinner = true;
/* Force update of front end */
StateHasChanged();
/* Start long running API/Db call */
await _carRepository.Update(item);