WPF MVVM:不使用Prism/MVVM Light,如何向第二个窗口ViewModel传两个参数?
无框架实现跨ViewModel参数传递的几种方案
方案1:构造函数直接传递参数
这是最直观的方式,通过第二个ViewModel的带参构造函数完成参数注入,适合简单的参数传递场景。
步骤:
- 为第二个ViewModel定义包含目标参数的构造函数
- 在第一个窗口打开第二个窗口前,实例化第二个ViewModel并传入参数
- 将实例化后的ViewModel绑定到第二个窗口的
DataContext
代码示例:
// 第一个窗口的ViewModel public class FirstViewModel { public ICommand OpenSecondWindowCommand { get; } public FirstViewModel() { OpenSecondWindowCommand = new RelayCommand(OpenSecondWindow); } private void OpenSecondWindow() { // 准备要传递的两个参数 string param1 = "来自第一个VM的参数1"; int param2 = 123; // 实例化第二个ViewModel并传入参数 var secondVm = new SecondViewModel(param1, param2); var secondWindow = new SecondWindow { DataContext = secondVm }; secondWindow.Show(); } } // 第二个窗口的ViewModel public class SecondViewModel { public string ReceivedParam1 { get; } public int ReceivedParam2 { get; } // 带参构造函数接收参数 public SecondViewModel(string param1, int param2) { ReceivedParam1 = param1; ReceivedParam2 = param2; } } // 自定义RelayCommand(不依赖框架需自行实现基础命令) public class RelayCommand : ICommand { private readonly Action _execute; private readonly Func<bool>? _canExecute; public event EventHandler? CanExecuteChanged; public RelayCommand(Action execute, Func<bool>? canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object? parameter) => _canExecute?.Invoke() ?? true; public void Execute(object? parameter) => _execute(); }
方案2:使用共享数据容器
通过全局可访问的共享类存储参数,适合需要在多个ViewModel间共享数据的场景。
步骤:
- 创建单例模式的共享数据类,定义需要传递的参数属性
- 第一个ViewModel将参数赋值给共享类的属性
- 第二个ViewModel在初始化时从共享类读取参数
代码示例:
// 共享数据容器(单例模式) public class SharedDataContainer { private static SharedDataContainer? _instance; public static SharedDataContainer Instance => _instance ??= new SharedDataContainer(); // 私有构造函数确保单例 private SharedDataContainer() { } // 定义要传递的参数 public string? Param1 { get; set; } public int Param2 { get; set; } } // 第一个窗口的ViewModel public class FirstViewModel { public ICommand OpenSecondWindowCommand { get; } public FirstViewModel() { OpenSecondWindowCommand = new RelayCommand(OpenSecondWindow); } private void OpenSecondWindow() { // 将参数存入共享容器 var sharedData = SharedDataContainer.Instance; sharedData.Param1 = "共享参数1"; sharedData.Param2 = 456; // 打开第二个窗口 var secondWindow = new SecondWindow(); secondWindow.Show(); } } // 第二个窗口的ViewModel public class SecondViewModel { public string? ReceivedParam1 { get; } public int ReceivedParam2 { get; } public SecondViewModel() { // 从共享容器读取参数 var sharedData = SharedDataContainer.Instance; ReceivedParam1 = sharedData.Param1; ReceivedParam2 = sharedData.Param2; } }
方案3:通过事件与委托传递
利用C#事件机制,让第一个ViewModel触发事件传递参数,第二个ViewModel订阅事件接收参数,适合松耦合的场景。
步骤:
- 在第一个ViewModel中定义带参数的事件
- 打开第二个窗口后,让第二个ViewModel订阅该事件
- 第一个ViewModel触发事件时传递参数
代码示例:
// 定义事件参数类,包含要传递的参数 public class ParamEventArgs : EventArgs { public string Param1 { get; } public int Param2 { get; } public ParamEventArgs(string param1, int param2) { Param1 = param1; Param2 = param2; } } // 第一个窗口的ViewModel public class FirstViewModel { public ICommand OpenSecondWindowCommand { get; } // 定义传递参数的事件 public event EventHandler<ParamEventArgs>? ParamPassed; public FirstViewModel() { OpenSecondWindowCommand = new RelayCommand(OpenSecondWindow); } private void OpenSecondWindow() { var secondVm = new SecondViewModel(); var secondWindow = new SecondWindow { DataContext = secondVm }; // 让第二个ViewModel订阅事件 ParamPassed += secondVm.ReceiveParams; secondWindow.Show(); // 触发事件传递参数 ParamPassed?.Invoke(this, new ParamEventArgs("事件传递参数1", 789)); } } // 第二个窗口的ViewModel public class SecondViewModel { public string? ReceivedParam1 { get; private set; } public int ReceivedParam2 { get; private set; } // 事件处理方法,接收参数 public void ReceiveParams(object? sender, ParamEventArgs e) { ReceivedParam1 = e.Param1; ReceivedParam2 = e.Param2; } }
注意事项:
- 方案1属于紧耦合,若后续参数变化需要修改构造函数,适合简单场景
- 方案2的单例容器要注意线程安全,多线程场景需加锁;同时要避免内存泄漏,不需要时可重置参数
- 方案3的事件订阅要记得在第二个窗口关闭时取消订阅,防止内存泄漏
内容的提问来源于stack exchange,提问作者Laos
相关产品推荐
相关产品推荐

