MAUI Blazor学习2-创建移动客户端Razor页面
MAUI Blazor学习2-创建移动客户端Razor页面
MAUI Blazor系列目录
为了适配移动客户端,还是要对页面做一下简单的布局。网上其实有一些适合移动客户端的Razor组件库,也可以拿来就用。我写一个简单的todo列表练练手,只实现功能,不考虑美观需求。
实现Master Detail页面
定义一个TodoItem数据类
public class TodoItem { public int Id { get; set; } public string Title { get; set; } = ""; public string Description { get; set; } = ""; public DateTime CreatedDate { get; set; } = DateTime.Now; public TodoPriority Priority { get; set; } = TodoPriority.Low; public bool IsFinished { get; set; } = false; }
编写服务类TodoService,初始化创建一些任务。
public class TodoService { public readonly List<TodoItem> TodoItems = new List<TodoItem>(); public TodoService() { for (int i = 1; i <= 20; i++) { var item = new TodoItem() { Id = i, Title = $"任务{i:00}", Description = $"学习MAUI系列-{i:00}", CreatedDate = (new DateTime(2023, 1, 1)).AddDays(i), Priority = (TodoPriority)(i % 3), IsFinished = false, }; TodoItems.Add(item); } } public void AddTodo(TodoItem item) { TodoItems.Add(item); }
新建任务列表页面,取代天气数据页面,一行一个任务,标题+描述,左右对齐。
@page "/fetchdata" @using MaBlaApp.Data @inject TodoService MyTodoService <ul class="list-group"> <li class="list-group-item list-group-item-primary d-flex justify-content-between"> <strong class="align-self-center">任务列表</strong> <a href="fetchdata/todoitem/create" class="btn btn-primary btn-sm">新建任务</a> </li> </ul> @if (todoItems == null) { <p><em>Loading...</em></p> } else { <div class="list-group" style="overflow:auto"> @foreach (var todoItem in todoItems) { string url = $"fetchdata/todoitem/details/{todoItem.Id}"; <a href=@url class="list-group-item list-group-item-action d-flex justify-content-between mb-1"> <strong>@todoItem.Title</strong> <small>@todoItem.Description</small> </a> } </div> } @code { private List<TodoItem> todoItems; protected override void OnInitialized() { todoItems = MyTodoService.TodoItems; } }
点击一行任务,跳转到该任务的详细页面
@page "/fetchdata/todoitem/details/{Id:int}" @using MaBlaApp.Data @inject TodoService MyTodoService @inject IJSRuntime JSRuntime <ul class="list-group"> <li class="list-group-item list-group-item-primary d-flex justify-content-between"> <strong class="align-self-center">任务详细</strong> <button class="btn btn-primary btn-sm" @onclick=Back>返回</button> </li> </ul> @if (todoItem is null) { <p><em>任务不存在...</em></p> } else { <ul class="list-group" style="overflow:auto"> @foreach (var item in items) { <li class="list-group-item d-flex justify-content-between mb-1"> <strong>@item.Key</strong> <small>@item.Value</small> </li> } <li class="list-group-item d-grid"> <a href=@editUrl class="btn btn-warning btn-sm btn-block">修改</a> </li> </ul> } @code { [Parameter] public int Id { get; set; } private TodoItem todoItem; private Dictionary<string, string> items = new Dictionary<string, string>(); private Dictionary<TodoPriority, string> TodoPriorityName = new Dictionary<TodoPriority, string>(); private string editUrl; protected override void OnInitialized() { todoItem = MyTodoService.TodoItems.FirstOrDefault(x => x.Id == Id); if (todoItem is null) return; TodoPriorityName[TodoPriority.Low] = "低"; TodoPriorityName[TodoPriority.Middle] = "中"; TodoPriorityName[TodoPriority.High] = "高"; items[nameof(todoItem.Id)] = $"{todoItem.Id}"; items[nameof(todoItem.Title)] = $"{todoItem.Title}"; items[nameof(todoItem.Description)] = $"{todoItem.Description}"; items[nameof(todoItem.CreatedDate)] = $"{todoItem.CreatedDate:d}"; items[nameof(todoItem.Priority)] = TodoPriorityName[todoItem.Priority]; items[nameof(todoItem.IsFinished)] = $"{todoItem.IsFinished}"; editUrl = $"fetchdata/todoitem/edit/{todoItem.Id}"; } private async void Back() { await JSRuntime.InvokeVoidAsync("window.history.back"); } }
实现编辑页面
主要是把TodoItem的各个属性,绑定到Razor组件。输入类型涵盖了文本,选择列表,开关。注意,checkbox如果想设置选中状态,必须在元素的属性中增加checked这个属性,它无法定义一个变量去绑定,Blazor提供了@attributes可以绑定动态属性,把它绑定到一个字典Dictionary<string, object>即可,正好解决需要单独出现的属性。这个方法也适用于input组件的disabled禁用。
@page "/fetchdata/todoitem/edit/{Id:int}" @using MaBlaApp.Data @inject TodoService MyTodoService @inject IJSRuntime JSRuntime <ul class="list-group"> <li class="list-group-item list-group-item-primary d-flex justify-content-between"> <strong class="align-self-center">修改任务</strong> <button class="btn btn-primary btn-sm" @onclick=Back>返回</button> </li> </ul> @if (todoItem is null) { <p><em>任务不存在...</em></p> } else { <ul class="list-group" style="overflow:auto"> <li class="list-group-item d-flex justify-content-between mb-1"> <strong class="align-self-center">@nameof(todoItem.Id)</strong> <small>@todoItem.Id</small> </li> <li class="list-group-item d-flex justify-content-between mb-1"> <strong class="align-self-center">@nameof(todoItem.Title)</strong> <input type="text" class="form-control" style="width: 50%;" maxlength="20" @bind-value="todoItem.Title" placeholder="任务标题" /> </li> <li class="list-group-item d-flex justify-content-between mb-1"> <strong class="align-self-center">@nameof(todoItem.Description)</strong> <input type="text" class="form-control" style="width: 50%;" maxlength="20" @bind-value="todoItem.Description" placeholder="任务描述" /> </li> <li class="list-group-item d-flex justify-content-between mb-1"> <strong class="align-self-center">@nameof(todoItem.CreatedDate)</strong> <input type="date" class="form-control" style="width: 50%;" @bind-value="todoItem.CreatedDate" min="2023-1-1" max="2023-12-31" /> </li> <li class="list-group-item d-flex justify-content-between mb-1"> <strong class="align-self-center">优先级</strong> <select class="form-control" style="width: 50%;" @bind="todoItem.Priority"> <option value=@TodoPriority.Low>低</option> <option value=@TodoPriority.Middle>中</option> <option value=@TodoPriority.High>高</option> </select> </li> <li class="list-group-item d-flex justify-content-between mb-1"> <strong class="align-self-center">@nameof(todoItem.IsFinished)</strong> <div class="form-check form-switch"> <input type="checkbox" class="form-check-input" @attributes=IsFinishedCss @bind-value="todoItem.IsFinished" /> </div> </li> </ul> } @code { [Parameter] public int Id { get; set; } private TodoItem todoItem; private Dictionary<string, object>? IsFinishedCss => todoItem.IsFinished ? new() { { "checked", "" }, } : null; protected override void OnInitialized() { todoItem = MyTodoService.TodoItems.FirstOrDefault(x => x.Id == Id); if (todoItem is null) return; } private async void Back() { await JSRuntime.InvokeVoidAsync("window.history.back"); } }
新建任务页面也差不多,详见项目仓库的代码。
测试效果
在手机模拟器上跑了一下,功能是对的,虽然不好看,就这样吧。
DEMO代码地址:https://gitee.com/woodsun/mauiblazorapp