Xamarin.iOS MvvmCross中详情按钮命令返回Null的问题排查
解决Xamarin.iOS MvvmCross中按钮命令先于文件写入执行的问题
嘿,这个问题我太熟悉了——本质就是异步操作的执行顺序没处理好!你的写入文件逻辑还没完成,详情命令就急着去读文件,第一次自然拿不到数据,第二次文件已经有内容了就正常了。下面给你几个具体的解决步骤:
1. 把文件操作改成异步并等待完成
首先,确保你的写入文件方法是异步的,并且返回Task,这样我们可以明确等待它执行完毕:
// 示例:异步写入每日ID到文件 private async Task WriteDailyIdToFileAsync() { var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var filePath = Path.Combine(documentsPath, "daily_recipe_id.txt"); // 生成随机ID var randomId = Guid.NewGuid().ToString(); // 异步写入,用await等待操作完成 await File.WriteAllTextAsync(filePath, randomId); }
2. 用MvvmCross的异步命令处理逻辑
MvvmCross提供了MvxAsyncCommand专门处理异步命令,别再用普通的MvxCommand了,不然异步操作容易“跑飞”:
// 在ViewModel里定义异步命令 public ICommand ShowRecipeDetailsCommand => new MvxAsyncCommand(ExecuteShowRecipeDetailsAsync); private async Task ExecuteShowRecipeDetailsAsync() { // 第一步:先等写入文件完成 await WriteDailyIdToFileAsync(); // 第二步:再读取文件里的ID var dailyId = await ReadDailyIdFromFileAsync(); // 第三步:有ID再执行详情逻辑 if (!string.IsNullOrEmpty(dailyId)) { // 跳转到详情ViewModel,传递ID参数 await NavigationService.Navigate<RecipeDetailsViewModel>(new { id = dailyId }); } } // 配套的异步读取方法 private async Task<string> ReadDailyIdFromFileAsync() { var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var filePath = Path.Combine(documentsPath, "daily_recipe_id.txt"); if (File.Exists(filePath)) { return await File.ReadAllTextAsync(filePath); } return null; }
3. 优化:避免重复写入当日ID
可以加个日期校验逻辑,防止每天重复生成ID,也能减少不必要的文件操作:
private async Task<string> GetValidDailyIdAsync() { var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var filePath = Path.Combine(documentsPath, "daily_recipe_id.txt"); var today = DateTime.Today.ToString("yyyy-MM-dd"); if (File.Exists(filePath)) { var fileContent = await File.ReadAllTextAsync(filePath); // 假设文件内容格式是「日期|ID」 var parts = fileContent.Split('|'); if (parts.Length == 2 && parts[0] == today) { // 当天已经有ID了,直接返回 return parts[1]; } } // 没有有效ID,生成新的并写入 var newId = Guid.NewGuid().ToString(); await File.WriteAllTextAsync(filePath, $"{today}|{newId}"); return newId; } // 然后命令里直接调用这个优化后的方法 private async Task ExecuteShowRecipeDetailsAsync() { var dailyId = await GetValidDailyIdAsync(); if (dailyId != null) { await NavigationService.Navigate<RecipeDetailsViewModel>(new { id = dailyId }); } }
为什么原来的代码会出问题?
如果你的写入文件方法是同步的但IO操作耗时,或者是异步的但没有用await等待,那么命令的执行线程会直接跳过写入步骤去读文件——这时候文件还没被写入,自然返回Null,点击按钮就没反应;第二次运行时文件已经存在,读取就有数据了。
内容的提问来源于stack exchange,提问作者Ashley van Laer
相关产品推荐
相关产品推荐

