Global Variables vs. MesageBus

Mar 22, 2012 at 8:07 PM

Hi Tony,

I have begun using Simple MVVM toolkit to build a small sample/reference application and really like the featureset and ease-of-use!  Great samples ... really helped me to get up and running very quickly!

I would like to get your guidance on how to do "global" variables in a navigation-based SL application that uses Simple MVVM.   I have been using both NotificationEventArgs and MesageBus in my app, and these work great to enable loosely-coupled communication between the ViewModel/View and between ViewModels, respectively.

However, it seems like there are certain scenarios where using plain ol' global variables, i.e., using static fields/properties in SL's App class, seems to work better (and is a lot more more straightforward) than using MessageBus.   But is it the "right" thing to do?

Here is my simple scenario:   I have a navigation-based SL app, very similar to your nav-based samples.  In the Home page's Loaded event , I call a web service to load the User profile, which includes the UserID.   In the "Loaded" event of subsequent pages that I navigate to, I want to load data using methods like GetCustomers(UserID) or GetRecentSales(UserID).  I need to pass the UserID to those pages (but I don't want to put the UserID in the URL).

I can do this quite easily using "global" variables.  First, I create a static field in SL's "App" class, like this:

public partial class App : Application
    {
        private static int userID = 0;
        ...
Then in the Home page, I save the UserID into that static field, like this:
public class HomeViewModel : ViewModelBase
    {
           ...
           private void UserLoaded(User entity, Exception error)
        {
            if (error == null)
            {
                App.userID = entity.UserID;
            ...
When navigating to any of the other pages, I can directly read that static variable in the page "Loaded" event, like this:

public class CustomersViewModel : ViewModelBase<CustomersViewModel>
    {
     public void LoadCustomerList()
        {
            serviceAgent.GetCustomerList
                (
                    App.userID, (entity, error) =>
                         CustomerLoaded(entity, error)
                );
         ...

This approach works nicely with my unit tests.  I can assign a value to the static App-wide variable during test setup and the Mock Service agent works just fine.  So no problems there.

I tried to accomplish the same thing using the MessageBus approach, but I ran into some challenges.   First, in HomeViewModel I send a message containing the UserID to the MessageBus, like this:

public class HomeViewModel : ViewModelBase    
{           
     ...
     private void UserLoaded(User entity, Exception error)
     {
          if (error == null)
          {
              SendMessage(MessageTokens.UserID,
                  new NotificationEventArgs(entity.UserID.ToString())); 
              ...

Then in the constructor of CustomersViewModel, I "subscribe" to the message, like this:

this.RegisterToReceiveMessages(MessageTokens.UserID, OnUserIdMessageReceived);

I thought this would work.  The trouble is, the callback method (OnUserIdMessageReceived) is never called!   I realize now that this is because the CustomersViewModel does not even exist yet when the message is sent from HomeViewModel.   (CustomersViewModel is not created/initialized until the HyperlinkButton is clicked back in MainPage.xaml.

I also tried a similar technique to send a message containing the UserID from MainPageViewModel to CustomersViewModel.  But I have the same problem:  CustomersViewModel isn't created/initialied until I navigate to it, and once it's been created it's too late to send the message from MainPageViewModel.

So is there anything "wrong" with the approach of using "global" variables, as I've shown above?   It is certainly simple, but feels inelegant to me.  Does it violate any "core principles" of the MVVM pattern, like loose coupling, etc?   Is there a better way to do this, using MessageBus or other techniques with the Mvvm Toolkit?

Thanks for your help,

Steve

Coordinator
Mar 23, 2012 at 4:17 PM

The problem with navigation in Silverlight is that there is no convenient way to pass a message to a view and view-model that are going to be instantiated when you navigate to the view.  To address this I advocate the use of a NavigationHelper class.  See this blog post for into on that: http://simplemvvmtoolkit.codeplex.com/discussions/267069.

Cheers,

Tony