Login dialog from Bootstrappers OnStartup method

Sep 18, 2011 at 5:08 PM
Edited Sep 18, 2011 at 5:12 PM

Hi there

I need to implement a login dialog from the overridden OnStartup method of my ScreenBootstrapper.

In the OnStartup method, I created a new WindowManager instance and called its  ShowDialog method.

But the dialog doesn't show up.

 

WindowManager windowManager = new WindowManager();
windowManager.ShowDialog(new LoginViewModel());

 

How would you implement a login dialog in the bootstrapper? As described in the documentation of the bootstrapper, this should be the right point to do it.

Coordinator
Sep 19, 2011 at 3:16 AM

Here's the full Bootstrapper from an App I worked on recently that does this:

public class AppBootstrapper : Bootstrapper {
    SimpleContainer container;

    protected override void Configure() {
        container = new ContainerConfiguration().CreateContainer();
        new ConventionConfiguration().Configure();
    }

    protected override void OnStartup(object sender, StartupEventArgs e) {
        if (StartLogin()) {
            StartMainApplication();
        }

        Application.Shutdown();
    }

    void StartMainApplication() {
        var shell = IoC.Get<IShell>();
        var windowManager = IoC.Get<IWindowManager>();
        windowManager.ShowDialog(shell);
    }

    bool StartLogin() {
        var login = IoC.Get<LoginViewModel>();
        var windowManager = IoC.Get<IWindowManager>();
        windowManager.ShowDialog(login);
        return login.IsLoginValid;
    }

    protected override object GetInstance(Type service, string key) {
        return container.GetInstance(service, key);
    }

    protected override IEnumerable<object> GetAllInstances(Type service) {
        return container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance) {
        container.BuildUp(instance);
    }
}

Sep 19, 2011 at 6:37 AM

Great, many thanks.

Sep 19, 2011 at 9:49 AM

I had gone about this a different way.  I have two view contexts for my shell vm, [UnAuthorised, Authorised] and upon successful authentication/authorisation, switch contexts.  A little bit of view controller code is needed to size/position the login context but it suits our needs perfectly.

Sep 21, 2011 at 7:57 AM

Unfortunately, I am not able to let the dialog showing up from the bootstrapper, whatever I do. Are there any special configurations needed? Is it possible that the view has to be in a special form, since there is no shell acting as a parent? Maybe this special scenario is the problem?

Sep 23, 2011 at 1:16 PM

No one an idea?

Sep 23, 2011 at 9:12 PM

Did you get any exception? Could you please post a snippet of your bootstrapper?

Sep 25, 2011 at 11:45 AM

Unfortunately there no exception, no error, nothing. The dialog just doesn't show up.

Here is my bootstrapper:

 

 public class ScreensBootstrapper : Bootstrapper
   {
      CompositionContainer container;

      protected override void Configure()
      {
         ConfigureContainer();
         ConfigureConventions();
      }

      private void ConfigureContainer()
      {
         container = CompositionHost.Initialize(new AggregateCatalog(AssemblySource.Instance
                                                                         .Select(x => new AssemblyCatalog(x))
                                                                         .OfType<ComposablePartCatalog>()));

         var batch = new CompositionBatch();

         batch.AddExportedValue<IWindowManager>(new WindowManager());
         batch.AddExportedValue<IEventAggregator>(new EventAggregator());

         batch.AddExportedValue(container);

         container.Compose(batch);

         // Setting the Language
         Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
      }

      private void ConfigureConventions()
      {
         ConventionManager.AddElementConvention<BusyIndicator>(BusyIndicator.IsBusyProperty, "IsBusy", "IsBusyChanged");
      }

      protected override void OnStartup(object sender, StartupEventArgs e)
      {
         if (StartLogin())
         {
            StartMainApplication();
         }

         Application.Shutdown();
      }

      void StartMainApplication()
      {
         var shell = IoC.Get<IShell>();
         var windowManager = IoC.Get<IWindowManager>();
         windowManager.ShowDialog(shell);
      }

      bool StartLogin()
      {
         var login = IoC.Get<LoginViewModel>();
         var windowManager = IoC.Get<IWindowManager>();
         windowManager.ShowDialog(login);
         return login.IsLoginValid;
      }

      protected override object GetInstance(Type service, string key)
      {
         return container.GetInstance(service, key);
      }

      protected override IEnumerable<object> GetAllInstances(Type service)
      {
         return container.GetAllInstances(service);
      }

      protected override void BuildUp(object instance)
      {
         container.BuildUp(instance);
      }
   }
Sep 26, 2011 at 10:49 AM

You must register LoginViewModel in the container when using the IoC or change it so you create the LoginViewModel yourself.

Sep 26, 2011 at 8:56 PM

I guess the LoginViewModel is registered through MEF attributes above the class.

I really can't figure out the problem from your description of the app behavior. Did you investigate what's happening inside OnStartup with the Debugger?
If you have the chance of building a small repro, please send it to marco dot amendola at gmail com; it would greatly help me to diagnose the problem quickly - hopefully :-)

Sep 27, 2011 at 5:20 PM
Edited Sep 27, 2011 at 5:21 PM

I just prepared a repro with the HelloScreens sample and of course it works. :-)

So I made a mistake somewhere in my original solution. I'm going to find it out soon.

Thank you anyway.

Sep 28, 2011 at 1:49 AM

