MVVM的目標之一就是為瞭解耦View和ViewModel。View負責視圖展示,ViewModel負責業務邏輯處理,儘量保證 View.xaml.cs中的簡潔,不包含複雜的業務邏輯代碼。 但是在實際情況中是View和ViewModel之間的交互方式還是比較複雜的,View和ViewModel的分離 ...
MVVM的目標之一就是為瞭解耦View和ViewModel。View負責視圖展示,ViewModel負責業務邏輯處理,儘量保證 View.xaml.cs中的簡潔,不包含複雜的業務邏輯代碼。
但是在實際情況中是View和ViewModel之間的交互方式還是比較複雜的,View和ViewModel的分離並不是界定的那麼清晰。
比如以下兩種場景:
1、如果需要某張視圖頁面彈出對話框、彈出子窗體、處理界面元素,播放動畫等。如果這些操作都放在ViewModel中,就會導致ViewModel還是要去處理View級別的元素,造成View和ViewModel的依賴。
最好的辦法就是ViewModel通知View應該做什麼,而View監聽接收到命令,並去處理這些界面需要處理的事情。
2、ViewModel和ViewModel之間也需要通過消息傳遞來完成一些交互。
而MVVM Light 的 Messenger類,提供瞭解決了上述兩個問題的能力:
Messenger類用於應用程式的通信,接受者只能接受註冊的消息類型,另外目標類型可以被指定,用Send<TMessage, TTarget>(TMessage message) 實現,
在這種情況下信息只能被傳遞如果接受者類型和目標參數類型匹配,message可以是任何簡單或者複雜的對象,你可以用特定的消息類型或者創建你自己的類型繼承自他們。
Messager類的主要交互模式就是信息接受和發送(可以理解為“發佈消息服務”和“訂閱消息服務”),是不是想到觀察者模式了,哈哈哈。
MVVM Light Messenger 旨在通過簡單的設計模式來精簡此場景:任何對象都可以是接收端;任何對象都可以是發送端;任何對象都可以是消息。
如圖:
1、View和ViewModel之間的消息交互
在View和ViewModel中進行消息器註冊,相當於訂閱服務。包含消息標誌、消息參數和消息執行方法。如下:
消息標誌token:ViewAlert,用於標識只閱讀某個或者某些Sender發送的消息,並執行相應的處理,所以Sender那邊的token要保持一致
執行方法Action:ShowReceiveInfo,用來執行接收到消息後的後續工作,註意這邊是支持泛型能力的,所以傳遞參數很方便。
View.xaml.cs 代碼如下:
1 public partial class NessagerForView : Window 2 { 3 public NessagerForView() 4 { 5 InitializeComponent(); 6 7 //消息標誌token:ViewAlert,用於標識只閱讀某個或者某些Sender發送的消息,並執行相應的處理,所以Sender那邊的token要保持一致 8 //執行方法Action:ShowReceiveInfo,用來執行接收到消息後的後續工作,註意這邊是支持泛型能力的,所以傳遞參數很方便。 9 Messenger.Default.Register<String>(this, "ViewAlert", ShowReceiveInfo); 10 this.DataContext = new MessengerRegisterForVViewModel(); 11 //卸載當前(this)對象註冊的所有MVVMLight消息 12 this.Unloaded += (sender, e) => Messenger.Default.Unregister(this); 13 } 14 15 /// <summary> 16 /// 接收到消息後的後續工作:根據返回來的信息彈出消息框 17 /// </summary> 18 /// <param name="msg"></param> 19 private void ShowReceiveInfo(String msg) 20 { 21 MessageBox.Show(msg); 22 } 23 }
ViewModel代碼:
1 public class MessengerRegisterForVViewModel:ViewModelBase 2 { 3 4 public MessengerRegisterForVViewModel() 5 { 6 7 } 8 9 #region 命令 10 11 private RelayCommand sendCommand; 12 /// <summary> 13 /// 發送命令 14 /// </summary> 15 public RelayCommand SendCommand 16 { 17 get 18 { 19 if (sendCommand == null) 20 sendCommand = new RelayCommand(() => ExcuteSendCommand()); 21 return sendCommand; 22 23 } 24 set { sendCommand = value; } 25 } 26 27 private void ExcuteSendCommand() 28 { 29 Messenger.Default.Send<String>("ViewModel通知View彈出消息框", "ViewAlert"); //註意:token參數一致 30 } 31 32 #endregion 33 }
結果:
2、ViewModel和ViewModel之間的消息交互,ViewModel和ViewModel在很多種場景下也需要通過消息傳遞來完成一些交互。
比如我打開了兩個視圖,一個視圖是用戶信息列表,一個視圖是用戶信息添加頁面,如果想要達到添加信息之後,用戶信息列表視圖實時刷新,用消息通知無疑是一個很棒的體驗。
我們來模擬一下:
MessengerRegisterViewModel代碼:
1 public class MessengerRegisterViewModel:ViewModelBase 2 { 3 public MessengerRegisterViewModel() 4 { 5 ///Messenger:信使 6 ///Recipient:收件人 7 Messenger.Default.Register<String>(this,"Message",ShowReceiveInfo); 8 } 9 10 11 #region 屬性 12 13 private String receiveInfo; 14 /// <summary> 15 /// 接收到信使傳遞過來的值 16 /// </summary> 17 public String ReceiveInfo 18 { 19 get { return receiveInfo; } 20 set { receiveInfo = value; RaisePropertyChanged(()=>ReceiveInfo); } 21 } 22 23 #endregion 24 25 26 #region 啟動新視窗 27 28 private RelayCommand showSenderWindow; 29 30 public RelayCommand ShowSenderWindow 31 { 32 get { 33 if (showSenderWindow == null) 34 showSenderWindow = new RelayCommand(()=>ExcuteShowSenderWindow()); 35 return showSenderWindow; 36 37 } 38 set { showSenderWindow = value; } 39 } 40 41 private void ExcuteShowSenderWindow() 42 { 43 MessengerSenderView sender = new MessengerSenderView(); 44 sender.Show(); 45 } 46 47 #endregion 48 49 50 #region 輔助函數 51 /// <summary> 52 /// 顯示收件的信息 53 /// </summary> 54 /// <param name="msg"></param> 55 private void ShowReceiveInfo(String msg) 56 { 57 ReceiveInfo += msg+"\n"; 58 } 59 #endregion 60 }
MessengerSenderViewModel代碼:
1 public class MessengerSenderViewModel:ViewModelBase 2 { 3 public MessengerSenderViewModel() 4 { 5 6 } 7 8 #region 屬性 9 private String sendInfo; 10 /// <summary> 11 /// 發送消息 12 /// </summary> 13 public String SendInfo 14 { 15 get { return sendInfo; } 16 set { sendInfo = value; RaisePropertyChanged(()=>SendInfo); } 17 } 18 19 #endregion 20 21 #region 命令 22 23 private RelayCommand sendCommand; 24 /// <summary> 25 /// 發送命令 26 /// </summary> 27 public RelayCommand SendCommand 28 { 29 get 30 { 31 if (sendCommand == null) 32 sendCommand = new RelayCommand(() => ExcuteSendCommand()); 33 return sendCommand; 34 35 } 36 set { sendCommand = value; } 37 } 38 39 private void ExcuteSendCommand() 40 { 41 Messenger.Default.Send<String>(SendInfo, "Message"); 42 } 43 44 #endregion 45 }
結果如下:
轉載請註明出處,謝謝