首页 > 其他分享 >Blazor学习之旅(3)实现一个Todo应用

Blazor学习之旅(3)实现一个Todo应用

时间:2023-07-07 09:14:10浏览次数:59  
标签:todoContext Task todoItem 之旅 Blazor Todo public TodoItem

最近在学习Blazor做全栈开发,因此根据老习惯,我会将我的学习过程记录下来,一来体系化整理,二来作为笔记供将来翻看。

本篇,我们通过一个简单的Todo示例应用来介绍如何实现基础的数据绑定和事件。

添加Todo组件

在Pages目录下,新增一个Razor组件,命名:Todo.razor

@page "/todo"

<h3>Todo</h3>

@code {

}

将Todo组件添加到导航栏

我们知道,在Shared目录下的NavMenu组件用于应用的导航,因此我们需要将Todo组件加进去以便可以访问到:

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <nav class="flex-column">

        ...

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="todo">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Todo
            </NavLink>
        </div>
    </nav>
</div>

这时导航栏中也就有Todo了:

添加Model

添加一个Models目录,在此目录下新建一个TodoItem类:

namespace EDT.BlazorServer.App.Models
{
    public class TodoItem
    {
        public string Id { get; set; }
        public string? Name { get; set; }
        public bool IsComplete { get; set; }
        public string? Remark { get; set; }
    }
}

为了模拟实现数据库访问的效果,这里我们使用EF Core的内存数据库来模拟。

首先,添加对Microsoft.EntityFrameworkCore.InMemory的应用。

其次,在Models目录下创建一个TodoContext类:

using Microsoft.EntityFrameworkCore;

namespace EDT.BlazorServer.App.Models
{
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }

        public DbSet<TodoItem> TodoItems { get; set; }
    }
}

然后,在Program.cs中注入这个DbContext:

// Add database context
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));

添加种子数据

为了方便演示,我们提前准备一些SeedData,创建一个SeedData的静态类:

namespace EDT.BlazorServer.App.Models
{
    public static class SeedData
    {
        public static void Initialize(TodoContext db)
        {
            var todos = new TodoItem[]
            {
                new TodoItem { Id = Guid.NewGuid().ToString(), Name = "Study Computer Network", IsComplete=false, Remark = "Take a Test" },
                new TodoItem { Id = Guid.NewGuid().ToString(), Name = "Study Operation System", IsComplete=false, Remark = "Take a Test" },
                new TodoItem { Id = Guid.NewGuid().ToString(), Name = "Study Data Structure", IsComplete=false, Remark = "Take a Test" },
                new TodoItem { Id = Guid.NewGuid().ToString(), Name = "Walk the dog", IsComplete=true, Remark = string.Empty },
                new TodoItem { Id = Guid.NewGuid().ToString(), Name = "Run 5km in 40mins", IsComplete=true, Remark = string.Empty },
            };

            db.TodoItems.AddRange(todos);
            db.SaveChanges();
        }
    }
}

然后,在Program.cs中确保运行这个初始化操作:

添加Service

假设我们所有的TodoItem都是通过Service来完成的,不直接在Pages下的组件中来操作。

首先,创建一个接口ITodoItemService:

using EDT.BlazorServer.App.Models;

namespace EDT.BlazorServer.App.Service.Contracts
{
    public interface ITodoItemService
    {
        Task<IList<TodoItem>> GetTodoItemsAsync();
        Task<TodoItem> GetTodoItemAsync(string id);
        Task<TodoItem> AddTodoItemAsync(TodoItem todoItem);
        Task<TodoItem> UpdateTodoItemAsync(TodoItem todoItem);
        Task<TodoItem> DeleteTodoItemAsync(TodoItem todoItem);
    }
}

这时,我们重新启动应用就可以看到Counter组件显示在主页上面了:

其次,实现TodoItemService:

using EDT.BlazorServer.App.Models;
using EDT.BlazorServer.App.Service.Contracts;
using Microsoft.EntityFrameworkCore;

