信使

介面 IMessenger 是類型合約,可用來在不同對象之間交換訊息。 這很適合用來分離應用程式的不同模組,而不需要保留所參考類型的強式參考。 您也可以將訊息傳送至令牌唯一識別的特定通道,並在應用程式的不同區段中有不同的 Messenger。 MVVM 工具組提供現成的兩個實作:和 StrongReferenceMessengerWeakReferenceMessenger前者在內部使用弱式參考,為收件者提供自動記憶體管理,而後者則使用強式參考,並要求開發人員在不再需要收件者時手動取消訂閱收件者(如需有關如何取消註冊訊息處理程式的詳細數據,請參閱下方),但為了交換,提供更佳的效能,而且記憶體使用量要少得多。

平臺 API:IMessengerWeakReferenceMessengerStrongReferenceMessengerRequestMessage<T>MessageHandler<TRecipient, TMessage>IRecipient<TMessage>ObservableRecipient、、、 。 CollectionRequestMessage<T>AsyncCollectionRequestMessage<T>AsyncRequestMessage<T>

運作方式

實作 IMessenger 的類型負責維護收件者(郵件接收者)與其已註冊的郵件類型,以及相對訊息處理程式之間的連結。 任何物件都可以使用訊息處理程式註冊為指定郵件類型的收件者,每當 IMessenger 實例用來傳送該類型的訊息時,就會叫用這個物件。 您也可以透過特定通道傳送訊息(每個通道都是由唯一令牌識別),讓多個模組可以交換相同類型的訊息,而不會造成衝突。 未使用令牌傳送的訊息會使用預設共用通道。

有兩種方式可以執行訊息註冊:透過 IRecipient<TMessage> 介面,或使用做為訊息處理程式的 MessageHandler<TRecipient, TMessage> 委派。 第一個可讓您使用對延伸模組的單一呼叫 RegisterAll 來註冊所有處理程式,以自動註冊所有宣告的郵件處理程式的收件者,而當您需要更多彈性或想要使用簡單 Lambda 表達式做為訊息處理程式時,後者會很有用。

WeakReferenceMessengerStrongReferenceMessenger 也會公開Default屬性,提供內建的線程安全實作套件。 此外,您也可以視需要建立多個 Messenger 實例,例如,將不同的信使服務提供者插入應用程式的不同模組中(例如,在同一個進程中執行的多個視窗)。

注意

WeakReferenceMessenger因為類型較容易使用,而且符合連結MvvmLight庫中 Messenger 類型的行為,所以它是MVVM Toolkit 中類型所使用的ObservableRecipient預設類型。 StrongReferenceType將 實體傳遞至該類別的建構函式,仍然可以使用 。

傳送和接收訊息

請考慮下列事項:

// Create a message
public class LoggedInUserChangedMessage : ValueChangedMessage<User>
{
    public LoggedInUserChangedMessage(User user) : base(user)
    {        
    }
}

// Register a message in some module
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this, (r, m) =>
{
    // Handle the message here, with r being the recipient and m being the
    // input message. Using the recipient passed as input makes it so that
    // the lambda expression doesn't capture "this", improving performance.
});

// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));

假設這個訊息類型用於簡單的訊息應用程式中,如果已選取,則會顯示標頭,其中包含目前已記錄使用者的使用者名稱和配置檔影像、具有交談清單的面板,以及另一個包含目前交談訊息的面板。 假設、 ConversationsListViewModelConversationViewModel 類型分別支援HeaderViewModel這三個區段。 在此案例中, LoggedInUserChangedMessage 訊息可能會在登入作業完成之後傳送 HeaderViewModel ,而其他兩個 viewmodel 可能會為其註冊處理程式。 例如, ConversationsListViewModel 將會載入新使用者的交談清單,如果 ConversationViewModel 目前交談存在,則只會關閉目前的交談。

實例 IMessenger 會負責傳遞訊息給所有已註冊的收件者。 請注意,收件者可以訂閱特定類型的訊息。 請注意,繼承的訊息類型不會在MVVM Toolkit所提供的預設 IMessenger 實作中註冊。

