WPF使用工厂委托DI时如何通过NavigationService向页面传参
现有代码说明
当前已通过工厂委托完成依赖注入注册,需要实现从PrinterDetails页面导航到ProvinceList页面时同步传递参数,并在目标页GetProvinceList方法中读取参数。
现有DI配置(App.xaml.cs)
private void ConfigureServices(ServiceCollection serviceCollection) { serviceCollection.AddTransient<Home>(); serviceCollection.AddSingleton<Func<Home>>(ServiceProvider => ServiceProvider.GetService<Home>); serviceCollection.AddTransient<PrinterDetails>(); serviceCollection.AddSingleton<Func<PrinterDetails>>(ServiceProvider => ServiceProvider.GetService<PrinterDetails>); serviceCollection.AddTransient<ProvinceList>(); serviceCollection.AddSingleton<Func<ProvinceList>>(ServiceProvider => ServiceProvider.GetService<ProvinceList>); serviceCollection.AddSingleton(Configuration); serviceCollection.AddTransient<ISqlDataAccess, SqlDataAccess>(); serviceCollection.AddTransient<IProvinceListViewModel, ProvinceListViewModel>(); serviceCollection.AddTransient(typeof(MainWindow)); }
现有导航发起页代码(PrinterDetails.xaml.cs)
public partial class PrinterDetails : Page, INotifyPropertyChanged { private Func<ProvinceList> ProvinceListFactory { get; } public PrinterDetails(Func<ProvinceList> provinceListFactory) { InitializeComponent(); DataContext = this; PrinterService printerService = new PrinterService(); cmbPrinterList.ItemsSource = printerService.PrinterList(); ProvinceListFactory = provinceListFactory; } private void btnProvince_Click(object sender, RoutedEventArgs e) { ProvinceList nextPage = this.ProvinceListFactory.Invoke(); NavigationService.Navigate(nextPage); } }
现有参数接收页代码(ProvinceList.xaml.cs)
public partial class ProvinceList : Page { private readonly IProvinceListViewModel _provinceListViewModel; public ProvinceList(IProvinceListViewModel provinceListViewModel) { InitializeComponent(); _provinceListViewModel = provinceListViewModel; GetProvinceList(); } private void GetProvinceList() { // 待实现:获取上一页面传递的参数 } }
实现方案(最小改动版本,推荐)
不需要调整现有DI注册逻辑,利用WPF Page自带的导航生命周期即可实现参数传递。
- 修改目标页ProvinceList
- 添加参数接收属性
- 重写
OnNavigatedTo生命周期方法,在导航完成后读取参数、执行业务逻辑 - 移除构造函数中对
GetProvinceList的调用(构造函数执行时参数尚未传递,会导致空值)
public partial class ProvinceList : Page { private readonly IProvinceListViewModel _provinceListViewModel; // 导航参数接收属性,可根据实际业务替换为具体的强类型 public object? PassedParameter { get; set; } public ProvinceList(IProvinceListViewModel provinceListViewModel) { InitializeComponent(); _provinceListViewModel = provinceListViewModel; } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); // 导航完成后执行参数依赖的业务逻辑 GetProvinceList(); } private void GetProvinceList() { // 直接读取PassedParameter即可获取上一页传递的参数 var param = PassedParameter; // 原有业务逻辑 } }
- 修改导航发起页的点击事件
实例化目标页后直接给参数属性赋值,再执行导航即可,不需要改动DI注册代码:
private void btnProvince_Click(object sender, RoutedEventArgs e) { ProvinceList nextPage = this.ProvinceListFactory.Invoke(); // 赋值要传递的参数,支持任意自定义类型、值类型、引用类型 nextPage.PassedParameter = "实际需要传递的业务参数"; NavigationService.Navigate(nextPage); }
可选强类型工厂方案
如果需要把传参逻辑收敛到工厂层、避免页面暴露可写参数属性,可以改造DI注册的工厂委托:
- 修改DI配置
把原有无参工厂替换为支持传参的强类型工厂:
// 替换原有ProvinceList的工厂注册 serviceCollection.AddTransient<ProvinceList>(); serviceCollection.AddSingleton<Func<object, ProvinceList>>(sp => { return (bizParam) => { var page = sp.GetRequiredService<ProvinceList>(); page.PassedParameter = bizParam; return page; }; });
- 修改PrinterDetails的工厂注入和导航逻辑
public partial class PrinterDetails : Page, INotifyPropertyChanged { // 修改工厂类型匹配新注册的委托 private Func<object, ProvinceList> ProvinceListFactory { get; } public PrinterDetails(Func<object, ProvinceList> provinceListFactory) { InitializeComponent(); DataContext = this; PrinterService printerService = new PrinterService(); cmbPrinterList.ItemsSource = printerService.PrinterList(); ProvinceListFactory = provinceListFactory; } private void btnProvince_Click(object sender, RoutedEventArgs e) { // 调用工厂时直接传入参数 ProvinceList nextPage = this.ProvinceListFactory.Invoke("实际需要传递的业务参数"); NavigationService.Navigate(nextPage); } }
注意事项
- 所有依赖导航参数的逻辑必须放到
OnNavigatedTo及之后的生命周期执行,禁止在构造函数中调用,否则会出现参数空引用问题 - 同进程内导航传递参数不需要做序列化处理,直接传递原始对象即可
- 若页面不需要保留参数引用,可在
OnNavigatedFrom生命周期中将参数属性置空,方便GC回收
内容的提问来源于stack exchange,提问作者Tomi
相关产品推荐
相关产品推荐

