【WPF】-MVVM-封装窗口管理器解耦在ViewModel中调用View元素弹出窗口
一.在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.在主界面注册要弹出的窗口类型
这里可以使用PopupWindow,因为同属于View层。
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。
总结:延迟了对象的创建,先把类型(对象的模板)注册进来,当你什么真正需要的时候,容器再使用类型把创建对象出来。
旧书不厌百回读,熟读深思子自知。