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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章