Login / Logout View Switching

Topics: Prism v2 - WPF 3.5, Prism v2 - WPF 4
May 18, 2010 at 8:57 AM
Edited May 18, 2010 at 9:00 AM

Hi

I have been franticly digging through PRISM guides for the past 2 months in anticipation of a new project we have to get into. So far I am very impressed and confused at the same time. It will be my first really big system rewrite from scratch, so naturally I want to do everything top notch and proper. I have roughly 2million questions about PRISM but I won't burden you with all of them at once.

My question for now is this:

I have created a shell with 5 regions. I have created a login module which gets loaded .WhenAvailable. On startup the shell does what it needs to and the login module is displayed as I desire. After successful login, I get into my (still empty for now) shell. Then I click the Logout button I have added into one of the regions. This basically runs through all the regions and removes all the views and sets up the shell to be as it is when it first started up ie. Login Layout.

Now my problem comes in here where I want to show my login screen again. The login module has already been loaded and registered with the region in the bootstrapper and the module's initialize() method. On startup the Bootstrapper kicks off the login module and loads it up automatically. But once I remove the login view from my shell, how do I get it to come back. The login button is in another module called ActiveUserModule (but still in the same project) as the login module. I thought I should do something like this, but the new LoginViewModuleViewModel(...) part seems to tell me that I should not. Here is my LogoutCommand's Execute function.

        public void ExecuteLogoutCommand(object parameter)
        {
            foreach (IRegion region in regionManager.Regions)
            {
                if (region.Name == RegionNames.ContentRegion)
                {
                    
                }
                // remove the views from the regions
                while (region.Views.FirstOrDefault() != null)
                {
                    var view = region.Views.FirstOrDefault();

                    if (view != null)
                    {
                        region.Remove(view);
                    }
                }
            }

            IRegion contentRegion = regionManager.Regions[RegionNames.ContentRegion];
            object existingView = contentRegion.Views.FirstOrDefault();

            if (existingView == null)
            {
                LoginView view = new LoginView([ ILoginModuleViewModel implementation should go here]);
                contentRegion.Add(view, "UserListView");
                contentRegion.Activate(view);
            }
            else
            {
                contentRegion.Activate(existingView);
            }

            //eventAggregator.GetEvent<SetLoginLayout>().Publish(true);
        }

 

Here is my View's constructor

        public LoginView(ILoginModuleViewModel viewModel)
        {
            InitializeComponent();

            this.DataContext = viewModel;
        }

 

Here is the ViewModuleViewModel implementation

        public LoginModuleViewModel(ILoginService loginService, IRegionManager regionManager, IEventAggregator eventAggregator)
        {
            this.loginService = loginService;
            this.regionManager = regionManager;
            this.eventAggregator = eventAggregator;
        }

 

When I say

LoginView view = new LoginView(new LoginModuleViewModel(blahblah);
I need to pass all of the paramaters which usually get dependancy injected.

Am I missing something? Am I completely wrong? How do I load back my Login module after logout? Any ideas would be greatly appreciated, and thanks for an awesome framework :)

Regards

Developer
May 19, 2010 at 1:56 PM
Edited May 19, 2010 at 1:58 PM

Hi,

I’m glad you are starting to use Prism.

The component that makes dependency injection possible in Prism is the dependency injection container, which is by default the Unity Application Block container. When you write:

LoginView view = new LoginView(new LoginModuleViewModel(blahblah);

you are explicitly creating an instance of that view through the new statement, so you need to pass the corresponding arguments to the view’s and ViewModel’s constructors. In order to have the container instantiate the view, and fulfill all its dependencies (in this case, the ViewModel, which has dependencies itself that the container will also resolve and inject), you have to write something like this:

LoginView view = this.Container.Resolve<LoginView>();

assuming this.Container is a reference to the Unity Container. That way, you decouple your view from the specific implementation of the ViewModel.

On a different matter, having a centralized control of when views are added and removed isn’t probably the best approach for achieving this functionality. I would recommend keeping each module responsible for adding and removing views. To that purpose, you could publish a “LoginEvent” when the user is authenticated, and a “LogoutEvent” when the logout button is clicked. Then you could have a component in your modules listening to those events, that would add and remove views accordingly when the events are published.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Dec 9, 2010 at 3:14 PM
Edited Dec 9, 2010 at 3:37 PM

Hi Guido,

For your comments:

"On a different matter, having a centralized control of when views are added and removed isn’t probably the best approach for achieving this functionality. I would recommend keeping each module responsible for adding and removing views. To that purpose, you could publish a “LoginEvent” when the user is authenticated, and a “LogoutEvent” when the logout button is clicked. Then you could have a component in your modules listening to those events, that would add and remove views accordingly when the events are published."

Do you have any samples/examples to illustrate this? 

 

Thanks!

Developer
Dec 9, 2010 at 7:16 PM
Edited Dec 21, 2010 at 3:22 PM

Hi,

You could have, for example, a button for logging in, and another one for logging out, binded to some DelegateCommands.

The commands those buttons would execute could look like this:

private void Login()
{
   eventAggregator.GetEvent<LoginEvent>().Publish(null);
}

 

private void Logout( )
{
   eventAggregator.GetEvent<LogoutEvent>().Publish(null);
}

 

Assuming eventAggregator is a reference to the Event Aggregator in your application, and that you have a LoginEvent and LogoutEvent defined in an infrastructure project.

Then, you could have each one of your modules subscribe to those events, and add and remove their views accordingly. For example a controller in a sample module which adds its views when logging in and removes them when logging out could have something like this:

public class SampleModuleController
{

   public SampleModuleController(IEventAggregator eventAggregator, IRegionManager regionManager)

   {

      this.eventAggregator.GetEvent<LoginEvent>().Subscribe(AddViews);

      this.eventAggregator.GetEvent<LogOutEvent().Subscribe(RemoveViews);

      this.regionManager = regionManager;

   }


   public void AddViews(object parameter)

   {

     
this.regionManager.Regions["SomeRegion"].Add(container.Resolve<SomeView>(),"SomeView");


   }


   public void RemoveViews(object parameter)

   {
      var View = this.regionManager.Regions["SomeRegion"].GetView("SomeView")

      this.regionManager.Regions["SomeRegion"].Remove(View);
 }

}

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Dec 13, 2010 at 6:49 PM

Thanks Guido for the example. It makes sense. I am basically trying to have Login/Logout functionality in my app. However, wanted to do this in modular way rather than having to use modal Login windows popup on app initialization (some other examples that I saw were illustrating this approach).