一.在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。
總結:延遲了對象的創建,先把類型(對象的模板)註冊進來,當你什麼真正需要的時候,容器再使用類型把創建對象出來。