namespace EDT.BlazorServer.App.Service
{
    public class TodoItemService : ITodoItemService
    {
        private readonly TodoContext _todoContext;


        public TodoItemService(TodoContext todoContext)
        {
            _todoContext = todoContext;
        }
        

        public async Task<TodoItem> AddTodoItemAsync(TodoItem todoItem)
        {
            todoItem.Id = Guid.NewGuid().ToString();
            todoItem.IsComplete = false;

            _todoContext.TodoItems.Add(todoItem);
            await _todoContext.SaveChangesAsync();

            return todoItem;
        }
        

        public async Task<TodoItem> DeleteTodoItemAsync(TodoItem todoItem)
        {
            _todoContext.TodoItems.Remove(todoItem);
            await _todoContext.SaveChangesAsync();

            return todoItem;
        }
        

        public async Task<TodoItem> GetTodoItemAsync(string id)
        {
            return await _todoContext.TodoItems.FirstOrDefaultAsync(t => t.Id == id);
        }
        

        public async Task<IList<TodoItem>> GetTodoItemsAsync()
        {
            return await _todoContext.TodoItems.ToListAsync();
        }
                 

        public async Task<TodoItem> UpdateTodoItemAsync(TodoItem todoItem)
        {
            _todoContext.TodoItems.Update(todoItem);
            await _todoContext.SaveChangesAsync();

            return todoItem;
        }
    }
}

完善Todo组件

这里,我们仿照FetchData组件添加一个表格 并 实现TodoItem的添加:

@page "/todo"
@using EDT.BlazorServer.App.Models
@using EDT.BlazorServer.App.Service.Contracts
@inject ITodoItemService todoItemService;

<h3>Todo (@todos.Count(todo => !todo.IsComplete))</h3>

@if (todos == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>IsComplete</th>
                <th>Remark</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var todo in todos)
            {
                <tr>
                    <td>@todo.Id.ToString()</td>
                    <td>@todo.Name</td>
                    <td><input type="checkbox" @bind="todo.IsComplete" /></td>
                    <td>@todo.Remark</td>
                </tr>
            }
        </tbody>
    </table>
}

<input placeholder="Todo Item Name (Necessary)" @bind="newTodoItemName" />
<input placeholder="Todo Item Remark (Optioinal)" @bind="newTodoItemRemark" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private IList<TodoItem> todos;
    private string? newTodoItemName;
    private string? newTodoItemRemark;

    protected override async Task OnInitializedAsync()
    {
        todos = await todoItemService.GetTodoItemsAsync();
    }

    private async void AddTodo()
    {
        if (string.IsNullOrWhiteSpace(newTodoItemName))
            return;

        var todoItem = new TodoItem { Name = newTodoItemName, Remark = newTodoItemRemark };
        await todoItemService.AddTodoItemAsync(todoItem);
        // Clear Textboxes
        newTodoItemName = newTodoItemRemark = string.Empty;
        // Refresh Todos
        todos = await todoItemService.GetTodoItemsAsync();
  }
}

需要注意的是:

(1)通过@inject指令进行Service的注入,和常见的构造函数注入不同。

(2)通过重写OnInitializeAsync事件,进行数据的初始化,即从数据库中读取TodoItem的列表。这部分属于Blazor组件的生命周期范畴,这里不过多纠结即可。唯一需要了解的是,OnInitialized 和 OnInitializeAsync 事件是在做组件的初始化,它发生在参数注入完成之后(这里的ITodoItemService就是注入的参数)。

(3)除了foreach,Blazor还包含其他循环指令,例如 @for、@while 和 @do while。这些指令返回重复的标记块。它们的工作方式与等效的 C# for、while 和 do...while 循环类似。

到此,最终的项目结构如下图所示:

运行效果

运行起来的效果如下图所示:

(1)加载Todo列表

(2)添加新的Todo事项

小结

本篇,我们实现了一个Todo应用。

