Where put bootstrapper? - wpf

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.

Related

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

How to customize startup of WPF application?

When a new WPF Application project is created, MainWindow.xaml, App.xaml and their corresponding code behind classes are automatically generated. In the App.xaml there is an attribute that defines which window is going to be run initially and by the default it's StartupUri="MainWindow.xaml"
I have created a new Dispatcher class in the same project. At startup, I want the instance of that class Dispatcher to be constructed and then one of its method to run. That method would actually create and show the MainWindow window. So how do I modify the App.xaml or App.xaml.cs in order to make it happen? Or, if it cannot be done by App, how should I implement it? Thanks.
You can remove the StartupUri attribute from the App.xaml.
Then, by creating an override for OnStartup() in the App.xaml.cs, you can create your new instance of your Dispatcher class.
Here's what my quick app.xaml.cs implementation looks like:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new MyClassIWantToInstantiate();
}
}
}
Update
I recently discovered this workaround for a bug if you use this method to customize app startup and suddenly none of the Application-level resources can be found.
Try to use the Startup event (class Application) - MSDN.
You can show MainWindow in this event handler - after you create a Dispatcher instance.
1.In App.xaml, To replace the StartupUri with a subscription to the Startup event.
Use the event in App.xaml.cs .
For instance,
Startup="Application_Startup" in .xaml.
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
// Create the startup window
MainWindow wnd = new MainWindow();
// Do stuff here, e.g. to the window
wnd.Title = "Something else";
// Show the window
wnd.Show();
}
}

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.

Is there an equivalent to PreApplicationStartMethod for WPF Applications?

For those that don't know, you can mark an assembly with the PreApplicationStartMethod, which will define a method that gets called before Application_Start in an ASP.NET site (if you're using .NET 4). I love using this in an Onion Architecture for defining a method that does all the setup for Dependency Injection.
My question is... is there any equivalent way of doing the same thing for a thick client application, such as one written in WPF?
For a WPF application it doesn't make much sense to mark an assembly with an attribute, since you are in control of which code will execute anyway.
A good place to do this initialization would be the OnStartup method.
In your App.xaml remove the StartupUri="MainWindow.xaml"
Then in your App.xaml.cs I do this:
public partial class App : Application
{
private IWindsorContainer _container;
private IView _view;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_container = new WindsorContainer();
/// Register your interfaces with your concrete implementations.
// we'll do View first in this example (some do view first others do ViewModel first)
_view = _container.Resolve<IView>();
_view.Show();
}
}

Caliburn Launch without App.xaml, but with bootstrapper

I have a WinForms project from which I want to open a WPF window from a WPF user control project.
But when I create an instance of the WPF window and call Show(), the bootstrapper isn't loaded. In an Windows Application, it's located in the App.xaml, but an user control project doesn't have this.
What can I do?
Thanks!
The only thing accomplished by having the bootstrapper in App.xaml's resources is instantiation of the bootstrapper and keeping a reference so it isn't garbage-collected. You could try making it instantiate like this:
public class SomeClass {
static Bootstrapper _bs = new Bootstrapper();
...
}
That will make sure it's initialized as part of static construction, which happens sometime before you can create an instance of SomeClass. You may have to experiment to see whether that should happen in your UserControl or in your Window.
I have a console application which presents a WPF gui that I made with Caliburn.Micro. I present the GUI like this:
_App = new App();
_App.Run();
Where App.xaml contains the bootstrapper and the main thread is STA like this:
[STAThread]
static int Main(string[] args)
{ ... }
I know your situation is different but maybe this will give you an idea.
Console application test:
Add MaterialDesignColors pakage
[System.STAThreadAttribute()]
static void Main(string[] args)
{
var _app = new App();
_app.InitializeComponent();
_app.Run();
_app.Shutdown();
}

Resources