Custom window in the bootstrapper as default window - wpf

What should be the procedure to set a custom RibbonWindow as the default shell window.
We are getting this window from a module. Which we registered and initialized.
protected override DependencyObject CreateShell()
{
return new xamRibbonWindow() as DependencyObject;
}
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.MainWindow = (xamRibbonWindow)Shell;
App.Current.MainWindow.Show();
}

While, it is a little unusual to get the Shell from a module, you could do it exactly the same way it is normally done. Are you using a dependency injection container? I'm going to assume you are:
protected override System.Windows.DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<Shell>();
}
You could just substitute your XamRibbonWindow class for Shell. This way, you do not need to reference the project directly that includes your shell. If you want the ability to resolve more than one shell depending on the modules that are loaded, I would create an interface IShell which XamRibbonWindow implements and register that type with the container.
Edit:
Regarding your comments, I would have the module load and on intialize resolve the IRegionManager and call .Add on your region. Or have the shell call NavigateTo if you are using the Navigation interface
Are you using View Discovery or View Injection? (You may need to review the Prism book on UI composition) Also, using MEF, Unity?

Related

How to correctly dispose of dependencies created by ContainerControlledLifetimeManager in a Prism-Unity-WPF application

I got an application mostly following this MSDN article.
Here is my bootstrapper class:
internal class Bootstrapper : UnityBootstrapper
{
// Wire up the dependencies using Unity container
protected override void ConfigureContainer()
{
base.ConfigureContainer();
// Register the connection manager
Container.RegisterType<IConnectionManager, ConnectionManager>(new ContainerControlledLifetimeManager());
}
// Return an instance of the main window
protected override DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<Shell>();
}
// For WPF, initialising shell is simply setting the data context and showing the main window
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.DataContext =
ServiceLocator.Current.GetInstance<MainViewModel>();
Application.Current.MainWindow.Show();
}
}
The connection manager in the code is registered with ContainerControlledLifetimeManager which means it will be treated as a singlton.
Now my connection manager is implementing IDisposable and I want to know the conventional way to dispose the container in order for it to dispose all related ContainerControlledLifetimeManager-ed objects.
I started by overriding OnExit of the application, but I found that UnitBootstrapper doesn't have a dispose method. I can write all the code manually to dispose the container on exit, but I am guessing there must be a formal way to do this kind of usual stuff.
This question is based on the old-style (Prism 6) Unity Bootstrapper. This answer is compatible with Prism 7 Unity containers.
An IUnityContainer object may be retrieved from the Prism IContainerProvider using the a Unity extension method, GetContainer(). The IUnityContainer can be disposed from the OnExit override of an Application that inherits from PrismApplication:
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
Container.GetContainer().Dispose(); // must be called to dispose singletons
}

How to inject the User controls onto the main window shell with prism?

I've recently started learning about MVVM and WPF, and have overcome most of my problems apart from this one (I want to use a model first approach). I can't wire up all of my application's parts with PRISM and whilst also using dependency injection (with ninject).
My current understanding of MVVM with DI is as follows:
We inject the model into the view model with constructor injection.
the app has knowledge of which views with which view model via a resource dictionary eg
<DataTemplate DataType="{x:Type viewModels:ViewModel1}">
<views:View1/>
</DataTemplate>
one can assign regions to the main window shell, and swap user controls into/out of these regions.
I tried to knock up a really basic example using ninject and prism - https://github.com/ultimateshovel/wpf-mvvm-example - however I can't get the user controls to be injected into the main windows shell... I don't understand what else I need to do. I have added details of the modules to the ninject module catalog, and registered the views with the corresponding regions via a region view registry.
Specifically, I'm not sure what I need in my Custom Ninject Bootstrapper, currently I have only the following:
public class CustomNinjectBootstrapper : NinjectBootstrapper
{
protected override DependencyObject CreateShell()
{
return Kernel.Get< Views.Shell >();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window) Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
var textModule = typeof( TextModule );
var buttonModule = typeof( ButtonModule );
ModuleCatalog.AddModule(new ModuleInfo(textModule.Name, textModule.AssemblyQualifiedName));
ModuleCatalog.AddModule(new ModuleInfo(buttonModule.Name, buttonModule.AssemblyQualifiedName));
}
}
I assume that I'm going to need to use a RegionManager, but I'm not sure how those work in a context which isn't view injection.
I suspect that I may also need to add things to the Initialize methods of my modules, which currently look like so
public void Initialize()
{
_regionViewRegistry.RegisterViewWithRegion
( "TextRegion", typeof( TextView ) );
}
but again, i'm not sure what

