I am trying to build a WPF Prism bases app using MVVM design pattern.
When my app first starts, I want to require the user to login. Once logged in, I want to show the default landing page with the user name and buttons.
My thought, when a user login, I would publish an event called UserLoggedIn
then on the home view-model, I would listen for that event. When the event is triggered, I would show the landing/home view.
So I created the event like so
public class UserLoggedIn : PubSubEvent<User>
{
}
Then in the LoginViewModel
I handle the login and publish the event like so
private void HandleLogin(LoginView loginView)
{
try
{
User user = AuthenticationService.Authenticate(Username, loginView.GetPassport());
IUserPassport passport = PassportManager.Get(user.Username);
if (passport == null)
{
// Create a new session
passport = new UserPassport(new CustomIdentity(user), RegionManager);
}
// Assign the current session
PassportManager.SetCurrent(passport);
// Trigger the event
EventAggregator.GetEvent<UserLoggedIn>().Publish(passport);
// Deactivate the login view
RegionManager.GetMainRegion().Deactivate(loginView);
}
catch (Exception ex)
{
//Do something with the error
}
}
Finally in my HomeViewModel
aka my landing view, I have the following code to listen for the UserLoggedIn
event.
public class HomeViewModel : BindableBase
{
protected IUnityContainer Container { get; set; }
protected ICoreRegionManager RegionManager { get; set; }
private IEventAggregator EventAggregator { get; set; }
public HomeViewModel(IUnityContainer container, ICoreRegionManager regionManager, IEventAggregator eventAggregator)
{
Container = container;
RegionManager = regionManager;
EventAggregator = eventAggregator;
eventAggregator.GetEvent<UserLoggedIn>().Subscribe(ShowTheLangingPage);
}
private void ShowTheLangingPage(User user)
{
var homeView = Container.Resolve<HomeView>();
RegionManager.AddToMainRegion(homeView);
FullName = user.FirstName;
}
// I am using PropertyChange.Fody package, so this propery will automaticly raise the PropertyChange event.
public string FullName { get; set; }
}
Problem is the ShowTheLangingPage
method never get triggered in my HomeViewModel
as expected.
I made sure the the View HomeView
and HomeViewModel
are wired up correctly, by directly loading the HomeView
on module initialization for testing.
Additionally, if add Container.Resolve<HomeView>();
just before I publish the event, the ShowTheLangingPage
I called. Its like I have to resolve the HomeView
manually for it to listen for the event.
How can I correctly listen for the UserLoggedIn
event so i can show the corresponding view.
So I can learn the better/recommended way, is it better to show the landing view from the LoginViewModel
instead of using event/listener.... and why? Also, if showing the landing view directly from the LoginViewModel
then what is the recommended method to navigate; using Region.Add() method or RegionManager.RequestNavigate
?
is it better to show the landing view from the LoginViewModel instead of using event/listener....
Yes.
and why?
Because that's what services (like the IRegionManager
) are for, doing stuff for your view models and other services. Also, you have noticed, events can only be subscribed to by living objects.
Also, if showing the landing view directly from the LoginViewModel then what is the recommended method to navigate; using Region.Add() method or RegionManager.RequestNavigate?
If anything, a third class should listen for UserLoggedIn
, but that's no gain over using the IRegionManager
directly. In fact, it's even worse, because you have to artifically create this class. Side note: if you wait for the garbage collector after Container.Resolve<HomeView>();
and before logging in, you won't go to the landing page, because there's no subscriber (again).