Messages


Messenger


Messenger is another toolkit characteri ViewModel property and is one of the main advantages of Fluent MVVM.

The Fluent MVVM Messenger engine is another toolkit characteristic, tries simply and ease to send and receive info between classes.

With Fluent MVVM Messenger engine any object can be sender, can be subscribe and can be object message, only needs a key for identify the message.

It is localized in MoralesLarios.FluentMVVM.Messages namespace and its principal class is MessengerManager. MessengerManager is a singleton class with ‘_’ (represented with underscore as singleton property name). This singleton can be injected for dependency injection and surprise its dependency call singleton.

MessengerManager is designed for gain development speed and save time to developer but if you are a purist developer, MessegerManager has generics methods versions.

MessengerManager has 3 methods kinds, Senders, Subscribers and Unsubscribes. We will analyze these methods for pairs, (Send – Subscribe) to better understand how it works. Finally we will see Unsubscribe methods.




Messenger Example Project


For our Messenger example, we choose a ViewBag Porperty reduce version.


Simple App

It's very simple app, one data list with a simple filter and reset filter. We will not explain this simple implementation, for more info, view example code in the section end, or ViewBag Porperty section.

We are going to focus in Messenger characteristics.




IMessengerManager


IMessengerManager, is the most important Fluent MVVM Messenger Interface.

In the following sections, we will see its most important methods.

This is your code:

