《进击吧!Blazor!》是自己与张善友老师单干的Blazor零根底入门系列视频,此系列能让一个从未接触过Blazor的程序员把握开发Blazor利用的能力。
视频地址:https://space.bilibili.com/48...
演示代码:https://github.com/TimChen44/...
本系列文章是基于《进击吧!Blazor!》直播内容编写,降级.Net5,改良问题,解说更全面。作者:陈超超
Ant Design Blazor 我的项目贡献者,领有十多年从业教训,长期基于.Net技术栈进行架构与开发产品的工作,现就职于正泰团体。
邮箱:timchen@live.com
欢送各位读者有任何问题分割我,咱们共同进步。
上一次课程咱们实现了ToDo利用的界面制作,这次咱们要将客户端的数据写入数据库,并从数据库中读物咱们须要的数据。
数据交互过程
咱们先看一下从客户端到数据库的流程
Blazor
Blazor客户端就是咱们上节课做的ToDo程序。
HttpClient
HttpClient就是咱们实现网络通讯用的组件,对于这类组件咱们心愿在一个利用中只结构一次,这样防止反复分配资源,因而咱们在Program.cs
中进行注册。
public class Program{ public static async Task Main(string[] args) { builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); }}
BaseAddress
为基地址,这样咱们应用时,Url只须要传入绝对地址即可,此处默认为以后主机的地址。DefaultRequestHeaders
默认HTTP申请头参数Timeout
连贯超时参数
- 依赖关系注入
下面通过服务注入的形式实现了HttpClient
全局共享(单例),那么如何应用服务?这里咱们就须要引入一下“依赖关系注入 (DI)”的概念。
DI是一种技术,基本原理是把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。利用可通过将内置服务注入组件来应用这些服务。 利用还可定义和注册自定义服务,并通过 DI 使其在整个利用中可用。
该技术在 Blazor 利用中常用于以下两个方面:
服务生存期决定了服务何时创立,何时销毁,有三种模式:
Scoped
:Blazor WebAssembly
利用以后没有 DI 范畴的概念。 已注册 Scoped
的服务的行为与 Singleton
服务相似。 然而,Blazor Server 托管模型反对 Scoped
生存期。 在 Blazor Server
利用中,Scoped
服务注册的范畴为“连贯”。 因而,即便以后用意是在浏览器中运行客户端,对于范畴应限定为以后用户的服务来说,首选应用 Scoped
服务。
Singleton
:DI 创立服务的单个实例。 须要 Singleton
服务的所有组件都会接管同一服务的实例。
Transient
:每当组件从服务容器获取 Transient
服务的实例时,它都会接管该服务的新实例。
这里的 HttpClient
应用了 AddScoped
办法,那么就是以后范畴内应用同一个实例,因为我的项目是Blazor WebAssembly
模式,所以相当于单例服务。
ASP.Net Core
我用ASP.Net Core我的项目给Blazor利用提供WebAPI接口
官网文档:https://docs.microsoft.com/zh...
我的项目构造如下
- launchSettings.json
这里配置了咱们调试的形式,端口等,绝对于一般的Web我的项目多了inspectUri
属性,具备以下作用:
- 使 IDE 可能检测到该利用为 Blazor WebAssembly 利用。
- 批示脚本调试根底构造通过 Blazor 的调试代理连贯到浏览器。
- 已启动的浏览器 (browserInspectUri) 上 WebSocket 协定 (wsProtocol)、主机 (url.hostname)、端口 (url.port) 和查看器 URI 的占位符值由框架提供。
{//省略其余配置 "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } },//省略其余配置}
- Controllers
控制器(Controller
)放在这里,站点的路由表是通过遍历我的项目中带有ApiControllerAttribute
(基类ControllerAttribute
)的类,而后寻找外面的办法实现,他和Blazor的路由表创立办法上有点类似。
[ApiController] [Route("api/[controller]/[action]")] public class TaskController : ControllerBase
Route
定义了路由格局,上例中[controller]/[action]
意为应用Controller
和action
的名称作为路由地址,这样写能够省去每个action
上标记路由名字的麻烦。
- Pages
寄存页面文件的地位,因为咱们的我的项目页面全副应用Blazor构建,所以用不到此文件夹,因而这里就不做介绍了。
- appsettings.json
站点的配置文件,咱们的我的项目就用到了数据库链接字符串配置
- Program.cs
利用的Main
函数在这里,这里实现了Host
的创立与启动
- Startup.cs
启动类,我的项目启动时的服务注册,配置等工作都在此处实现ConfigureServices
应用此办法将服务增加到容器。Configure
应用此办法来配置HTTP申请管道。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env){//省略其余代码 app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllers(); endpoints.MapFallbackToFile("index.html"); });}
app.UseBlazorFrameworkFiles();
配置应用程序提供Blazor WebAssembly框架文件,默认根门路为/
,也能够自定义门路前缀endpoints.MapControllers();
增加控制器(Controller
)的路由。endpoints.MapFallbackToFile("index.html");
增加默认路由地址是index.html
。
EF Code
所有的数据咱们须要保留入数据库,这里我抉择应用EF Core作为咱们的数据拜访技术
官网文档:https://docs.microsoft.com/zh...
EF Core局部特点
- Entity Framework (EF) Core 是轻量化、可扩大、开源和跨平台版的数据拜访技术。
- EF Core可用作对象关系映射程序 (O/RM),能让咱们用对象来解决数据库,应用Linq进行查问,这样咱们就能够不必编写大量SQL代码了。
- EF Core 反对多个数据库引擎,比方MySQL、SQLite等。
他反对采纳Code Firs或者Database First两种模式
Code Firs
用代码编写对象关系,而后通过它创立数据库。Database First
能够提供现有数据库,反向生成对象映射 。
Database
数据库我抉择SQL Server,应用全套微软技术栈工具链应用体验比拟好,当然咱们也能够抉择其余数据库。
SQL Server产品家族中有一个SQL Server LocalDB的货色,它是SQL Server的一个超级精简版本,安装包只有几十MB(装置好后200+MB),它蕴含了数据库的根底性能,然而不反对联网,只能本机连贯,对于集体开发资源占用少,强烈推荐,VS装置Web开发组件会默认装置此数据库。
连贯时服务器名称默认是(localdb)\MSSQLLocalDB
,也能够应用C:\Program Files\Microsoft SQL Server\130\Tools\Binn\SqlLocalDB.exe
进行配置数据库实例
咱们能够应用VS的SQL Server对象资源管理器来查看咱们的数据库,不过我这里强烈推荐应用SQL Server Management Studio (SSMS) 的“数据库关系图”性能来保护数据库,可视化编辑表,主外键关系等,保留即更新数据库,这对于数据库优先的模式下开发十分敌对,效率极高。
下图是咱们ToDo利用应用的表构造。
代码实战
下面介绍了数据交互的流程概念,接下来咱们革新上回制作的ToDo我的项目。
引入和配置EF Code
咱们先创立一个ToDo.Entity
我的项目用于存储ORM映射以及EF的Context。
留神:目前VS 16.8.4版本创立类库会默认应用.net core 3.1,须要手动批改成.net 5
应用EF Core Power Tools工具创立代码
因为咱们下面曾经把数据库设计实现了,所以咱们采纳Database First
模式创立EF相干的代码。
此处举荐一个从数据库到EF实体的代码生成扩大EF Core Power Tools
扩大下载地址:https://marketplace.visualstu...
抉择要连贯的数据库。
抉择要增加的数据库对象。
配置Context
的名称和命名空间等,下图是我罕用配置。
EF Core Power Tools
生成的代码文件如下
appsettings.json中增加链接字符串
关上ToDo.Server\appsettings.json
增加数据库连贯字符串
"ConnectionStrings": { "DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ToDo;Integrated Security=True" },
应用EF Core Power Tools
生成的TodoContext.cs
文件中就有默认的连贯字符串,开发时想偷懒能够间接从这里复制????。
ConfigureServices中增加服务注册
关上ToDo.Server\Startup.cs
,把TodoContext
注册到DbContext
中为,并设置连贯字符串
services.AddDbContext<TodoContext>(options =>{ options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));});
有时候咱们须要在输入EF执行的SQL语句,这便于咱们调试以及优化数据库,上面的配置就把EF日志输入到控制台
/// <summary>/// 输入日志/// </summary>public static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });public void ConfigureServices(IServiceCollection services){//省略其余代码 services.AddDbContext<TodoContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")).UseLoggerFactory(loggerFactory); });}
性能实现
首先创立ToDo.Server\Controllers\TaskController.cs
文件用于编写WebAPI接口,代码如下:
namespace ToDo.Server.Controllers{ [ApiController] [Route("api/[controller]/[action]")] public class TaskController : ControllerBase { TodoContext Context; public TaskController(TodoContext context) { Context = context; } }}
通过依赖注入将TodoContext
注入到以后类中。
1. 列出当天的所有代办工作
ToDo.Server
TaskController.cs
中增加GetToDayTask
办法用于返回以后待办数据。
[HttpGet]public List<TaskDto> GetToDayTask(){ var result = Context.Task.Where(x => x.PlanTime == DateTime.Now.Date); return QueryToDto(result).ToList();}[NonAction]private IQueryable<TaskDto> QueryToDto(IQueryable<Entity.Task> query){ return query.Select(x => new TaskDto() { TaskId = x.TaskId, Title = x.Title, Description = x.Description, PlanTime = x.PlanTime, Deadline = x.Deadline, IsImportant = x.IsImportant, IsFinish = x.IsFinish, });}
ToDo.Client
增加Pages\ToDay.razor.cs
类文件,VS会主动将ToDay.razor
与ToDay.razor.cs
折叠到一起。
在类定义中减少partial
关键字,申明类为部分类,你能够了解成ToDay.razor
与ToDay.razor.cs
中的代码都属于同一个类,只是放在不同文件中,编译器编译时会将他们合并到一起后进行编译。
public partial class ToDay
接着做一下代码迁徙
- 将
Pages\ToDay.razor
文件@code{}
中的代码剪切到ToDay.razor.cs
- 将
Pages\ToDay.razor
文件@inject
代码采纳[Inject] public MessageService MsgSrv { get; set; }
这样的格局等价的迁徙到ToDay.razor.cs
这样做咱们能够实现界面代码与业务代码离开在不同的文件中,不便整顿代码,进步代码可读性。
后续其余页面我默认实现了创立部分类的操作,不再赘述。
ToDay.razor.cs
中增加HttpClient
的依赖注入,用于向服务端发动Http申请
[Inject] public HttpClient Http { get; set; }
我的项目中其余类如果应用到HttpClient
,我默认实现了依赖注入,不再赘述。????广告工夫????
Blazor
和Ant Design Blazor
中有很多服务,咱们常常在不同的中央须要注入,为了编码不便,咱们提供了一个VS扩大疾速插入罕用服务代码段,装置地址:https://marketplace.visualstu...
批改OnInitializedAsync
办法的代码
private List<TaskDto> taskDtos = new List<TaskDto>();bool isLoading = true;protected async override Task OnInitializedAsync(){ isLoading = true; taskDtos = await Http.GetFromJsonAsync<List<TaskDto>>("api/Task/GetToDayTask"); isLoading = false; await base.OnInitializedAsync();}
Http.GetFromJsonAsync<List<TaskDto>>
应用HttpGet
模式申请数据,这里应用await
进行异步期待,充分利用await
能够极大的简化代码量。isLoading
是载入状态,网络通讯必然有提早,防止白屏,咱们在载入前后别离扭转载入状态,同时批改ToDay.razor
代码增加Spin
组件用于显示载入成果。
<PageHeader Title="@("我的一天")" Subtitle="@DateTime.Now.ToString("yyyy年MM月dd日")"></PageHeader><Spin Spinning="isLoading"><!--插入代码--> @foreach (var item in taskDtos)<!--省略其余代码--> <Input @bind-Value="@newTask.Title" OnkeyUp="OnInsert" /> </div></Spin><!--插入代码-->
2. 增加代办
ToDo.ServerTaskController.cs
中增加SaveTask
办法用于保留新的待办内容
[HttpPost]public Guid SaveTask(TaskDto dto){ Entity.Task entity; if (dto.TaskId == Guid.Empty) { entity = new Entity.Task(); entity.TaskId = Guid.NewGuid(); Context.Add(entity); } else { entity = Context.Task.FirstOrDefault(x => x.TaskId == dto.TaskId); } entity.Title = dto.Title; entity.Description = dto.Description; entity.PlanTime = dto.PlanTime; entity.Deadline = dto.Deadline; entity.IsImportant = dto.IsImportant; entity.IsFinish = dto.IsFinish; Context.SaveChanges(); return entity.TaskId;}
我通过判断dto.TaskId
的值,间接将新增与更新写在一个接口中,这样能够复用代码。
此处能够应用AutoMapper
库来简化赋值过程,这将在未来的章节中具体介绍
ToDo.ClientToDay.razor.cs
文件批改OnInsert
办法相干的代码
TaskDto newTask = new TaskDto() { PlanTime = DateTime.Now.Date };[Inject] public MessageService MsgSrv { get; set; }bool isNewLoading = false;async void OnInsert(KeyboardEventArgs e){ if (e.Code == "Enter") { if (string.IsNullOrWhiteSpace(newTask.Title)) { MsgSrv.Error($"题目必须填写"); return; } isNewLoading = true; var result = await Http.PostAsJsonAsync<TaskDto>($"api/Task/SaveTask", newTask); if (result.IsSuccessStatusCode) { newTask.TaskId = await result.Content.ReadFromJsonAsync<Guid>(); taskDtos.Add(newTask); newTask = new TaskDto() { PlanTime = DateTime.Now.Date }; } else { MsgSrv.Error($"申请产生谬误 {result.StatusCode}"); } isNewLoading = false; StateHasChanged(); }}
ToDay.razor
文件减少保留时期待组件
<Spin Spinning="isNewLoading"><!--插入代码--> <div class="task-input"> <DatePicker Picker="@DatePickerType.Date" @bind-Value="@newTask.PlanTime" /> <Input @bind-Value="@newTask.Title" OnkeyUp="OnInsert" /> </div> </Spin><!--插入代码-->
通过Http.PostAsJsonAsync
调用api/Task/SaveTask
将newTask
内容提交到后端并保留,返回的HttpResponseMessage
蕴含了状态编码等,如果胜利就在界面上显示新的待办,失败就提醒谬误
MessageService
全局展现操作反馈信息。
组件文档地址:https://ant-design-blazor.git...
3. 编辑待办
ToDo.ServerTaskController.cs
中增加GetTaskDto
办法用于获取待办信息
public TaskDto GetTaskDto(Guid taskId){ var result = Context.Task.Where(x => x.TaskId == taskId); return QueryToDto(result).FirstOrDefault();}
ToDo.ClientTaskInfo.razor
文件中减少Spin
与@if
代码
<Spin Spinning="isLoading"> @if (taskDto != null)<!--页面关上时taskDto并没有值,所以间接绑定到Form会产生异样,所以这里须要做一个不为空判断--> { <Form OnFinish="OnSave" Model="taskDto" LabelColSpan="8"><!--当用户点击submit按钮时会触发OnFinish事件,所以通常会在这里进行保留操作--><!--省略其余代码--> <div> <Button HtmlType="submit">保留</Button> <Button OnClick="OnCancel">勾销</Button> </div> </Form> }</Spin>
TaskInfo.razor.cs
增加上面代码
public partial class TaskInfo : DrawerTemplate<TaskDto, TaskDto>{ [Inject] public HttpClient Http { get; set; } [Inject] public MessageService MsgSvr { get; set; } TaskDto taskDto; bool isLoading = false; protected override async Task OnInitializedAsync() { //通过api/Task/GetTaskDto接口取得待办内容 taskDto = await Http.GetFromJsonAsync<TaskDto>($"api/Task/GetTaskDto?taskId={base.Options.TaskId}"); await base.OnInitializedAsync(); } async void OnSave() { var result = await Http.PostAsJsonAsync<TaskDto>($"api/Task/SaveTask", taskDto); if (result.StatusCode == System.Net.HttpStatusCode.OK) { await base.CloseAsync(taskDto);//敞开抽屉,并返回以后待办数据 } else { MsgSvr.Error($"申请产生谬误 {result.StatusCode}"); } } async void OnCancel() { await base.CloseAsync(null);//如果点击了勾销,那么将null返回进来 }}
ToDay.razor.cs
中的OnCardClick
办法更新
[Inject] public DrawerService DrawerSrv { get; set; }async void OnCardClick(TaskDto task){ var result = await DrawerSrv.CreateDialogAsync<TaskInfo, TaskDto, TaskDto>(task, title: task.Title, width: 450); if (result == null) return; var index = taskDtos.FindIndex(x => x.TaskId == result.TaskId); taskDtos[index] = result; await InvokeAsync(StateHasChanged);}
DrawerSrv.CreateDialogAsync
绝对于DrawerSrv.CreateAsync
简化了调用办法,默认将抽屉的CloseAsync
参数返回,这就简化了每次应用抽屉时须要注册CloseAsync
事件的麻烦,也让代码更加清晰。title: task.Title, width: 450
应用可选参数简化对抽屉的参数配置。
DrawerService组件帮忙文档:https://ant-design-blazor.git...
4. 批改重要水平
ToDo.ServerTaskController.cs
中增加SetImportant
办法用于批改IsImportant
字段的值
[HttpPost]public void SetImportant(SetImportantReq req){ var entity = Context.Task.FirstOrDefault(x => x.TaskId == req.TaskId); entity.IsImportant = req.IsImportant; Context.SaveChanges();}
ToDo.Shared
增加SetImportantReq
类用于SetImportant
接口申请参数
public class SetImportantReq{ public Guid TaskId { get; set; } public bool IsImportant { get; set; }}
ToDo.ClientToDay.razor.cs
中的OnStar
办法更新
private async void OnStar(TaskDto task){ var req = new SetImportantReq()//ToDo.Shared我的项目中的类能够前后端专用,这就是Blazor劣势之一。 { TaskId = task.TaskId, IsImportant = !task.IsImportant, }; var result = await Http.PostAsJsonAsync<SetImportantReq>("api/Task/SetImportant", req); if (result.IsSuccessStatusCode) { task.IsImportant = req.IsImportant;//申请胜利后须要批改本地重要状态 StateHasChanged();//状态扭转,刷新页面的显示 }}
5. 批改实现状态
ToDo.ServerTaskController.cs
中增加SetFinish
办法用于批改IsFinish
字段的值
[HttpPost]public void SetFinish(SetFinishReq req){ var entity = Context.Task.FirstOrDefault(x => x.TaskId == req.TaskId); entity.IsFinish = req.IsFinish; Context.SaveChanges();}
ToDo.Shared
增加SetFinishReq
类用于SetFinish
接口申请参数
public class SetFinishReq{ public Guid TaskId { get; set; } public bool IsFinish { get; set; }}
ToDo.ClientToDay.razor.cs
中的OnFinish
办法更新
private async void OnFinish(TaskDto task){ var req = new SetFinishReq() { TaskId = task.TaskId, IsFinish = !task.IsFinish, }; var result = await Http.PostAsJsonAsync<SetFinishReq>("api/Task/SetFinish", req); if (result.IsSuccessStatusCode) { task.IsFinish = req.IsFinish; StateHasChanged(); }}
6. 删除代办
ToDo.ServerTaskController.cs
中增加DelTask
办法用于删除待办。
[HttpDelete]public void DelTask(Guid taskId){ Context.Task.Remove(Context.Task.Find(taskId)); Context.SaveChanges();}
ToDo.ClientToDay.razor.cs
中的OnFinish
办法更新
[Inject] public ConfirmService ConfirmSrv { get; set; }public async Task OnDel(TaskDto task){ if (await ConfirmSrv.Show($"是否删除工作 {task.Title}", "删除", ConfirmButtons.YesNo, ConfirmIcon.Info) == ConfirmResult.Yes) { taskDtos.Remove(task); }}
ConfirmService
能够快捷地弹出一个内置的确认框,相似于 Windows MessageBox。
ConfirmService组件帮忙文档:https://ant-design-blazor.git...
7. 查问代办
ToDo.ServerTaskController.cs
中增加GetSearch
办法用于批改SetFinish
字段的值
[HttpPost]public GetSearchRsp GetSearch(GetSearchReq req){ if (req.PageIndex == 0) req.PageIndex = 1; var query = Context.Task.Where(x => x.Title.Contains(req.QueryTitle ?? "")); foreach (var sort in req.Sorts) { if (sort.SortOrder == "descend") query = query.OrderBy(sort.SortField + " DESC"); else query = query.OrderBy(sort.SortField); } var result = new GetSearchRsp() { Data = QueryToDto(query.Skip(--req.PageIndex * req.PageSize).Take(req.PageSize)).ToList(), Total = query.Count(), }; return result;}
if (req.PageIndex == 0) req.PageIndex = 1
????吐槽开始:简直所有的UI框架页码都是从0开始,然而AntDesign标准的页码是从1开始的,然而没有载入数据时又是返回0????,所以要特地留神。
OrderBy
应用了System.Linq.Dynamic.Core
扩大包,它提供了一些动静的Linq反对,比方此处排序我传入的参数不是一个表达式,而是一个字符串,这样能够让代码灵活性大增。
ToDo.Shared
public class GetSearchReq{ public string QueryTitle { get; set; } public int PageIndex { get; set; } public int PageSize { get; set; } public List<SortFieldName> Sorts { get; set; }}public class SortFieldName{ /// <summary> /// 排序字段 /// </summary> public string SortField { get; set; } /// <summary> /// 排序方向 /// </summary> public string SortOrder { get; set; }} public class GetSearchRsp{ public List<TaskDto> Data { get; set; } public int Total { get; set; }}
ToDo.ClientTaskSearch.razor
文件的代码
@page "/search"<PageHeader Title="@("全副待办事项")" Subtitle="@($"数量:{total}")"></PageHeader><Search @bind-Value="queryTitle" OnSearch="OnSearch"></Search><Table Loading="@isLoading" DataSource="@datas" PageSize="10" Total="@total" OnChange="OnChange" TItem="TaskDto"> <AntDesign.Column @bind-Field="@context.Title" Sortable> @context.Title @if (context.IsImportant) { <Tag Color="orange">重要</Tag> } </AntDesign.Column> <AntDesign.Column @bind-Field="@context.Description" /> <AntDesign.Column @bind-Field="@context.PlanTime" Sortable /> <AntDesign.Column @bind-Field="@context.Deadline" /> <AntDesign.Column @bind-Field="@context.IsFinish"> @if (context.IsFinish) { <Icon Type="check" Theme="outline" /> } </AntDesign.Column></Table>
TaskSearch.razor.cs
文件的代码
[Inject] public HttpClient Http { get; set; }private bool isLoading = false;List<TaskDto> datas = new List<TaskDto>();private string queryTitle;private int total = 0;//点击查问按钮时检索数据private async Task OnSearch(){ await OnQuery(1, 10, new List<SortFieldName>());}//以后页码,排序产生扭转时调用查询方法检索数据private async Task OnChange(AntDesign.TableModels.QueryModel<TaskDto> queryModel){ await OnQuery( queryModel.PageIndex, queryModel.PageSize, queryModel.SortModel.Where(x => string.IsNullOrEmpty(x.SortType.Name) == false).OrderBy(x => x.Priority) .Select(x => new SortFieldName() { SortField = x.FieldName, SortOrder = x.SortType.Name }).ToList() );}//检索数据private async Task OnQuery(int pageIndex, int pageSize, List<SortFieldName> sort){ isLoading = true; var req = new GetSearchReq() { QueryTitle = queryTitle, PageIndex = pageIndex, PageSize = pageSize, Sorts = sort, }; var httpRsp = await Http.PostAsJsonAsync<GetSearchReq>($"api/Task/GetSearch", req); var result = await httpRsp.Content.ReadFromJsonAsync<GetSearchRsp>(); datas = result.Data; total = result.Total; isLoading = false;}
Search
带有查问按钮的文本框框
Search组件文档地址:https://ant-design-blazor.git...
查看具体服务
在我的一天
与全副
页面上均存在关上待办详情的性能需要,这时咱们就能够本人做一个服务将两边的性能合并到一起。
增加TaskDetailServices.cs
文件,退出以下代码
namespace ToDo.Client{ public class TaskDetailServices { public DrawerService DrawerSvr { get; set; } public TaskDetailServices(DrawerService drawerSvr) { DrawerSvr = drawerSvr; } public async Task EditTask(TaskDto taskDto, List<TaskDto> datas) { var taskItem = await DrawerSvr.CreateDialogAsync<TaskInfo, TaskDto, TaskDto>(taskDto, title: taskDto.Title, width: 450); if (taskItem == null) return; var index = datas.FindIndex(x => x.TaskId == taskItem.TaskId); datas[index] = taskItem; } }}
TaskDetailServices(DrawerService drawerSvr)
只有razor
文件能够应用[Inject]
标记属性进行注入服务,一般得类须要在构造函数中定义能力注入服务。
Program.cs
文件中注册TaskDetailServices
builder.Services.AddScoped<TaskDetailServices>();
TaskSearch.razor
文件中增加详情按钮
<AntDesign.Column TData="object"> <Button OnClick="x=>OnDetail(context)">详情</Button> </AntDesign.Column>
TaskSearch.razor.cs
插入以下代码,咱们注入自定义的服务,应用服务中的办法关上编辑界面。
[Inject] public TaskDetailServices TaskSrv { get; set; }private async Task OnDetail(TaskDto taskDto){ await TaskSrv.EditTask(taskDto, datas);}
次回预报
下一次咱们要介绍Blazor的精华,也是我集体认为Blazor框架体系中最优良的个性——组件。咱们通过几个小实例展现Blazor的组件开发方法,敬请期待
学习材料:
https://aka.ms/LearnBlazor