Is there an equivalent to PreApplicationStartMethod for WPF Applications? - wpf

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();
}
}

Related

Caliburn.Micro Starting the bootstrapper from code?

Normally I just but the bootstrapper in the resources of the App.xaml, but for an app I'm building I need code execution to begin elsewhere and then start the bootstrapper up once I'm done my initialization code.
How can I start the bootstrapper?
I set the App.xaml to call a function as then did this:
using System.Windows;
namespace WpfApplication9
{
public partial class App : Application
{
private AdminBootstrapper b;
private void App_OnStartup(object sender, StartupEventArgs e)
{
//DO initialization
b = new AdminBootstrapper();
b.Start();
}
}
}
When I run nothing happens, and my view does not appear. I know the view/viewmodel work because if I put the bootstrapper in the resources section of the App.xaml it appears.
What am I doing wrong here?
Use the Initialize() method instead of Start(). I had the same error and searched the internet and found a post that said to use Initialize() instead. I tried it on the sample app in the Caliburn.Micro docs and it worked for me.
This is not the "correct" way to use the bootstrapper, the bootstrapper IS the place were you do the setup you talk of. The whole point is to provide a place were Caliburn.Micro knows you are going to set up. Without seeing your bootstrapper though it is impossible to know what is wrong.
The root ViewModel is not loaded until after Configure is called. This is your extensibility point. If you need to do complex configuration you could call a couple of overrides here and then derive a class which exposes these methods.
In general though you would need to provide more information about what you are doing before I could give you a concrete recipe.
Maybe not the correct way (wanted to remove it from the markup) but still, this code seems to work...
public partial class App : Application
{
MyBootstrapper _bootstrapper;
protected override void OnStartup(StartupEventArgs e)
{
_bootstrapper = new MyBootstrapper();
base.OnStartup(e);
}
}
public class MyBootstrapper : BootstrapperBase
{
public MyBootstrapper()
{
Start();
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
}

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.

Where to place and configure IoC container in a WPF application?

I am working on a middle sized WPF application (MVVM) that should be extensible and maintainable in the future. Thus I decided to use an IoC container (Unity in this case) to keep things flexible.
However I am not sure where to place and configure Unity in a WPF application.
I guess container should be accessible globally so it should probably go to Application class. But should I make it as static property? Should I configure it in Application_Startup() event handler?
Eg:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public static UnityContainer MyUnityContainer;
private void Application_Startup(object sender, StartupEventArgs e)
{
// instantiate and configure Unity
}
}
This way I will be able to access container from any place in the application via static property:
App.MyUnityContainer
I guess this is one way to do it but I am not sure if there are better practices for this issue, specifically for WPF apps.
Have a look at the Composition Root Pattern. What you want to do is to initialize it in your Startup event handler and forget about its existence for the rest of the application.
You are trying to implement the Service Locator Pattern, which according to many is an inferior solution to this problem.
Let me post what I've concluded and hopefully it'll help people out. Correct if there's anything wrong! :P
I guess we'd be looking into something like this:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
UnityContainer myUnityContainer = new UnityContainer();
//make sure your container is configured
myUnityContainer.RegisterType<ISomeDependency, SomeDependencyImplementation>();
myUnityContainer.RegisterType<IMainWindow, MainWindow>();
myUnityContainer.Resolve<IMainWindow>().Show();
}
}
public partial class MainWindow : Window, IMainWindow
{
private ISomeDependency _someDependency;
public MainWindow(ISomeDependency someDependency)
{
_someDependency = someDependency;
}
}
Note there are no globals or singletons, the container survives as long as MainWindow does and all dependencies behind this point of entry further into the composition graph are automagically resolved as long as the container knows about them.
As per new version of Unity container, we have to register it's own instance as well to get it in view models via constructor injection.
App.xaml.cs file:
protected override void OnStartup(StartupEventArgs e)
{
var unityIoC = new UnityContainer();
unityIoC.RegisterTypes(AllClasses.FromAssembliesInBasePath(), WithMappings.FromMatchingInterface, WithName.Default);
unityIoC.RegisterInstance(typeof(IUnityContainer), unityIoC);
}
View Model class
[InjectionConstructor]
public MyViewModel(IUnityContainer container)
{
}
Now unity container would be available for us in view model and can be used to resolve.

Silverlight ViewModelLocator defined in app.xaml needs a reference to the DI container

I have a ViewModelLocator class that I am defining in app.xaml which is used by my views to databind to the correct ViewModel.
DataContext="{Binding HomeViewModel, Source={StaticResource Locator}}"
I am using Prism and Unity and my ViewModelLocator class needs a reference to an application level unity container.
I wanted inject the IUnityContainer into the ctor of the ViewModelLocator but the ViewModelLocator gets instanciated from app.xaml using a parameterless ctor.
Is there a preferred way to get access to an application level container - for all other classes in the app I just use ctor injection to get the global container.
What I am currenlty doing for the ViewModelLocator is defining a static variable in my BootStrapper class to store the container. I create the container by overriding the CreateContainer method on UnityBootStrapper.
protected override IUnityContainer CreateContainer()
{
BootStrapper.DIContainer = base.CreateContainer();
return BootStrapper.DIContainer;
}
Then in the ViewModelLocator class I just reference the BootStrapper.DIContainer property to register my viewmodels
BootStrapper.DIContainer.RegisterType<IShellViewModel, DesignShellViewModel>();
This works fine but it is the only place in the application that needs to reference this static property on the bootstrapper - and would like to get rid of it if possible.
thanks
Michael
I had the same issue while converting a Silverlight RIA Business app of mine to use Prism, Unity, and MVVM light toolkit. I came up with this workaround which is to just let the App.xaml create an instance of my ViewModelLocator class and during the application startup event I remove that instance it created from the application resources and re-add an instance using Unity container's Resolve method.
Register the VML with Unity.
Boostrapper.cs: (UnityBootstrapper class)
protected override void ConfigureContainer()
{
Container.RegisterType<ViewModelLocator>(new ContainerControlledLifetimeManager());
base.ConfigureContainer();
}
Use either constructor or property injection in the VML for IUnityContainer. Here I'm using property injection. Also note that the default parameterless constructor is required because App.xaml is going to instantiate its own instance that we'll just wind up throwing away.
ViewModelLocator.cs: (used for blendability)
public class ViewModelLocator
{
[Dependency]
public IUnityContainer Container { get; set; }
public ViewModelLocator() { }
....
}
Remove and re-add the VML to the application resources. Replace the string literal "Locator" with whatever you called your VML in the App.xaml ResourceDictionary section.
App.xaml.cs:
private void Application_Startup(object sender, StartupEventArgs e)
{
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
Resources.Remove("Locator");
Resources.Add("Locator", bootstrapper.Container.Resolve<ViewModelLocator>());
}
Your now cocked, locked, and ready to rock..
I thought I'd follow-up on this since it hasn't been marked as answered.
I've followed a similar approach to Degree451 except I don't remove and re-add the locator as that smells a bit. Instead, I use the built-in capabilities of both Silverlight as well as Unity to handle the problem.
Having the Container property in the ViewModelLocator class marked with the DependencyAttribute means that the class can have its dependencies resolved after instantiation. So in my Bootstrapper, I override ConfigureContainer and add the following code:
var vml = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator;
Container.BuildUp(typeof(ViewModelLocator), vml);
The first line retrieves the instance automatically created by the application from the App.xaml markup. The second line uses Unity to resolve any properties marked with the DependencyAttribute.
To me, this is a much cleaner solution. Of course, it's not Blendable.

Resources