2

I have a Silverlight application architected using an MVVM approach. In my ViewModel it is time to load some data only after the user is LoggedIn, so I need to intercept this event to trigger my LoadData(). With default configuration, and I mean this in the App.xaml.cs:

public App()
    {
        InitializeComponent();

        // Create a WebContext and add it to the ApplicationLifetimeObjects
        // collection.  This will then be available as WebContext.Current.
        WebContext webContext = new WebContext();
        webContext.Authentication = new FormsAuthentication();
        //webContext.Authentication = new WindowsAuthentication();
        this.ApplicationLifetimeObjects.Add(webContext);

If you try to subscribe to LoggedIn Or LoggedOut events in the ViewModel constructor, you get a bit of problems: WebContext doesn't exists yet.

So I thought... I'll create my WebContext first and then I'll InitializeComponents() in my App but that made ExpressionBlend sad...

So, here it is my solution, I like to share it with you because I'm not totally convinced that this would be the right approach:

App.Current.Startup += (sender, eventArgs) => 
        {
            WebContext.Current.Authentication.LoggedIn += WebContext_LoggedIn;
            WebContext.Current.Authentication.LoggedOut += WebContext_LoggedOut;
        };

In my ViewModel ctor I subscribe to App.Current.Startup and my delegate will subscribe my ViewModel to Login events, this way I have not changed my App.xaml.cs and I'm sure to subscribe to Login events when WebContext exists... So:

private void WebContext_LoggedIn(object sender, AuthenticationEventArgs e)
    {
        LoadData();
    }

EDIT

In this case I'm more interested in understanding if I'm right when I say that I shouldn't change the order between InitializeComponent() and the rest and that I need to listen for a particular event to trigger my LoadData().

Just for the sake of completeness, here it is my refactor to get rid of that dependency in my ViewModel:

I created a message:

public class UserLoginStatusChangedMessage : MessageBase
{
    public bool IsLoggedIn { get; set; }
}

sent it here:

private void Application_Startup(object sender, StartupEventArgs e)
    {
        // This will enable you to bind controls in XAML files to WebContext.Current
        // properties
        this.Resources.Add("WebContext", WebContext.Current);

        // This will automatically authenticate a user when using windows authentication
        // or when the user chose "Keep me signed in" on a previous login attempt
        WebContext.Current.Authentication.LoadUser(this.Application_UserLoaded, null);

        // Show some UI to the user while LoadUser is in progress
        this.InitializeRootVisual();

        WebContext.Current.Authentication.LoggedIn += (s, a) => 
        { 
            Messenger.Default.Send(new UserLoginStatusChangedMessage 
            { IsLoggedIn = true }); 
        };

        WebContext.Current.Authentication.LoggedOut += (s, a) => 
        {
            Messenger.Default.Send(new UserLoginStatusChangedMessage 
            { IsLoggedIn = false });
        };
    }

and received it like this in ViewModel ctor:

 Messenger.Default.Register<UserLoginStatusChangedMessage>(this, msg => 
        {
            if (msg.IsLoggedIn)
            {
                LoadData();
            }
        });
JackNova
  • 3,911
  • 5
  • 31
  • 49

1 Answers1

1

I'd suggest using some kind of messenger class that would send a message when the user is logged in. MVVMLight has a nice messenger class that is easy to use. Then you would just send a message when the user's logged in state changes and subscribe to that event in your view model that needs to know if the user is logged in.

You could check the WebContext to see if it is created and if it is created if the user is logged in when your viewmodel is created and then after that just use the messages to determine if/when this changes.

Bryant
  • 8,660
  • 1
  • 33
  • 53
  • Thanks for your answer, yes I normally use a messenger for those things and in this example is certainly better... otherwise I'm breaking the pattern. In this case I'm more interested in understanding if I'm right when I say that I shouldn't change the order between InitializeComponent() and the rest and that I need to listen for a particular event to trigger my LoadData() – JackNova Sep 21 '11 at 16:59
  • Your edited code looks fine to me. You could probably make Blend happier if you only loaded the WebContext when you weren't in design mode. MVVMLight has a way to check for that too. – Bryant Sep 21 '11 at 17:29