乐趣区

关于c#:进击吧Blazor第一章-4数据交互

《进击吧!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 利用中常用于以下两个方面:

服务生存期决定了服务何时创立,何时销毁,有三种模式:

ScopedBlazor 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 属性,具备以下作用:

  1. 使 IDE 可能检测到该利用为 Blazor WebAssembly 利用。
  2. 批示脚本调试根底构造通过 Blazor 的调试代理连贯到浏览器。
  3. 已启动的浏览器 (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] 意为应用 Controlleraction的名称作为路由地址,这样写能够省去每个 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.razorToDay.razor.cs折叠到一起。

在类定义中减少 partial 关键字,申明类为部分类,你能够了解成 ToDay.razorToDay.razor.cs中的代码都属于同一个类,只是放在不同文件中,编译器编译时会将他们合并到一起后进行编译。

    public partial class ToDay

接着做一下代码迁徙

  1. Pages\ToDay.razor 文件 @code{} 中的代码剪切到ToDay.razor.cs
  2. 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,我默认实现了依赖注入,不再赘述。

???? 广告工夫????
BlazorAnt 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.Server
TaskController.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.Client
ToDay.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/SaveTasknewTask内容提交到后端并保留,返回的 HttpResponseMessage 蕴含了状态编码等,如果胜利就在界面上显示新的待办,失败就提醒谬误

MessageService全局展现操作反馈信息。

组件文档地址:https://ant-design-blazor.git…

3. 编辑待办

ToDo.Server
TaskController.cs中增加 GetTaskDto 办法用于获取待办信息

public TaskDto GetTaskDto(Guid taskId)
{var result = Context.Task.Where(x => x.TaskId == taskId);
    return QueryToDto(result).FirstOrDefault();}

ToDo.Client
TaskInfo.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.Server
TaskController.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.Client
ToDay.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.Server
TaskController.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.Client
ToDay.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.Server
TaskController.cs中增加 DelTask 办法用于删除待办。

[HttpDelete]
public void DelTask(Guid taskId)
{Context.Task.Remove(Context.Task.Find(taskId));
    Context.SaveChanges();}

ToDo.Client
ToDay.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.Server
TaskController.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.Client
TaskSearch.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

退出移动版