使用IPopupService自定义弹窗时出现KeyNotFoundException错误求助
问题原因及解决方案
核心问题
你遇到的KeyNotFoundException是因为依赖注入注册错误,以及ShowPopupAsync的用法与服务配置不匹配:
- 错误的注册方式
AddTransient<SimplePopup, SimplePopupViewModel>()把弹窗页面和ViewModel错误映射,导致PopupService找不到对应的ViewModel关联弹窗 - 弹窗未正确绑定ViewModel,也未实现返回值逻辑
步骤1:修复依赖注入注册
修改MauiProgram.cs中的服务注册代码,将错误映射替换为分别注册弹窗和ViewModel:
// 替换原来的错误注册行 builder.Services.AddTransient<SimplePopup>(); builder.Services.AddTransient<SimplePopupViewModel>();
如果要使用ShowPopupAsync<TViewModel>泛型方法,需额外添加弹窗与ViewModel的接口绑定:
// 让PopupService能通过ViewModel找到对应的弹窗 builder.Services.AddTransient<IPopup<SimplePopupViewModel>, SimplePopup>();
步骤2:完善弹窗的ViewModel绑定与返回值逻辑
修改弹窗后台代码(SimplePopup.xaml.cs)
添加构造函数注入ViewModel,并实现按钮点击返回结果的逻辑:
using CommunityToolkit.Maui.Views; using SimplePopup.ViewModel; namespace SimplePopup; public partial class SimplePopup : Popup { public SimplePopup(SimplePopupViewModel viewModel) { InitializeComponent(); BindingContext = viewModel; // 绑定ViewModel到弹窗 } // Yes按钮点击事件,返回true表示确认 private void YesButton_Clicked(object sender, EventArgs e) { Close(true); } // No按钮点击事件,返回false表示取消 private void NoButton_Clicked(object sender, EventArgs e) { Close(false); } }
修改弹窗XAML代码
给按钮添加点击事件绑定:
<?xml version="1.0" encoding="utf-8" ?> <toolkit:Popup x:Class="SimplePopup.SimplePopup" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewModel="clr-namespace:SimplePopup.ViewModel" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"> <VerticalStackLayout> <Label HorizontalOptions="Center" Text="{Binding Name}" VerticalOptions="Center" /> <Button Text="Yes" Clicked="YesButton_Clicked" /> <Button Text="No" Clicked="NoButton_Clicked" /> </VerticalStackLayout> </toolkit:Popup>
步骤3:修正弹窗调用代码
方式1:直接实例化弹窗(直观易调试)
private readonly IServiceProvider _serviceProvider; private readonly IPopupService _popupService; // 通过构造函数注入所需服务 public MainPage(IServiceProvider serviceProvider, IPopupService popupService) { InitializeComponent(); _serviceProvider = serviceProvider; _popupService = popupService; } private async void Button_Clicked(object sender, EventArgs e) { try { // 获取ViewModel并设置展示数据 var popupVm = _serviceProvider.GetRequiredService<SimplePopupViewModel>(); popupVm.Name = "John Smith"; // 创建弹窗实例并弹出 var popup = new SimplePopup(popupVm); var result = await _popupService.ShowPopupAsync(popup); // 处理用户返回结果 if (result is bool isConfirmed) { Console.WriteLine(isConfirmed ? "用户确认操作" : "用户取消操作"); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
方式2:使用泛型ShowPopupAsync<TViewModel>(需步骤1的接口绑定)
private async void Button_Clicked(object sender, EventArgs e) { try { // 自动创建ViewModel和弹窗,设置数据并获取返回结果 var result = await _popupService.ShowPopupAsync<SimplePopupViewModel>(viewModel => viewModel.Name = "John Smith"); if (result is bool isConfirmed) { Console.WriteLine(isConfirmed ? "用户确认操作" : "用户取消操作"); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
内容的提问来源于stack exchange,提问作者phm
相关产品推荐
相关产品推荐

