Haberci

IMessenger Arabirim, farklı nesneler arasında ileti alışverişi yapmak için kullanılabilecek türler için bir sözleşmedir. Bu, başvurulan türlere güçlü referanslar tutmak zorunda kalmadan bir uygulamanın farklı modüllerini birbirinden bağımsız hâle getirmek için yararlı olabilir. Belirli kanallara belirteçle benzersiz olarak tanımlanan iletiler göndermek ve uygulamanın farklı bölümlerinde farklı messenger'lara sahip olmak da mümkündür. MVVM Araç Seti, kutusundan iki uygulama sağlar: WeakReferenceMessenger ve StrongReferenceMessenger: birincisi, alıcılara otomatik bellek yönetimi sunan zayıf başvuruları dahili olarak kullanır, ikincisi ise güçlü başvurular kullanır ve geliştiricilerin artık gerekli olmadığında alıcılarının aboneliklerini el ile kaldırmasını gerektirir (ileti işleyicilerinin kaydını kaldırma hakkında daha fazla ayrıntı aşağıda bulunabilir), ancak bunun karşılığında daha iyi performans ve çok daha az bellek kullanımı sunar.

Platform API'leri:IMessenger, WeakReferenceMessenger, StrongReferenceMessenger, IRecipient<TMessage>, MessageHandler<TRecipient, TMessage>, , ObservableRecipientRequestMessage<T>AsyncRequestMessage<T>CollectionRequestMessage<T>AsyncCollectionRequestMessage<T>, .

Nasıl çalışır?

Uygulayan IMessenger türler, göreli ileti işleyicileri ile alıcılar (iletilerin alıcıları) ve kayıtlı ileti türleri arasındaki bağlantıları korumakla sorumludur. Herhangi bir nesne, bir ileti işleyicisi kullanılarak belirli bir ileti türü için alıcı olarak kaydedilebilir. Bu, örnek bu türde bir ileti göndermek için her IMessenger kullanıldığında çağrılır. Birden çok modülün çakışmaya neden olmadan aynı türdeki iletileri değiş tokuş edebilmesi için belirli iletişim kanalları aracılığıyla (her biri benzersiz bir belirteçle tanımlanan) ileti göndermek de mümkündür. Belirteç olmadan gönderilen iletiler varsayılan paylaşılan kanalı kullanır.

İleti kaydını gerçekleştirmenin iki yolu vardır: ya IRecipient<TMessage> arabirimi aracılığıyla ya da ileti işleyicisi olarak görev yapan bir MessageHandler<TRecipient, TMessage> temsilci kullanarak. birincisi, tüm işleyicileri uzantıya RegisterAll tek bir çağrıyla kaydetmenize olanak tanır ve bu da bildirilen tüm ileti işleyicilerinin alıcılarını otomatik olarak kaydederken, ikincisi daha fazla esnekliğe ihtiyacınız olduğunda veya basit bir lambda ifadesini ileti işleyicisi olarak kullanmak istediğinizde kullanışlıdır.

WeakReferenceMessenger ve StrongReferenceMessenger de, pakete yerleşik iş parçacığı güvenli bir uygulama sunan bir Default özelliğini sunar. Gerekirse, örneğin uygulamanın farklı bir modülüne (örneğin, aynı işlemde çalışan birden çok pencere) farklı bir DI hizmet sağlayıcısı eklendiğinde birden çok messenger örneği oluşturmak da mümkündür.

Not

WeakReferenceMessenger türü kullanımı daha basit olduğundan ve MvvmLight kitaplığındaki messenger türünün davranışıyla eşleştiğinden, MVVM Araç Seti'ndeki ObservableRecipient türü tarafından kullanılan varsayılan türdür. StrongReferenceType, o sınıfın oluşturucusuna bir örnek geçirilerek yine de kullanılabilir.

İleti gönderme ve alma

Aşağıdakileri inceleyin:

// 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));