That's unfortunate. It's hard for me to figure out the issue unless I notice something strange in the code (which is not the case here).
I believe, however, it could be just a simple overshigh. Again, try to run OnStartup under debugger, and check whether VMs are created correctly.
You can also turn logging on (see http://caliburnmicro.codeplex.com/discussions/222622) to get some additional information about what's going on.

Oct 4, 2011 at 11:15 AM
Edited Oct 4, 2011 at 12:08 PM

For quickness I took a similar approach but when I call windowManager.ShowDialog(shell) in my StartApplication it return instantly without showing a dialog.  Is there any potential reason for this?

Edit: Application.ShutDownMode needs to be set to explicit shutdown.

Oct 9, 2011 at 3:38 PM

I  got the problem. The problem was, that I forgot the "Export" attribute for the login dialog.



[Export(typeof(LoginViewModel))]

 

Surprisingly the export attribute is not needed in case of showing the login dialog in the shell.

So, everything was working correctly. I found nothing strange while debugging. The only problem was the export attribute. Was my fault, but I wonder if this two approaches (bootstrapper, shell) are working differently. Thats why I didn't get the idea, that the export attribute was the problem.

Oct 9, 2011 at 3:45 PM
lmao

I've been watching this thread for a while.

I'm from the WAF club - I just joined this Caliburn club last week.

Yeppers - I had the same problem with my Login STOMPING on the MEF - Ended up doing it code-behind. Meh - works great.

But I can say I diligently looked into this issue - drove me nutz for a while :)

On Sun, Oct 9, 2011 at 9:38 AM, Tongo <notifications@codeplex.com> wrote:

From: Tongo

I got the problem. The problem was, that I forgot the "Export" attribute for the login dialog.



[Export(typeof(LoginViewModel))]

Surprisingly the export attribute is not needed in case of showing the login dialog in the shell.

So, everything was working correctly. I found nothing strange while debugging. The only problem was the export attribute. Was my fault, but I wonder if this two approaches (bootstrapper, shell) are working differently. Thats why I didn't get the idea, that the export attribute was the problem.

Read the full discussion online.

To add a post to this discussion, reply to this email (caliburnmicro@discussions.codeplex.com)

To start a new discussion for this project, email caliburnmicro@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Oct 9, 2011 at 9:06 PM

I'm glad you got it fixed. It definitely was a problem with MEF configuration: if you don't register LoginVM, Ioc.Get<> can't locate it, hence CM fails to display the corresponding view.
It's not clear to me why you didn't get any exception; I guess it could have been swallowed by a general UnhandledException event handler, perhaps.
Regarding the fact that you seemed to be able to successfully show LoginVM in a Conductor, I guess that you were creating LoginVM instance with "new LoginVM()" instead of "IoC.Get<LoginVM>"; am I correct?

Oct 10, 2011 at 11:29 AM
Edited Oct 10, 2011 at 1:21 PM

That's correct. In the Shell (conductor) I created a new instance of LoginViewModel by myself, so I can understand now why it worked in the shell.

In the bootstrapper on the other hand, I tried either way, without success.

So, to make it complete, I am going to check every case again, to make sure it works for all approaches. I'll let you know the result.

Dec 25, 2011 at 9:14 PM
Edited Dec 27, 2011 at 4:01 PM

Marco,

when i'am using your approach, the login window remains visible - in fact, it behaves like parent window for my ShellViewModel (it's visible, but blocked, "under" the ShellViewModel).
I'am using Ninject as my IoC. I thought that injecting WindowManager in SingletonScope is a problem, but in TransientScope everything is the same...

EDIT: Nevermind, that was my stupid mistake...

Apr 9, 2013 at 3:37 AM
Digging up this old thread because I'm trying to get a similar behavior on Windows Phone 8. The challenge is that the ShowDialog call is throwing a NullReferenceException in the DialogHost ctor:
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
    var windowManager = IoC.Get<IWindowManager>();
    if (Persistence.Settings.IsFirstLogin)
    {
        var gettingStarted = IoC.Get<ViewModels.GettingStarted.IndexViewModel>();
        // Next line throws System.NullReferenceException from Caliburn.Micro.WindowManager.DialogHost..ctor(INavigationService navigationSvc)
        windowManager.ShowDialog(gettingStarted);
    }

    base.OnStartup(sender, e);
}
Any thoughts on why the NavigationService isn't populating the current context and how to make this sort of start-up dialog work on Windows Phone 8?
Apr 11, 2013 at 5:49 PM
INavigationService won't be active in that fashion yet... it would also need to be IoC.Get<> called to get a working instance. Since this code appears to be from the BootStrapper... At least that would be my first guess and the second would be the IndexViewModel isn't in the registered with the container yet.
Jun 10, 2013 at 6:00 PM
Edited Jun 10, 2013 at 6:03 PM
colinbo, I was running into the same issue using 1.5.1 for WP8.

The following worked for me:

var navigationService = IoC.Get<INavigationService>();
if(SomethingIsTrue())
{
navigationService.UriFor<SomethingIsTruePageViewModel>().Navigate();
}
else
{
navigationService.UriFor<SomethingIsNOTTruePageViewModel>().Navigate();
}

But might have issues?

mvermef, you stated "INavigationService won't be active in that fashion yet". But, I used INavigationService. Is the above code subject to an issue I'm unaware of?
Jun 11, 2013 at 4:11 AM
no your call to the service is correct for all intents and purposes... and should work accordingly
Nov 15, 2013 at 3:11 PM
I know this is an old post...but since absolutely none if the answers worked for me I'm going to assume the original poster made the same mistake I just made(and I've done it before).
When he showed the login window in the bootstrapper HE CLOSED that window on "login" or whatever.
Well...if you do that the application will shutdown(default setting...application shutdowns when the first window is closed...don't remember where you can change that).
Anyway...instead of CLOSING that login window HIDE it instead and your App will now start.