Blazor待办应用最后一个复选框无法保持勾选且无法写入JSON文件
问题分析与解决方案
核心问题
- 双向绑定与手动事件冲突:复选框同时使用
@bind="todo.IsDone"和@oninput="CheckboxChanged",导致状态更新逻辑冲突,最后一项的状态无法正确同步。 - TodoItem无属性变更通知:普通类
TodoItem的属性变化无法被Blazor组件自动感知,引发UI与数据模型的状态不一致。 - 同步文件操作的不当包装:用
Task.Run包裹同步文件写入方法,可能引发线程安全问题,且最后一项的状态未及时被捕获就执行了写入。
具体修复步骤
1. 移除冲突事件绑定,改用绑定回调
将复选框的@oninput替换为@bind:after,确保绑定完成后再执行写入逻辑,避免冲突:
<input @key="todo" type="checkbox" @bind="todo.IsDone" @bind:after="() => CheckboxChanged()" />
简化CheckboxChanged方法:
public async Task CheckboxChanged() { await todoApi.WriteAsync(todos); // @bind:after会自动触发组件更新,无需手动调用StateHasChanged }
2. 让TodoItem支持属性变更通知(推荐)
修改TodoItem实现INotifyPropertyChanged,确保属性变化时组件能及时感知:
using System.ComponentModel; using System.Runtime.CompilerServices; public class TodoItem : INotifyPropertyChanged { private string _title; private bool _isDone; public string Title { get => _title; set { _title = value; OnPropertyChanged(); } } public bool IsDone { get => _isDone; set { _isDone = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
3. 优化JSON读写为异步实现
将JsonApi的同步方法改为异步,避免阻塞线程:
using System.Text.Json; namespace Todolist.API { public class JsonApi: IApi { private readonly string _filePath = Path.Combine(AppContext.BaseDirectory, "todos.json"); public async Task WriteAsync(List<TodoItem> todos) { string json = JsonSerializer.Serialize(todos); await File.WriteAllTextAsync(_filePath, json); } public async Task<List<TodoItem>> ReadAsync() { if (!File.Exists(_filePath)) { await File.CreateAsync(_filePath); return new List<TodoItem>(); } var json = await File.ReadAllTextAsync(_filePath); if (string.IsNullOrWhiteSpace(json)) return new List<TodoItem>(); return JsonSerializer.Deserialize<List<TodoItem>>(json) ?? new List<TodoItem>(); } } // 更新IApi接口定义 public interface IApi { Task WriteAsync(List<TodoItem> todos); Task<List<TodoItem>> ReadAsync(); } }
4. 调整组件初始化和添加逻辑
修改OnInitializedAsync和ValidFormSubmitted方法,适配异步接口:
protected override async Task OnInitializedAsync() { todos = await todoApi.ReadAsync(); Console.WriteLine("Initialized"); } public async Task ValidFormSubmitted() { Console.WriteLine("Clicked"); if(!string.IsNullOrWhiteSpace(newTodo)) { todos.Add(new TodoItem { Title = newTodo }); await todoApi.WriteAsync(todos); newTodo = string.Empty; } }
额外注意事项
- 确保文件路径正确:使用
AppContext.BaseDirectory获取应用根目录,避免因工作目录不同导致的文件读写问题。 - 避免在UI线程执行同步IO操作:异步文件操作能提升Blazor应用的响应性,尤其是在Server模式下。
内容的提问来源于stack exchange,提问作者zigjag
相关产品推荐
相关产品推荐