Caliburn.Micro - why uses UserControl instead of Window

My question is exactly like in the title.
I'm starting with Caliburn.Micro for MVVM approach (which also is new for me) and in every tutorial the first step is to remove the default MainWindow.xaml file and create a new UserControl file. Why is that? UserControl does not even accept a Title. Isn't it possible to build application using normal Windows? I already tried that, but with every launch I get error "Cannot find view for ViewModel", although both MainView.xaml and MainViewModel.cs are present. When I created a pair of USerControl and ViewModel for it, everything started to work as expected. So again, why Windows don't work?
It wouldn't really be a problem, but I'm thinking that some additions like Modern UI themes for WPF might not work without a window. I'm not sure of that.
Probably one solution would be to display a defined UserControl View inside of a Window, but it's just a workaround.
You could create your own custom shell window by creating a custom WindowManager:
public class CustomWindowManager : WindowManager
{
protected override Window CreateWindow(object rootModel, bool isDialog, object context, IDictionary<string, object> settings)
{
Window window = new Window();
window.Title = "custom...";
return window;
}
}
...that you register in your bootstrapper:
public class HelloBootstrapper : BootstrapperBase
{
...
protected override void Configure()
{
_container.Singleton<IWindowManager, CustomWindowManager>();
...
}
}

Should I create separate Bootstrapper for each WPF window?

I am new in WPF and Prism. I'd like to know if I should create new bootstrapper for each new window? For Example I have "Window1" where I select element from ListBox and click button "ShowDetails" and in the new window "Window2" I should see the details of my selection. I have windows and modules for them, but I'd like to know how and where I can register the module "Module2" for "Window2"?
Example of my Bootstrapper.
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
var mainWindow = new Window1();
mainWindow.Show();
return mainWindow;
}
protected override IModuleCatalog GetModuleCatalog()
{
var moduleCatalog = new ModuleCatalog();
moduleCatalog.AddModule(typeof(Module1));
return moduleCatalog;
}
}
"App.xaml.cs"
public partial class App : Application
{
public App()
{
var bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}
The Bootstrapper is used usually in the startup class of a WPF Application. Usually this will be the file App.xaml.cs in the standard template, which is the code-behind class of the App.xaml file. You override the method OnStartup and instantiate your Bootstrapper and call its run method. You can delay the startup of the bootstrapper until the override of OnStartup instead of writing this in the constructor of the App.xaml.cs class. You will then use the RegionManager in Prism and define regions in your XAML. If you have multiple independent Windows this is a bit different from the way Prism is intended to be used. There is the concept of a MainWindow or Shell which you define in the CreateShell method of the Bootstrapper class which is available in the Prism source code. Instead, have a main window and define regions and perhaps consider creating a mechanism for displaying additional windows in dialogs. It is possible partition up the MainWindow into multiple regions and inject user controls via the RegionManager. This is done via the activate method of the RegionManager.
Start up by reading the Patterns And Practices Guide and perhaps consider watching the videos of Mike Taulty upon Prism. The first video is here:
Prism & Silverlight: Part 1 - Taking Sketched Code Towards Unity
There are many videos in the video series (10 in total) that will help you get started with PRISM.
An example of how to define a region in XAML is shown next:
<ItemsControl Regions:RegionManager.RegionName="MainRegion" />
A PRISM region can be activated, e.g. through a DelegateCommand or ICommand bound to a button is the following code:
var viewA = new ViewA();
var regionA = (new RegionManager()).Regions["RegionA"];
regionA.Activate(viewA);
You will have to define multiple modules that implement the IModule Interface and add these to your ModuleCatalog as you already have done with ModuleA.

Where put bootstrapper?

I want to create PRISM application with MVVM pattern and I don't know where I should put bootstrapper?
In Model, ViewModel or View?
Bootstrapper creates shell (so in View?) but it also registers container etc so maybe it should be like separate service?
The bootstrapper is part of the executable framework for configuring your application.
I suggest putting the bootstrapper code in the OnStartup event handler of your Application class.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
SplashScreen splash = new SplashScreen("Resources\\mysplash.png");
splash.Show(true);
base.OnStartup(e);
MyBootstrapper b = new MyBootstrapper();
b.Run();
}
}
Technically, it is part of the View layer, imho, but is really there to configure the catalog and perform start-up operations.

Resources