Blazor-在API调用上显示等待或微调框

时间:2019-06-14 20:41:13

标签: c# blazor

在我的开拓者应用程序中,我正在对后端服务器进行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();
    }
}

5 个答案:

答案 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的方式:

  1. 使用async函数。
  2. 对虚拟dom进行更改。
  3. 取消阻止主线程(我使用await Task.Delay(1)
  4. 继续您的任务。

示例

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。

效果:

enter image description here

整页代码(已编辑,符合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);
相关问题