1

I am new to WPF/Prism and I am trying to do the following: I need to load a Login View ( windows or user control) before launching my Main Window. And after successful login, remove the Login view and go to the Main Mindow.

I have looked at several answers within here but all are referencing older versions of PRISM with the boostrapper class.

I have a WPF (Prism 7) application which contains the main project and an Authorization Module.

From my Main project App.xaml.cs

 protected override Window CreateShell()
 {
   return Container.Resolve<MainWindow>();
 }

 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
 {
    moduleCatalog.AddModule<AuthorizationModule>();
 }

In the Authorization module i have my LoginView / LoginViewModel. The authortization Module registers a LoginService which will be injected to the LoginViewModel

public void RegisterTypes(IContainerRegistry containerRegistry)
{
   containerRegistry.Register(typeof(ILoginService), typeof(LoginService));
}

The LoginViewModel will take care of authenticating the user using this LoginService.

Part of the answers I've seen show something like this:

protected override void InitializeShell()
{
    Window login = new LoginView();
    var loginVM = new LoginViewModel(new LoginAuth());
    loginVM.LoginCompleted += (sender, args) =>
    {
        login.Close();
        Application.Current.MainWindow.Show();
    };
    login.DataContext = loginVM;
    // problem below:
    login.ShowDialog();
}

However, this seems a bit off having to instantiate the LoginView manually instead of just having a container do it for you.

Also, the InitiallizeShell on PRISM 7 is expecting the current shell being created. Im not sure if I should use this value being passed to Activate the Main Window.

 protected override void InitializeShell(Window shell)

I also read from Brian Lagunas himself on Github to maybe use the EventAggregator (which I've tried). i've had the Authorization Module register the EventAggregator and from the LoginViewModel, on successful login, publish a SuccessfulLoginEvent but I can figure out how to subscribe to that event from Main app

So basically the expected result is that when the application launches, if the user is not logged in, show the LoginView, after the user authenticates him self, take him to the MainWindow with all needed modules already loaded.

Any help would be greatly appreciated.

ArHe
  • 11
  • 3

2 Answers2

2

I gave this a try and came up with the following:

App:

public partial class App : PrismApplication
{ 
    protected override Window CreateShell()
    {
        return Container.Resolve<Login>();
    }
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.Register(typeof(object), typeof(Login), "Login");
        containerRegistry.RegisterInstance(typeof(LoginViewModel), new LoginViewModel(Container.GetContainer(), Container.Resolve<RegionManager>()));
        containerRegistry.Register(typeof(object), typeof(MainWindow), "MainWindow");
        containerRegistry.RegisterInstance(typeof(MainWindowViewModel), new MainWindowViewModel(Container.GetContainer(), Container.Resolve<RegionManager>()));
    }
}

XAML:

<Window x:Class="LoginTest.Views.Login"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:LoginTest.Views"
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d"
    Title="Login" Height="250" Width="400">
<Grid>
    <Button Content="Login" HorizontalAlignment="Left" Height="61" Margin="100,100,0,0" VerticalAlignment="Top" Width="164" Command="{Binding LoginCommand}"/>

</Grid>

Codebehind:

public partial class Login : Window
{
    public Login()
    {
        InitializeComponent();
        ((LoginViewModel)DataContext).NewWindow += StartMainApp;
        ((LoginViewModel)DataContext).CloseWindow += CloseWindow;
    }

    private void StartMainApp(Object win)
    {
        Application.Current.MainWindow = (Window)win;
        Application.Current.MainWindow.Show();
    }

    private void CloseWindow()
    {
        this.Close();
    }
}

ViewModel:

class LoginViewModel : BindableBase
{
    private readonly IUnityContainer _container;
    private readonly IRegionManager _regionManager;
    private PrismApplication _application;


    private string _title = "Prism Application";
    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
    }

    public DelegateCommand LoginCommand { get; set; }
    public delegate void NewWindowDelegate(Object win);
    public delegate void CloseWindowDelegate();
    public CloseWindowDelegate CloseWindow{ get; set; }
    public NewWindowDelegate NewWindow { get; set; }

    public LoginViewModel(IUnityContainer container, IRegionManager regionManager)
    {
        _regionManager = regionManager;
        _container = container;

        LoginCommand = new DelegateCommand(OnLogin);
    }

    private void OnLogin()
    {
        Trace.WriteLine("Logging in");
        // do your login stuff

        // If Login OK continue here
        NewWindow.Invoke(_container.Resolve<MainWindow>());
        CloseWindow.Invoke();

    }
}

I hope my example is of any use!

user947737
  • 326
  • 2
  • 11
0

I want to express my gratitude to user947737 for good advice. I tried it myself and it worked out for me. Additionally, of course, I added the MainWindowsModelView constructor.

public class MainWindowViewModel : BindableBase
    {
        private readonly IUnityContainer _container;
        private readonly IRegionManager _regionManager;
        private PrismApplication _application;
        //private string _title = "Prism Application";
        //public string Title
        //{
        //    get { return _title; }
        //    set { SetProperty(ref _title, value); }
        //}

        public MainWindowViewModel(IUnityContainer container, IRegionManager regionManager)
        {
            _container = container;
            _regionManager = regionManager;
        }
    }