Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mvvm light Messenger.Default.Register in View codebehind?

The BookShelf solution John Papa presented at Mix11 has something that sounds a bit odd to me... It uses an MVVM pattern and MVVM Light toolkit... Everything is great. The only thing I can't understand is this: In codebehind of Views it register for a couple of messages, here it is the code:

public partial class BookView : Page
{
    public BookView()
    {
        InitializeComponent();
        //btnEdit.SetBinding(Button.IsEnabledProperty, new Binding("User.IsAuthenticated") { Source = Application.Current.Resources["WebContext"] });
        Title = ApplicationStrings.HomePageTitle;
        RegisterMessages();
    }

    private void RegisterMessages()
    {
        Messenger.Default.Register<LaunchEditBookMessage>(this, OnLaunchEditBook);
        Messenger.Default.Register<SavedBookDialogMessage>(this, OnSaveBookDialogMessageReceived);
    }

    private void OnLaunchEditBook(LaunchEditBookMessage msg)
    {
        var editBook = new EditBookWindow();
        editBook.Show();
    }

    private void OnSaveBookDialogMessageReceived(SavedBookDialogMessage msg)
    {
        MessageBox.Show(msg.Content, msg.Caption, msg.Button);
    }
//...

It is a business application, if you switch from that Page to another and then come back there, the page gets instanciated again and keeps registering for those messages causing those to fire multiple times...

How comes it subscribe for those messages in codebehind instead of in ViewModels? has this something to do with UI thread? **Is this a correct implementation?

How would you unregister those messages if user navigates to another page?

EDIT: REFACTORED CODE

XAML

<sdk:Page Loaded="Page_Loaded" Unloaded="Page_Unloaded">

CODE BEHIND

private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        RegisterMessages();
    }

    private void Page_Unloaded(object sender, RoutedEventArgs e)
    {
        Messenger.Default.Unregister(this);
    }
like image 307
JackNova Avatar asked Oct 09 '22 22:10

JackNova


1 Answers

Yes, this looks like a bug in his example. He probably isn't expected the page to get instantiated more than once in an application. There is a method for Messenger.Default.Unregister you could hook into on an Unloaded event to fix this issue (you might consider moving the register to Loaded as well.

I understand why he put the events in the View, however. He is opening a new window and calling MessageBox.Show(), since these are very tightly coupled to the View, he kept them in the View. I still don't like the solution personally...

Other MVVM frameworks fight this problem a little better, such as Caliburn. It has lots of helper classes to do View-like things from your ViewModel. Caliburn can 100% eliminate anything in code-behind, but it has a pretty big learning curve.

like image 175
jonathanpeppers Avatar answered Oct 13 '22 11:10

jonathanpeppers