下一篇,我们学习一下在Blazor中数据是如何被共享的。

参考资料

Microsoft Learning,《使用Blazor生成Web应用

 

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

标签:todoContext,Task,todoItem,之旅,Blazor,Todo,public,TodoItem
From: https://www.cnblogs.com/edisonchou/p/edc_aspnet_blazor_learning_chap3.html

相关文章

  • Blazor学习之旅(2)第一个Blazor应用
    本篇我们来构建第一个BlazorWeb应用,这里我们选择BlazorServer类型,后面我们再学习BlazorWebAssembly类型。话外音:有人问我西门子在用Blazor吗?是的,西门子德国的两家数字化工厂都有在用Blazor开发Web应用,特别用到了MudBlazor这个UI组件库并封装一个完整的内部系统开发模板,值得关......
  • 安语未,开启你的互联网之旅!
    在当今互联网时代,我们无法想象没有互联网所带来的便利。网民们每天都在互联网上浏览新闻、购物、社交、娱乐等,而博客、影视等也成为了我们生活的一部分。为了更好地提供用户体验,让你的互联网之旅更加便捷愉快,我将为你介绍一些关于博客、互联网、影视和上网导航的知识。首先,让我们......
  • Blazor学习之旅(1)初步了解Blazor
    2022年9月以来在学习Blazor做全栈开发,因此根据老习惯,我会将我的学习过程记录下来,一来体系化整理,二来作为笔记供将来翻看。作为第一篇,我们先来了解一下这个Blazor到底是个什么鬼。什么是Blazor?Blazor是微软近年来主推的,基于C#、HTML与CSS来构建交互式WebUI的框架。 借助Blaz......
  • MAUI Blazor Android 输入框软键盘遮挡问题2.0
    前言关于MAUIBlazorAndroid输入框软键盘遮挡问题,之前的文章已经有了答案,MAUIBlazorAndroid输入框软键盘遮挡问题但是这个方案一直存在一点小的瑕疵在小窗模式下,界面的高度始终不正确所以本篇文章重点解决这个问题特别感谢这篇文章AndroidwebView输入框软键盘遮挡问题......
  • 【十一】JavaScript之案例-todolist
    【十一】JavaScript之案例-todolist基本页面<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title><style>body,ul,input{margin:0;padding:......
  • 深入docker(todo)
    2018年接触容器,已经有好几个年头,但目前停留在使用,维护,制作镜像,编排等,方方面面都涉及到,基本够用。看过一本华为写的深入书籍,感觉一般。计划花点时间系统研究下内部机制,从如下几块进行实践:1.容器技术:namespace,cgroups,aufs2.构造容器的本质3.构造镜像的本质4.容器网络的本质5.r......
  • 力扣之旅-0级小白到1级小白
    0到1是一个巨大的进步!海明威说过:“优于别人并不高贵,真正的高贵是优于过去的自己“目录:引言开始的挫折与挑战寻找解题思路和技巧持之以恒与刻意练习克服困难和失败的心态高效学习和准备复习寻求帮助和合作成功的喜悦与未来计划1、引言力扣是一个在线编程挑战平台,提供了广泛的算法和......
  • MAUI Blazor获取内存使用情况
    varrunTime=Java.Lang.Runtime.GetRuntime();varmaxMemory=runTime.MaxMemory();vartotalMemory=runTime.TotalMemory();varfreeMemory=runTime.FreeMemory();//获取可用内存ActivityManager.MemoryIn......
  • TodoList案例
       案例介绍文本框里面输入内容,按下回车,就可以生成待办事项。点击待办事项复选框,就可以把当前数据添加到已完成事项里面。点击已完成事项复选框,就可以把当前数据添加到待办事项里面。但是本页面内容刷新页面不会丢失。toDoList分析以及注意点刷新页面不会丢失数据,......
  • todo记事本
    <!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <title>TodoList</title>  <style>    body{      background-color:#f6f6f6;      font-family:'......