Bu ileti türünün, oturum açmış kullanıcının kullanıcı adını ve profil resmini içeren bir başlık bölümü, konuşmaların listelendiği bir panel ve seçiliyse mevcut konuşmadaki iletileri gösteren başka bir panel görüntüleyen basit bir mesajlaşma uygulamasında kullanıldığını düşünelim. Diyelim ki bu üç bölüm sırasıyla HeaderViewModel, ConversationsListViewModel ve ConversationViewModel türleri tarafından destekleniyor. Bu senaryoda, LoggedInUserChangedMessage iletisi bir oturum açma işlemi tamamlandıktan sonra HeaderViewModel tarafından gönderilebilir ve diğer iki görünüm modeli de bunun için işleyiciler kaydedebilir. Örneğin, ConversationsListViewModel yeni kullanıcıya ait konuşma listesini yükler; ConversationViewModel ise, bir konuşma varsa, yalnızca mevcut konuşmayı kapatır.

Örnek, IMessenger tüm kayıtlı alıcılara ileti teslim etme işlemini üstlenir. Alıcının belirli bir türe ait iletilere abone olabileceğini unutmayın. Devralınan ileti türlerinin MVVM Araç Seti tarafından sağlanan varsayılan IMessenger uygulamalarda kayıtlı olmadığını unutmayın.

Bir alıcıya artık ihtiyaç duyulmadığında, ileti almayı durdurabilmesi için kaydını kaldırmanız gerekir. Kaydı ileti türüne, kayıt belirtecine veya alıcıya göre kaldırabilirsiniz:

// 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);

Uyarı

Daha önce belirtildiği gibi, alıcıları izlemek için zayıf başvurular kullandığından, türü kullanırken WeakReferenceMessenger bu kesinlikle gerekli değildir; bu, kullanılmayan alıcıların hala etkin ileti işleyicileri olsa bile çöp toplama için uygun olacağı anlamına gelir. Yine de performansları geliştirmek için aboneliklerini kaldırmak iyi bir uygulamadır. Öte yandan, StrongReferenceMessenger uygulaması kayıtlı alıcıları izlemek için güçlü referanslar kullanır. Bu, performans nedeniyle yapılır ve bellek sızıntılarını önlemek için kayıtlı her alıcının el ile kaydının kaldırılmış olması gerektiği anlamına gelir. Yani, bir alıcı kayıtlı olduğu sürece, kullanımda olan StrongReferenceMessenger örneği ona etkin bir referans tutar; bu da çöp toplayıcının söz konusu örneği toplamasını engeller. Bunu ya el ile yapabilir ya da ObservableRecipient öğesinden türeyebilirsiniz; bu öğe, varsayılan olarak, devre dışı bırakıldığında alıcıya ait tüm mesaj kayıtlarının kaldırılmasını otomatik olarak gerçekleştirir (bu konuda daha fazla bilgi için ObservableRecipient belgelerine bakın).

İleti işleyicilerini kaydetmek için arabirimini IRecipient<TMessage> kullanmak da mümkündür. Bu durumda, her alıcının belirli bir ileti türü için arabirimi uygulaması ve iletileri alırken çağrılacak bir Receive(TMessage) yöntem sağlaması gerekir, örneğin:

// 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));

İstek iletilerini kullanma

Messenger örneklerinin bir diğer kullanışlı özelliği de bir modülden diğerine değer istemek için kullanılabilmesidir. Bunu yapmak için paket aşağıdaki gibi kullanılabilecek bir temel RequestMessage<T> sınıf içerir:

// 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> sınıfı, bir LoggedInUserRequestMessage öğesinden içerdiği User nesnesine dönüştürmeyi sağlayan örtük bir dönüştürücü içerir. Bu ayrıca ileti için bir yanıt alınıp alınmadığını denetler ve durum böyle değilse bir özel durum oluşturur. Bu zorunlu yanıt garantisi olmadan istek iletileri göndermek de mümkündür: Yalnızca döndürülen iletiyi yerel bir değişkende depolayın ve ardından yanıt değerinin kullanılabilir olup olmadığını el ile denetleyin. Bunun yapılması, Send yöntemi döndüğünde bir yanıt alınmazsa otomatik özel durumu tetiklemez.

Aynı ad alanı, diğer senaryolar için temel istekler iletisini de içerir: AsyncRequestMessage<T>, CollectionRequestMessage<T> ve AsyncCollectionRequestMessage<T>. Eşzamansız bir istek mesajını şu şekilde kullanabilirsiniz:

// 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>();

Örnekler