Blazor學習之旅(3)實現一個Todo應用

5fd22d2ba9541602a01176401d69aa6b.jpeg

【Blazor】|?總結/Edison Zhou


大家好,我是Edison。

最近在學習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了:

e38116db97239154aa57a86847a02b91.png

添加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組件顯示在主頁上面了:

0513d4e89c47327a8f8850df7a5a5601.png

其次,實現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 TextboxesnewTodoItemName = newTodoItemRemark = string.Empty;// Refresh Todostodos = await todoItemService.GetTodoItemsAsync();}
}

需要注意的是:

(1)通過@injec指令進行Service的注入,和常見的構造函數注入不同。

(2)通過重寫OnInitializeAsync事件,進行數據的初始化,即從數據庫中讀取TodoItem的列表。這部分屬于Blazor組件的生命周期范疇,這里不過多糾結即可。唯一需要了解的是,OnInitialized 和 OnInitializeAsync 事件是在做組件的初始化,它發生在參數注入完成之后(這里的ITodoItemService就是注入的參數)。

(3)除了foreach,Blazor還包含其他循環指令,例如?@for、@while 和?@do while。這些指令返回重復的標記塊。它們的工作方式與等效的 C# for、while 和 do...while 循環類似。

到此,最終的項目結構如下圖所示:

d85ba7c9284b810cf35ef456a7343c03.png

運行效果

運行起來的效果如下圖所示:

(1)加載Todo列表

b232301479d76e96ad549b16c57b9bb6.png

(2)添加新的Todo事項

6f5362a864214cd26c07e4f85233b060.gif

小結

本篇,我們實現了一個Todo應用。

下一篇,我們學習一下在Blazor中數據是如何被共享的。

參考資料

Microsoft Docs,《使用Blazor生成Web應用》

d0f30ce176cf8bd88ab000ab66968694.gif

年終總結:Edison的2021年終總結

數字化轉型:我在傳統企業做數字化轉型

C#刷題:C#刷劍指Offer算法題系列文章目錄

.NET面試:.NET開發面試知識體系

.NET大會:2020年中國.NET開發者大會PDF資料

d917b6c01d8261171e19820beaf33d5c.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282065.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282065.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282065.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaScript 省市級聯效果

為什么80%的碼農都做不了架構師&#xff1f;>>> JavaScript 省市級聯效果 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">2 <html xmlns"http…

20分鐘完成Mac上的 LNMP 環境部署,優雅·高效開發(Docker方式)

一、前言 對于很多開發者來說&#xff0c;突然轉到在 mac 系統開發&#xff0c;可能會非常難受&#xff0c;主要有以下幾個原因 1、mac 上安裝軟件程序坑多&#xff0c;比如安裝 PHP、Nginx&#xff0c;會存在很多使用 linux 或 windows 時沒有遇到過的坑 2、對 mac 系統不熟…

可編程交換時代就在這里

在第一批網絡處理器推出20年后&#xff0c;我們正在向完全可編程數據平面邁進&#xff0c;網絡運營商在虛擬化方面的努力推動了這一趨勢的發展。 大多數物理網絡系統正在被運行在網絡核心和邊緣的服務器上的虛擬網絡功能&#xff08;VNF&#xff09;取代。這些服務器一般采用通…

【智力大沖浪】

【智力大沖浪】riddle內存限制&#xff1a; 128M【題目描述】例 1 智力大沖浪&#xff08;riddle.pas&#xff09;。【題目描述】小偉報名參加中央電視臺的智力大沖浪節目。本次挑戰賽吸引了眾多參賽者&#xff0c;主持人為了表彰大家的勇氣&#xff0c;先獎勵每個參賽者 m 元。…

調試 不彈出 小米_時隔六年,小米NFC碰碰貼復活,碰一下自動亮燈、聯網、投屏...

有朋友問我&#xff0c;NFC除了刷門禁、刷公交、離線支付外&#xff0c;還能干什么&#xff1f;實際上NFC的應用場景遠不止于此&#xff0c;今天就帶大家開開眼界。今年是小米十周年&#xff0c;各種酷玩新品不斷&#xff0c;其中“小米碰碰貼2”就是一款便宜又好玩的產品。小米…

微信小程序把玩(三)tabBar底部導航

為什么80%的碼農都做不了架構師&#xff1f;>>> tabBar相對而言用的還是比較多的&#xff0c;但是用起來并沒有難&#xff0c;在app.json中配置下tabBar即可&#xff0c;注意tabBar至少需要兩個最多五個Item選項 主要屬性&#xff1a; 對于tabBar整體屬性設置&…

WPF 之列表分頁控件

WPF 之列表分頁控件控件名&#xff1a;WindowAcrylicBlur作者&#xff1a; WPFDevelopersOrg - 黃佳 | 驚鏵原文鏈接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40。Visual Studio 2022。項目使用 MIT 開源許可協議。新建Paginat…

高并發下防止庫存超賣解決方案

一、概述 目前網上關于防止庫存超賣&#xff0c;我沒找到可以支持一次購買多件的&#xff0c;都是基于一次只能購買一件做的秒殺方案&#xff0c;但是實際場景中&#xff0c;一般秒殺活動都是支持&#xff11;&#xff5e;&#xff15;件的&#xff0c;因此為了補缺&#xff0…