public interface IMessengerManager
{
    bool ExistsByKey(string key);
    bool ExistsByKeyEmisor(string key, [CallerFilePath] string emisor = "");
    void Send(string key);
    void Send(string key, Action callback);
    void Send<TCallback>(string key, Action<TCallback> callback);
    void Send<TMessage>(string key, TMessage messageObject);
    void Send<TMessage>(string key, TMessage messageObject, Action callback);
    void Send<TMessage, TCallback>(string key, TMessage messageObject, Action<TCallback> callback);
    void SendAnonymous(string key, object messageAnnonimous);
    void SendAnonymous(string key, object messageAnnonimous, Action<dynamic> callbackAnonymous);
    void Subscribe(string key, Action action, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void Subscribe<TMessage>(string key, Action<TMessage> action, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void SubscribeWithCallback(string key, Action<Action> actionWithCallbackParameter, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void SubscribeWithCallback<TMessage>(string key, Action<TMessage, Action> actionWithCallbackParameter, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void SubscribeWithCallback<TCallback>(string key, Action<Action<TCallback>> actionWithCallbackParameter, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void SubscribeWithCallback<TMessage, TCallback>(string key, Action<TMessage, Action<TCallback>> actionWithCallbackParameter, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void SubscribeAnonymous(string key, Action<dynamic> actionAnonymous, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void SubscribeAnonymousWithCallback(string key, Action<dynamic, Action<dynamic>> actionWithCallbackAnonymous, [CallerFilePath] string emisor = "", bool isOverwrite = true);
    void Unsubscribe(string key);
    void Unsubscribe(string key, object action);
    int UnsubscribeByThisEmisor([CallerFilePath] string emisor = "");
    int UnsubscribeAll();
}

Interface signatures.



Simple Send / Suscribe



void Send<TMessage>(string key, TMessage messageObject) 
void Subscribe<TMessage>(string key, Action<TMessage> action)

IMessengerManager Interface.

Is the simplest case. Sender and subscriber are connected by a simple key.

Transmitter send an empty message and receiver does a configured job when receive empty message. It is an empty notice message.



For our example, we will a message to open a new window (about window) from a button.

We will add a new View (About window) in our project.


About Window


We will add a new button in MainWindow.xaml.


About button

Xaml MainWindow new code:


<Button Command="{Binding AboutCommand}"  Style="{StaticResource SimpleButton}" Content="About" Height="20" Width="50" Margin="40,25,39,0" 
		Background="LightBlue" >
    <Button.BitmapEffect>
        <DropShadowBitmapEffect/>
    </Button.BitmapEffect>
</Button>

About button has a simple Command (AboutCommand).


We will add the send message in SimpleRelayCommand implementation Action method in our MainViewModel.cs.


using MoralesLarios.FluentMVVM.Messages;
public SimpleRelayCommand AboutCommand => new SimpleRelayCommand(AboutExecuted);

private void AboutExecuted()
{
    MessengerManager._.Send($"{nameof(MainViewModel)}-OpenAbout");
}

$"{nameof(MainViewModel)}-OpenAbout" is a Send method key parameter. By nomenclature use: ClassNane + '-' + descriptive action. In this way we know which class send message at all times only see the key. In greats proyects this can be ussefull.


We will add suscrive code in view codebehind MainWindow.xaml.cs.


using MoralesLarios.FluentMVVM.Messages;
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MessengerManager._.Subscribe($"{nameof(MainViewModel)}-OpenAbout", OpenAboutAction);
    }

    private void OpenAboutAction()
    {
        new About().Show();
    }
}

Suscrive method is located in class constructor.

All process in video.




Simple Send / Suscrive with callback action



public void Send<TCallback>(string key, Action<TCallback> callback);
public void SubscribeWithCallback<TCallback>(string key, Action<Action<TCallback>> actionWithCallbackParameter);

IMessengerManager Interface.

It’s the same example but in this case, we will add a callback action for the user response.

We will add a message confirmation for reset the filters.

We will Add a Command button in xaml code:

<Button Command="{Binding ResetCommand}" Content="Reset" />

About button has a simple Command (AboutCommand).
public SimpleRelayCommand ResetCommand => new SimpleRelayCommand(ResetCommandExecuted, 
() => ! string.IsNullOrEmpty(ViewBag.ArtistNameFilter) ||
      ! string.IsNullOrEmpty(ViewBag.AlbumNameFilter));
 
private void ResetCommandExecuted()
{
    MessengerManager._.Send<bool>($"{nameof(MainViewModel)}-ResetFilter", ResetFilterCallbak);
}
 
private void ResetFilterCallbak(bool response)
{
    if (response) InitialViewBag();
}

ViewModel Code.

Call MessengerManager Send bool message in the ResetCommandExected command method. We will configure ResetFilterCallback method of Action bool type to receive the user’s response. If response in true, we will reset filters textboxex.

public MainWindow()
{
    InitializeComponent();

    MessengerManager._.SubscribeWithCallback<bool>($"{nameof(MainViewModel)}-ResetFilter", ResetFilterAction);
}
 
private void ResetFilterAction(Action<bool> callback)
{
    var userResponse = MessageBox.Show($"Can you reset filters ?", "Reset Filters", MessageBoxButton.YesNo, MessageBoxImage.Information);
 
    var responseResult = userResponse == MessageBoxResult.Yes;
 
    callback(responseResult);
}

View Code-Behind Code.

We will subscribe in the View constructor, with a special method SuscriveWithCallback bool.

Notification response is a typical example for this method. We will store user’s response, and cast to bool this response to send it back to ViewModel.

Screen Filtered.


Window filtered


Notification popup.


Notification Popup




Send / Subscribe with Messenger Object



void Send<TMessage>(string key, TMessage messageObject) 
void Subscribe<TMessage>(string key, Action<TMessage> action)

IMessengerManager Interface.

Is the simplest case. Sender and subscriber are connected by a simple key with a second parameter with extra information.

Transmitter send an empty message and receiver does a configured job when receive empty message. It is an empty notice message.



For our example, we will a personal message to our View, and we will show this message in a MessageBox. In this example, extra information is a string type, but this will be another class.

We will send message personalized information for the close button. The confirmation will be left for the following example.

We will add a Command to the close button.

<Button Command="{Binding CloseCommand}" ToolTip="Close Screen" />

XAML code.

We will add a SimpleRelayCommand, with an executed action, with a MessengerManager Send method call, with a message information.

public SimpleRelayCommand CloseCommand => new SimpleRelayCommand(CloseExecuted);

private void CloseExecuted()
{
    MessengerManager._.Send($"{nameof(MainViewModel)}-Close", $"You are closing the app at {DateTime.Now}");
}

ViewModel code.

Finally, we will add View Code-behind code, with a MessageBox construction whit a message from the ViewModel.

public MainWindow()
{
    InitializeComponent();

    MessengerManager._.Subscribe<string>($"{nameof(MainViewModel)}-Close", Closection);

	// more code
}

private void Closection(string obj)
{
    MessageBox.Show(obj, "Close Window", MessageBoxButton.OK, MessageBoxImage.Information);

    Close();
}

View Code-Behind code.

Close Action





Send / Subscribe with sender object and Simple Sender Callback Response



void Send<TMessage>(string key, TMessage messageObject, Action callback);
void SubscribeWithCallback<TMessage>(string key, Action<TMessage, Action> actionWithCallbackParameter);

IMessengerManager Interface.

This case is the same to the last but adding a sender object to send. It is a little more complete. As we can see Send and SubscribeWithCallback methods are generics TMessage type versions.

Transmitter send a message with a ‘data’ object and receiver does a configured job when receive message with extra info through ‘data’ object received. Inside of configured job, usually in the end we will execute delegate parameter callback. It is an empty notice message. It is a notice message with extra info message with sender callback.



We omitted the example, because are very similar to the above.




Send / Subscribe with sender object and Simple Sender Callback Response with response object



void Send<TMessage, TCallback>(string key, TMessage messageObject, Action<TCallback> callback);
void SubscribeWithCallback<TMessage, TCallback>(string key, Action<TMessage, Action<TCallback>> actionWithCallbackParameter);

IMessengerManager Interface.

This case is the most complicated and the most completed. If we see methods signature we can see that they add two parameters type for method. The first designates the sender message object type and the second the sender response object type, at the same time, this parameters types they are part of Action parameters types too.

Transmitter send a message with a ‘data’ object and receiver does a configured job when receive message with extra info through ‘data’ object received. Inside of configured job, usually in the end we will execute delegate parameter callback adding its response object. It is a notice message with response object information. It is a notice message with extra info message with sender callback and response object.




We create a new internal type to save filter and actual time to send it to the View. We will call it FilterInfo.

public class FilterInfo
{
    public string   FilterName  { get; set; }
    public string   FilterAlbum { get; set; }
    public DateTime ActualTime  { get; set; }
}

FilterInfo class.


Send ViewModel code.

public void Send_Suscribe_with_sender_object_and_simple_sender_Callback_Response_with_responseObject()
{
    var filterInfo = new FilterInfo
    {
        FilterName   = ViewBag.ArtistNameFilter,
        FilterAlbum  = ViewBag.AlbumNameFilter,
        ActualTime   = DateTime.Now
    };

    MessengerManager._.Send<FilterInfo, bool>($"{nameof(MainViewModel)}-CaseComplexWithCallback", filterInfo, CaseComplexWithCallback);
}

private void CaseComplexWithCallback(bool response)
{
            
}

Send method.

View code behind suscribe code.

public MainWindow()
{
    InitializeComponent();

    MessengerManager._.SubscribeWithCallback<FilterInfo, bool>($"{nameof(MainViewModel)}-CaseComplexWithCallback", CaseComplexWithCallbackAction);
}

private void CaseComplexWithCallbackAction(FilterInfo sendMessage, Action<bool> callback)
{
            
}

Suscribe method.


A typical example of this overload is MessageBox show/response iteration,





Anonymous Methods



Anonymous methods are a simplified way of sending / receiving messages. They seek to save time by using anonymous types, something similar to using objects in javascript. This is one of the advantages of using Fluent MVVM, because it allows you to use cases for typed (purist) and other anonymous / dynamic classes for people who want more speed and simplicity of development.

In the last example, we have created a new type for send filter information. If we use anonymous methods, we would have saved creating this class.





Send / Subscribe with Messenger Anonymous Object



void SendAnonymous(string key, object messageAnnonimous);
void SubscribeAnonymous(string key, Action<dynamic> action);

IMessengerManager Interface.

These are the anonymous sender / subscribe messages. They have the same functionality than your brother’s generics, but made for vague like me. These methods aren’t for purists but accelerate development work since we don’t have to create a specific class before only for transmission. As in another cases this has a cons that we lost the intellisense.

Transmitter send a message with an anonymous ‘data’ object and receiver does a configured job when receive message with extra info through ‘data’ object received. It is a notice message with extra info.


Remake the previous (simple format) example with anonymous method.


Send ViewModel code.

public void Simple_Send_Anonymous()
{
    var filterInfo = new
    {
        FilterName  = ViewBag.ArtistNameFilter,
        FilterAlbum = ViewBag.AlbumNameFilter,
        ActualTime  = DateTime.Now
    };

    MessengerManager._.SendAnonymous($"{nameof(MainViewModel)}-SendSimpleAnonymous", filterInfo);
}

flterInfo variable, is anonymous type now.



Suscribe View Code-Behind method code.

public MainWindow()
{
    MessengerManager._.SubscribeAnonymous($"{nameof(MainViewModel)}-SendSimpleAnonymous", SendSimpleAnonymousAction);
}

private void SendSimpleAnonymousAction(dynamic anonymousSendObject)
{
    string   filterName = anonymousSendObject.FilterName;
    string   albumName  = anonymousSendObject.FilterAlbum;
    DateTime sendTime   = anonymousSendObject.ActualTime;

    // more code.
}

flterInfo variable, is anonymous type now.



Send / Subscribe with anonymous sender object and Simple Sender Callback Response with anonymous response object



void SubscribeAnonymous(string key, Action<dynamic> actionAnonymous);
void SubscribeAnonymousWithCallback(string key, Action<dynamic, Action<dynamic>> actionWithCallbackAnonymous);

IMessengerManager Interface.

The same to last case, but adding an anonymous response object.

Transmitter send a message with an anonymous ‘data’ object and receiver does a configured job when receive message with extra info through ‘data’ object received. Inside of configured job, usually in the end we will execute delegate parameter callback adding its response object. It is a notice message with response object information. It is a notice message with extra info message with sender callback and response anonymous object.



We omitted the example, because are very similar to the above.





The lost Suscribe optional parameters



In many previous signatures, two optional parameters were missing for compression. These are the lost parameters:


[CallerFilePath] string emisor = ""

bool isOverwrite = true

Lost parameters.

This is a real signature.

public void Subscribe<T>(string key, Action<T> action, [CallerFilePath] string emisor = "", bool isOverwrite = true);

Real Suscribe signature.



To better understand the lost parameters utility, we must give a small service implementation description.

The Messenger engine, save the subscriber for all Subscribe methods. This technique helps storage delegating its pseudo pk in (key + subscriber) conjunction instead of the (key + Action reference). This helps for individuals subscribers unsubscribes.

Without having to save actions references in internal variables are used for that Visual Studio auto-implementing methods, and more importantly with this technique Messenger engine can easily recognize subscriptions and overwrite them if they already exists so the user does not have to worry about unsubscribe his subscriptions on close/unload the window/class. All this is invisible for the user thought emisor (transmitter) parameter and CallerFilePath attribute.

IsOverride parameter allows throw exception if override subscribe in messenger storage. This force to unsubscribe all subscriptions in all messenger class instantons. It isn’t necessary because the lost performance is priceless and unsubscribes work more tedious.





UnSuscribe Methods






Simple Unsubscribe



void Unsubscribe(string key);

Unsuscribe method.

Unsubscribe all subscriptions subscribe with the key parameter.




Unsubscribe for Action reference



void Unsubscribe(string key, object action);

Unsuscribe method.

Unsubscribe all subscriptions subscribe with the key and action reference parameters. It isn’t very practice method but can be useful when we save action reference in an internal method parameter.





Unsubscribe for actual transmitter



int UnsubscribeByThisEmisor([CallerFilePath] string emisor = "");

Unsuscribe method.

Unsubscribe all subscriptions subscribe with the actual class. It is very useful for windows subscriptions, but it is only advisable for purist’s developments.






UnsubscribeAll



int UnsubscribeAll();

Unsuscribe method.

Clean all Messenger engine subscriptions.







Download Examples Code









1 comentario :

  1. Progressive slots put a number of the} wagered funds into a jackpot pool that progresses with each credit score bet. Individual slot machines can have a progressive jackpot or two or more slot machines additionally be} linked allowing many players to compete for 카지노사이트 a jackpot. The on line casino video games below have a number of the} most revolutionary options out there right now. Pair that with an excellent RTP, and it’s simple to see why they're fan-favorite real money slot video games.

    ResponderEliminar