【WPF】-MVVM-封装窗口管理器解耦在ViewModel中弹出窗口

发布时间 2023-05-07 13:18:33作者: David.Meng

一.在ViewModel层直接调用View弹出窗体

如下图所示,这样做就发生了在ViewModel层直接使用了View,两者产生了耦合,ViewModel里是不应该包含View的,这不是我们期望的。

 

二.封装窗口管理器解耦在ViewModel中调用View

2.1.封装窗口管理器

延迟了对象的创建,先把类型(对象的模板)注册进来,当你什么真正需要的时候,容器再使用类型把创建对象出来

 1  /// <summary>
 2     /// 窗口管理器
 3     /// </summary>
 4     public class WindowManager
 5     {
 6         static Dictionary<string, WindowStruct> _regWindowContainer = new Dictionary<string, WindowStruct>();
 7 
 8         /// <summary>
 9         /// 注册类型
10         /// </summary>
11         /// <typeparam name="T"></typeparam>
12         /// <param name="name"></param>
13         /// <param name="owner"></param>
14         public static void Register<T>(string name, System.Windows.Window owner = null)
15         {
16             if (!_regWindowContainer.ContainsKey(name))
17             {
18                 _regWindowContainer.Add(name, new WindowStruct { WindowType = typeof(T), Owner = owner });
19             }
20         }
21 
22         /// <summary>
23         /// 获取对象
24         /// </summary>
25         /// <typeparam name="T"></typeparam>
26         /// <param name="name"></param>
27         /// <param name="dataContext"></param>
28         /// <returns></returns>
29         public static bool ShowDialog<T>(string name, T dataContext)
30         {
31             if (_regWindowContainer.ContainsKey(name))
32             {
33                 Type type = _regWindowContainer[name].WindowType;
34                 //反射创建窗体对象
35                 var window = (System.Windows.Window)Activator.CreateInstance(type);
36                 window.Owner = _regWindowContainer[name].Owner;
37                 window.DataContext = dataContext;
38                 return window.ShowDialog() == true;
39             }
40 
41             return false;
42         }
43     }
44 
45     public class WindowStruct
46     {
47         public Type WindowType { get; set; }
48         public System.Windows.Window Owner { get; set; }
49     }

 

2.2.在主界面注册要弹出的窗口类型

 1  /// <summary>
 2     /// DialogMainWindow.xaml 的交互逻辑
 3     /// </summary>
 4     public partial class DialogMainWindow : Window
 5     {
 6         public DialogMainWindow()
 7         {
 8             InitializeComponent();
 9             //注册窗体类型到容器
10             //通过第三方窗口容器View和ViewModel解耦
11             WindowManager.Register<PopupWindow>("PopupWindow", this);
12             this.DataContext = new PopupWindowViewModel();
13         }
14     }

 

2.3.ViewModel层弹出窗体

 1 public class PopupWindowViewModel: CommandBase
 2     {
 3         public CommandBase BtnShowDialogCommand { get; set; }
 4 
 5 
 6         public PopupWindowViewModel()
 7         {
 8             BtnShowDialogCommand = new CommandBase()
 9             {
10                 DoExecute = new Action<object>((obj) => {
11                     //直接在ViewModel层调用View层,产生了耦合
12                     //PopupWindow popupWindow = new PopupWindow();
13                     //popupWindow.ShowDialog();
14 
15                    
16                     PopupModel<string> popupModel = new PopupModel<string>();
17                     popupModel.Value = obj.ToString();
18 
19                     //经过这样的封装,解耦了在ViewModel层直接使用View
20                     WindowManager.ShowDialog<PopupModel<string>>("PopupWindow", popupModel);
21                 }),
22                 DoCanExecute = new Func<object, bool>((obj) => {
23                     return true;
24                 })
25             };
26         }
27     }

 

经过这样的封装,解耦了在ViewModel层直接使用View。
总结:延迟了对象的创建,先把类型(对象的模板)注册进来,当你什么真正需要的时候,容器再使用类型把创建对象出来。