WPF技术问询:如何从Window向Page的ViewModel传递IConfiguration
问题描述
我之前能轻松将appsettings.json中的IConfiguration传递给WPF的Window,现在希望用规范方式把它传给Window里Frame加载的Page对应的ViewModel(该ViewModel作为Page的DataContext),避免手动重新读取配置。以下是当前代码及尝试过的操作:
public partial class HomeWindow : Window { readonly IConfiguration _config; public HomeWindow(IConfiguration config) { _config = config; // 用JSON设置实例化对象 InitializeComponent(); DataContext = new HomeWindowVM(config) } } public class HomeWindowVM { readonly IConfiguration _config; //public INotify btnCheckoutPage { get; set; } public object MyFrameContent { get; set; } public HomeWindowVM(IConfiguration config) { _config = config; CheckoutClickCommand = new MyCommand(CheckoutClick); ShipmentClickCommand = new MyCommand(ShipmentClick); frameURI = new INotify(); frameVis = new INotify(); frameVis.MyProperty = "Hidden"; } private void CheckoutClick() { frameURI.MyProperty = "CheckoutPage.xaml"; frameVis.MyProperty = "Visible"; // 我试过这段代码 //CheckoutPage checkoutPage = new CheckoutPage(_config); //MyFrameContent = new CheckoutPage(_config); } } public partial class CheckoutPage : Page { readonly IConfiguration _config; public CheckoutPage() { InitializeComponent(); DataContext = new CheckoutPageVM(); } public CheckoutPage(IConfiguration config) { _config = config; InitializeComponent(); DataContext = new CheckoutPageVM(config); } } public class CheckoutPageVM { readonly IConfiguration _config; public CheckoutPageVM(IConfiguration config) { _config = config; LblErrorProjectNum = new INotify(); LblErrorProjectNum.MyProperty = "Hidden"; LblErrorTransfer = new INotify(); LblErrorTransfer.MyProperty = "Hidden"; CheckoutSubmitCommand = new MyCommand(CheckoutSubmit); } }
解决方案
方案1:直接实例化Page并传递配置(简单直接)
你之前尝试的实例化CheckoutPage(_config)是可行的,问题在于你用了URI导航的方式(frameURI.MyProperty = "CheckoutPage.xaml"),这种方式无法传递参数。改为直接实例化Page并通过Frame导航:
修改HomeWindowVM的CheckoutClick方法:
private void CheckoutClick() { // 假设你的Frame控件在HomeWindow的XAML中命名为MainFrame var mainFrame = Application.Current.MainWindow.FindName("MainFrame") as Frame; if (mainFrame != null) { // 直接用带配置参数的构造函数创建Page mainFrame.Navigate(new CheckoutPage(_config)); frameVis.MyProperty = "Visible"; } }
这样CheckoutPage会通过构造函数接收IConfiguration,并传递给自己的ViewModel,无需手动重读配置。
方案2:使用依赖注入容器(推荐规范)
如果项目使用Microsoft.Extensions.DependencyInjection这类DI容器,注册IConfiguration为单例后,容器会自动完成依赖注入,无需手动传递:
- 启动时注册服务:
var services = new ServiceCollection(); // 注册IConfiguration为单例 services.AddSingleton<IConfiguration>(configuration); // 注册Page和ViewModel services.AddTransient<CheckoutPage>(); services.AddTransient<CheckoutPageVM>(); services.AddTransient<HomeWindow>(); services.AddTransient<HomeWindowVM>(); var serviceProvider = services.BuildServiceProvider();
- 修改
CheckoutPage构造函数,依赖注入ViewModel:
public partial class CheckoutPage : Page { public CheckoutPage(CheckoutPageVM viewModel) { InitializeComponent(); DataContext = viewModel; } }
CheckoutPageVM保持原构造函数,容器自动注入IConfiguration:
public class CheckoutPageVM { readonly IConfiguration _config; public CheckoutPageVM(IConfiguration config) { _config = config; // 原有初始化代码 } }
- 在
HomeWindowVM中通过容器获取CheckoutPage:
private readonly IServiceProvider _serviceProvider; public HomeWindowVM(IConfiguration config, IServiceProvider serviceProvider) { _config = config; _serviceProvider = serviceProvider; // 原有初始化代码 } private void CheckoutClick() { var checkoutPage = _serviceProvider.GetRequiredService<CheckoutPage>(); var mainFrame = Application.Current.MainWindow.FindName("MainFrame") as Frame; mainFrame?.Navigate(checkoutPage); frameVis.MyProperty = "Visible"; }
这种方式符合依赖注入的设计原则,代码耦合度更低,维护性更好。
方案3:通过ViewModel传递配置
如果不想用DI容器,可以先创建CheckoutPageVM并传入配置,再把ViewModel传给CheckoutPage:
- 修改
CheckoutPage,添加接收ViewModel的构造函数:
public partial class CheckoutPage : Page { public CheckoutPage(CheckoutPageVM viewModel) { InitializeComponent(); DataContext = viewModel; } }
- 修改
HomeWindowVM的CheckoutClick方法:
private void CheckoutClick() { var checkoutVM = new CheckoutPageVM(_config); var checkoutPage = new CheckoutPage(checkoutVM); var mainFrame = Application.Current.MainWindow.FindName("MainFrame") as Frame; mainFrame?.Navigate(checkoutPage); frameVis.MyProperty = "Visible"; }
这种方式也能实现配置的传递,且无需修改原有ViewModel的构造逻辑。
内容的提问来源于stack exchange,提问作者Bigbear
相关产品推荐
相关产品推荐