當不再需要收件者時,您應該將其取消註冊,使其停止接收訊息。 您可以透過訊息類型、註冊令牌或收件者取消註冊:

// Unregisters the recipient from a message type
WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage>(this);

// Unregisters the recipient from a message type in a specified channel
WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage, int>(this, 42);

// Unregister the recipient from all messages, across all channels
WeakReferenceMessenger.Default.UnregisterAll(this);

警告

如前所述,使用類型時 WeakReferenceMessenger 並非絕對必要,因為它使用弱式參考來追蹤收件者,這表示即使未使用的收件者仍然具有作用中的郵件處理程式,仍有資格進行垃圾收集。 不過,若要改善效能,請取消訂閱它們仍然是很好的做法。 另一方面,實作 StrongReferenceMessenger 會使用強式參考來追蹤已註冊收件者。 這是基於效能考慮而完成的,這表示應該手動取消註冊每個已註冊的收件者,以避免記憶體流失。 也就是說,只要收件者已註冊, StrongReferenceMessenger 使用中的實例就會保留其作用中參考,這可防止垃圾收集行程能夠收集該實例。 您可以手動處理此作業,或繼承自 ObservableRecipient,根據預設,此動作會自動在停用收件者時移除收件者的所有郵件註冊(如需詳細資訊,請參閱檔 ObservableRecipient

您也可以使用 IRecipient<TMessage> 介面來註冊訊息處理程式。 在此情況下,每個收件者都必須實作指定訊息類型的介面,並提供 Receive(TMessage) 在接收郵件時要叫用的方法,如下所示:

// Create a message
public class MyRecipient : IRecipient<LoggedInUserChangedMessage>
{
    public void Receive(LoggedInUserChangedMessage message)
    {
        // Handle the message here...   
    }
}

// Register that specific message...
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this);

// ...or alternatively, register all declared handlers
WeakReferenceMessenger.Default.RegisterAll(this);

// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));

使用要求訊息

Messenger 實例的另一個實用功能是,它們也可用來向另一個模組要求值。 為了這樣做,封裝包含基 RequestMessage<T> 類,其可以使用如下:

// Create a message
public class LoggedInUserRequestMessage : RequestMessage<User>
{
}

// Register the receiver in a module
WeakReferenceMessenger.Default.Register<MyViewModel, LoggedInUserRequestMessage>(this, (r, m) =>
{
    // Assume that "CurrentUser" is a private member in our viewmodel.
    // As before, we're accessing it through the recipient passed as
    // input to the handler, to avoid capturing "this" in the delegate.
    m.Reply(r.CurrentUser);
});

// Request the value from another module
User user = WeakReferenceMessenger.Default.Send<LoggedInUserRequestMessage>();

類別包含隱含轉換 RequestMessage<T> 子,可讓 從 LoggedInUserRequestMessage 轉換成其自主 User 物件。 這也會檢查是否已收到訊息的回應,如果不是這種情況,則會擲回例外狀況。 您也可以在沒有這項強制回應保證的情況下傳送要求訊息:只要將傳回的訊息儲存在局部變數中,然後手動檢查回應值是否可用。 如果方法傳回時 Send 未收到回應,這樣做將不會觸發自動例外狀況。

相同的命名空間也包含其他案例的基底要求訊息: AsyncRequestMessage<T>CollectionRequestMessage<T>AsyncCollectionRequestMessage<T>。 以下說明如何使用異步要求訊息:

// Create a message
public class LoggedInUserRequestMessage : AsyncRequestMessage<User>
{
}

// Register the receiver in a module
WeakReferenceMessenger.Default.Register<MyViewModel, LoggedInUserRequestMessage>(this, (r, m) =>
{
    m.Reply(r.GetCurrentUserAsync()); // We're replying with a Task<User>
});

// Request the value from another module (we can directly await on the request)
User user = await WeakReferenceMessenger.Default.Send<LoggedInUserRequestMessage>();

範例

  • 查看 範例應用程式 (適用於多個 UI 架構),以查看 MVVM 工具組的運作情形。
  • 您也可以在單元測試中找到更多範例。