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