【幾何/分治】【最短路】【數學期望】Day 10.24

1、斜率 可以證明如果兩點之間還有一點的話那么原來的兩個點連線一定不會是最大斜率 然后我就寫了個沙茶分治………… 其實根據上面的推論只用枚舉相鄰的兩個點&#xff0c;掃一遍就可以了 1 #include <cstdio>2 #include <algorithm>3 #include <iostream>4…

K8s 介紹

過去一段時間&#xff0c;公司事情比較多&#xff0c;現在稍微能好點&#xff0c;今天進一步驗證自己K8S 集群環境&#xff0c;遇到不少問題&#xff0c; 發現從自己的master 上無法訪問node 的pod&#xff0c; 然后一堆search 。 config 。。 [rootk8s-master ~]# systemctl s…

easypoi needmerge失效_EasyPOI簡單用例,簡單有效

用poi導出Excel表格&#xff0c;需要配置很多東西&#xff0c;也比較麻煩&#xff0c;這里使用poi的封裝easypoi&#xff0c;可以快速配置&#xff0c;實現Excel或者word文件的導出。這里我們結合SpringMVC開發easypoi。1&#xff0c;導入以下3個.jar包:這里是springMVC和easyp…

禁止sethc.exe運行 防止3389的sethc后門

廢話&#xff1a;在土司看到的一篇文章,發私信給那個哥們兒說讓不讓轉載,結果還沒回復我就在百度看到相同的文章。他自己也是轉載的。這哥們兒ID遲早被ban 文章轉載自:http://www.jb51.net/hack/64484.html 點“開始”&#xff0c;在“運行”中敲入gpedit.msc依次展開“用戶配置…

Mac 與虛擬機中的linux集群共享文件目錄設置

一、環境介紹 本機&#xff1a;Macos Big Sur系統 虛擬機軟件&#xff1a;vmware-fusion 虛擬機上虛擬的linux - centos7 系統 二、實現的效果 在mac上創建一個/Users/SH-Server/vm-vagrant目錄&#xff0c;作為之后和虛擬機linux系統 /data 文件夾的共享目錄。 我們最終想…

jsp編程技術徐天鳳課后答案_jsp編程技術教材課后習題.doc

jsp編程技術教材課后習題JSP編程技術習題集1.6 本 章 習 題思考題(1)為什么要為JDK設置環境變量&#xff1f;(2)Tomcat和JDK是什么關系&#xff1f;(3)什么是Web服務根目錄、子目錄、相對目錄&#xff1f;如何配置虛擬目錄&#xff1f;(4)什么是B/S模式&#xff1f;(5)JSP、Jav…

JVM知識(一)

java三大流&#xff1a;數據流、控制流、指令流 線程是執行程序的最小單元&#xff0c;一個線程中也有這些東西。 java 運行時數據區&#xff1a; 1.程序計數器 指向當前線程正在執行的字節碼指令地址。如果此時從一個線程轉為執行另一個線程&#xff0c;此時就會中斷&#xff…

AWD-LSTM為什么這么棒?

摘要&#xff1a; AWD-LSTM為什么這么棒&#xff0c;看完你就明白啦&#xff01;AWD-LSTM是目前最優秀的語言模型之一。在眾多的頂會論文中&#xff0c;對字級模型的研究都采用了AWD-LSTMs&#xff0c;并且它在字符級模型中的表現也同樣出色。 本文回顧了論文——Regularizing …

Spread / Rest 操作符

Spread / Rest 操作符指的是 ...&#xff0c;具體是 Spread 還是 Rest 需要看上下文語境。 當被用于迭代器中時&#xff0c;它是一個 Spread 操作符&#xff1a;&#xff08;參數為數組&#xff09; function foo(x,y,z) {console.log(x,y,z); }let arr [1,2,3]; foo(...arr);…

python postman腳本自動化_如何用Postman做接口自動化測試

什么是自動化測試把人對軟件的測試行為轉化為由機器執行測試行為的一種實踐。例如GUI自動化測試&#xff0c;模擬人去操作軟件界面&#xff0c;把人從簡單重復的勞動中解放出來本質是用代碼去測試另一段代碼&#xff0c;屬于一種軟件開發工作&#xff0c;已經開發完成的用例還必…

Mac上,為虛擬機集群上的每臺虛擬機設置固定IP

一、環境介紹 本機&#xff1a;macOS系統 虛擬機軟件&#xff1a;VMware Fusion 虛擬機上&#xff1a;centos7內核的Linux系統集群 二、為什么要為每臺虛擬機設置固定ip 由于每次啟動虛擬機&#xff0c;得到的ip可能不一樣&#xff0c;這樣對遠程連接非常不友好&#xff0c…

朱曄的互聯網架構實踐心得S1E7:三十種架構設計模式(上)

設計模式是前人通過大量的實踐總結出來的一些經驗總結和最佳實踐。在經過多年的軟件開發實踐之后&#xff0c;回過頭來去看23種設計模式你會發現很多平時寫代碼的套路和OO的套路和設計模式里總結的類似&#xff0c;這也說明了你悟到的東西和別人悟到的一樣&#xff0c;經過大量…