Bri*_*ian 6 c# asp.net razor blazor
我正在开发一个允许用户搜索我们的数据库的应用程序。当用户输入搜索词时,应用程序会访问 API 端点并返回数据。然后我显示数据。
当 API 返回数据时,我有一个范围服务:
services.AddScoped<AppState>();
Run Code Online (Sandbox Code Playgroud)
这使得每个返回的数据集可以在应用程序的所有组件中使用。
页面加载后SearchResults.razor,它就会从我的范围服务中获取结果,然后绘制页面的其余部分。
我需要一个“加载”微调器来放置数据,直到 API 返回数据,这可能需要很长时间,具体取决于搜索的数据量。
我的问题是,我无法弄清楚使用什么作为真/假“触发器”来了解是否显示数据或加载旋转器,或者在 API 向我发送数据后如何刷新页面。
我下面的内容仅适用于第一次初始搜索(从我的Index.razor页面),但不适用于任何包含的“过滤器”组件。
搜索结果.razor:
@page "/searchresults"
@layout PageTopComponents
<Header.razor></Header.razor>
<LeftMenu.razor>
<FilterRazorComponent01.razor></FilterRazorComponent01.razor>
<FilterRazorComponent02.razor></FilterRazorComponent02.razor>
<FilterRazorComponent03.razor></FilterRazorComponent03.razor>
<FilterRazorComponent04.razor></FilterRazorComponent04.razor>
</LeftMenu.razor>
<MainContentComponent.razor>
// CONTENT HERE SHOULD BE VISIBLE WHEN DATA HAS ARRIVED, OTHERWISE IT SHOULD SHOW A "WAITING" SPINNER
@if(API_Data_Received != null && API_Data_Received.count > 0){
foreach(){
// API Retrieved Data Here
}
} else {
// Loading Spinner
}
<ContinueSearch.razor></ContinueSearch.razor>
<Paginator.razor @ref="PaginatorComponentReference">
<ChildContent>
// THIS IS WHERE I DISPLAY ALL SEARCH DATA ...
// CONTAINS: public Paginator PaginatorComponentReference;
</ChildContent>
</Paginator.razor>
</MainContentComponent.razor>
@code {
// code here ...
public async Task GetQueryStringValues()
{
Uri uri = navigationManager.ToAbsoluteUri(System.Net.WebUtility.UrlDecode(navigationManager.Uri));
Dictionary<string, StringValues> queryStrings = QueryHelpers.ParseQuery(uri.Query);
}
}
Run Code Online (Sandbox Code Playgroud)
分页器.razor:
<div> [ << ] [ < ] NAVIGATION [ > ] [ >> ] </div>
@ChildContent // Is "ChildContent" in SearchResults.razor
<div> [ << ] [ < ] NAVIGATION [ > ] [ >> ] </div>
Run Code Online (Sandbox Code Playgroud)
我包含的大多数 .RAZOR 组件都会进行某种“过滤”并使用以下内容:
String href = "/searchresults" + // other parameters here ...
NavigationManager.NavigateTo(href);
Run Code Online (Sandbox Code Playgroud)
这意味着,每当我“过滤”时,我总是会点击该SearchResults.razor页面。
我相信我已经尝试了await InvokeAsync(StateHasChanged);所有可覆盖方法的一些组合:
SearchResults.razor但在我的表单条目首次加载后似乎没有任何效果Index.razor。
我需要做什么才能让它发挥作用?这看起来很简单,但我就是无法弄清楚。
MrC*_*tis 10
答案展示了如何更新 Blazor WeatherForecast 应用程序以演示状态/通知模式以及如何在组件中使用它。我使用了天气预报应用程序,因为您的问题没有足够的详细信息,无法使用您的代码作为答案的基础,而天气预报应用程序提供了一个很好的构建模板。
起点是标准 Blazor Server 模板项目。我的叫StackOverflow.Answers
添加一个Loading.razor组件。这将检测加载状态并在加载记录时显示旋转器。
@if (this.IsLoaded)
{
@this.ChildContent
}
else
{
<div class="loader"></div>
}
@code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public bool IsLoaded { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
添加组件CSS文件--Loading.razor.css格式化旋转器:
.page-loader {
position: absolute;
left: 50%;
top: 50%;
z-index: 1;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
.loader {
border: 16px solid #f3f3f3;
/* Light grey */
border-top: 16px solid #3498db;
/* Blue */
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
margin-left: auto;
margin-right: auto;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Run Code Online (Sandbox Code Playgroud)
我将原始服务拆分为单独的数据和视图服务(良好的设计实践)。
更新WeatherForecastService. 现在是数据服务,它所需要做的就是提供数据。在真实的应用程序中,它将与数据代理交互以获取真实数据。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StackOverflow.Answers.Data
{
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private List<WeatherForecast> recordsShort;
private List<WeatherForecast> recordsLong;
public WeatherForecastService()
{
recordsShort = GetForecastsShort;
recordsLong = GetForecastsLong;
}
public async Task<List<WeatherForecast>> GetForecastsAsync(bool islong = false)
{
await Task.Delay(3000);
return islong ? this.recordsLong : this.recordsShort;
}
public List<WeatherForecast> GetForecastsShort
{
get
{
var rng = new Random();
return Enumerable.Range(1, 3).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToList();
}
}
public List<WeatherForecast> GetForecastsLong
{
get
{
var rng = new Random();
return Enumerable.Range(1, 6).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToList();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将新WeatherForecastViewService类添加到数据文件夹。这是我们的视图服务。它保存我们的数据,并且是 UI 使用的服务。它从数据服务获取数据并公开Records列表和ListChanged列表更改时触发的事件。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace StackOverflow.Answers.Data
{
public class WeatherForecastViewService
{
public List<WeatherForecast> Records { get; set; }
private WeatherForecastService weatherForecastService;
public WeatherForecastViewService(WeatherForecastService weatherForecastService)
{
this.weatherForecastService = weatherForecastService;
}
public async Task GetForecastsAsync(bool islong = false)
{
this.Records = null;
this.NotifyListChanged(this.Records, EventArgs.Empty);
this.Records = await weatherForecastService.GetForecastsAsync(islong);
this.NotifyListChanged(this.Records, EventArgs.Empty);
}
public event EventHandler<EventArgs> ListChanged;
public void NotifyListChanged(object sender, EventArgs e)
=> ListChanged?.Invoke(sender, e);
}
}
Run Code Online (Sandbox Code Playgroud)
添加一个新组件 - WeatherForecastList.razor. 这就是来自的胆量Fetchdata。它:
Loading组件。WeatherForecastViewService。它没有自己的副本 - 所有组件都使用相同的列表。ListChanged事件并StateHasChanged在触发 evwnt 时调用。@implements IDisposable
@using StackOverflow.Answers.Data
<h1>Weather forecast</h1>
<Loading IsLoaded="this.isLoaded" >
<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 viewService.Records)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
</Loading>
@code {
[Inject] private WeatherForecastViewService viewService { get; set; }
private bool isLoaded => viewService.Records is not null;
protected override async Task OnInitializedAsync()
{
await GetForecastsAsync();
this.viewService.ListChanged += this.OnListChanged;
}
private async Task GetForecastsAsync()
=> await viewService.GetForecastsAsync();
private void OnListChanged(object sender, EventArgs e)
=> this.InvokeAsync(this.StateHasChanged);
public void Dispose()
{
this.viewService.ListChanged -= this.OnListChanged;
}
}
Run Code Online (Sandbox Code Playgroud)
更新Startup服务以获取新服务。
services.AddSingleton<WeatherForecastService>();
services.AddScoped<WeatherForecastViewService>();
Run Code Online (Sandbox Code Playgroud)
更新FetchData。它现在使用该WeatherForecastList组件。该按钮提供了一种更改列表和查看 UI 更新的机制。
@page "/fetchdata"
@using StackOverflow.Answers.Data
<WeatherForecastList/>
<div class="m-2">
<button class="btn btn-dark" @onclick="this.LoadRecords">Reload Records</button>
</div>
@code {
[Inject] WeatherForecastViewService viewService { get; set; }
private bool isLong = true;
private async Task LoadRecords()
{
await this.viewService.GetForecastsAsync(isLong);
this.isLong = !this.isLong;
}
}
Run Code Online (Sandbox Code Playgroud)
希望我第一次就把所有代码都写对了!我确信有人会指出任何明显的错误或改进。