简体   繁体   中英

Display two WPF windows simultaneously using Caliburn.Micro

I have a need to display two WPF controls at one time, in separate windows, at startup. The parent windows are of the same type and the user controls (and parent window) are defined in a separate assembly, which is only referenced by the host project. I am using Caliburn.Micro as an MVVM framework and Ninject for IoC. How can this be done?

All viewmodels are derived from PropertyChangedBase. I have already setup AppBootstrapper to define the Caliburn.Micro standard bindings, such as WindowManager:

  _kernel.Bind<IControl1>().To<Control1ViewModel>().InSingletonScope();
  _kernel.Bind<IControl2>().To<Control2ViewModel>().InSingletonScope();
  _kernel.Bind<IParentWindow>().To<ParentWindowViewModel>();

and created an override for OnStartup that created Control1:

DisplayRootViewFor<IWindow1>();

The user control is supplied to the parent window in a ContentControl as a window context, like this:

<ContentControl x:Name="WindowView"
     HorizontalAlignment="Stretch"
     VerticalAlignment="Stretch"
     cal:View.Context="{Binding ViewContext}"
     cal:View.Model="{Binding WindowContent}" />

Finally, I also provided an override to SelectAssemblies, so that Caliburn.Micro could find the views and viewmodels in the dll:

protected override IEnumerable<Assembly> SelectAssemblies()
{
    var assemblies = base.SelectAssemblies().ToList();
    assemblies.Add(typeof(IControl1).GetTypeInfo().Assembly);
    return assemblies;
}

I have tried several possible solutions, none of which worked:

  1. Open the Window2 from the constructor of the Window1 viewmodel (using WindowManager.ShowWindow). However, this only opened Window2, and never opened Window1. Probably not a good idea anyway..

  2. Create one window in AppBootstrapper.OnStartup, and another window using the App.xaml StartupUri, however this did not allow me to include the user control inside a generic parent window. All I could do was open an empty parent window.

  3. Call DisplayRootViewFor() on the interface for each window to open on startup. The problem with this is there is no way to set the window content, so you don't get the custom parent window, just the default window provided by Caliburn.Micro.

Here is how I did it:

In AppBootstrapper.cs, instead of calling DisplayRootViewFor, create an instance of the parent window first:

var parentWindow = _kernel.Get<IParentWindow>();

Provide the user control to the parent window context:

parentWindow = _kernel.Get<IControl1>();

Open the window with WindowManager.ShowWindow:

_kernel.Get<IWindowManager>().ShowWindow(parentWindow, null, windowSettings);

Simply repeat the process for the second window:

var window2 = _kernel.Get<IParentWindow>();
window2.WindowContent = _kernel.Get<IControl2>() ;
_kernel.Get<IWindowManager>().ShowWindow(window2, null, windowSettings);

This will create two windows, containing user controls defined in an external assembly, using Caliburn.Micro in WPF.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM