I saw an increasing demand for mini workflows / domain sub-parts in one of my projects. Most containers have some kind of support for sub scopes or nested containers, but I do not want to expose the Container API. If you have few places were you need nested containers you can implement this directly for your container of choice. An example of this is a container specific implementation of Web API’s IDependencyResolver. But in our case we had several different needs for scoped contexts near the domain. My solution was to abstract the context in a interface IScopedContext. (more…)
Caliburn.Micro
MVVM with Excel and Caliburn.Micro
One of my colleagues needed to modernize a tool we had for Excel. He asked me for suggestions, since he knew I’m into modern UI development. I know very little about the Excel API but after some googling I found out that you are limited to Winforms. There is however a control in Winforms called ElementHost that let you host WPF elements in Winforms. This coupled with a custom Bootstrapper for CM will enable you to develop sleek MVVM tools in Excel.
The Boostrapper will act as an entry point for our Caliburn enabled app. It needs to inherit from BootstrapperBase rather than the standard generic base class Bootstrapper of TModel.
public class Bootstrapper<TModel> : BootstrapperBase { private readonly StandardKernel kernel; public Bootstrapper(ElementHost host) : base(false) { kernel = new StandardKernel(); Start(); var model = kernel.Get<TModel>(); var view = ViewLocator.LocateForModel(model, null, null); ViewModelBinder.Bind(model, view, null); host.Child = view; } protected override void Configure() { kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope(); } protected override object GetInstance(Type service, string key) { return kernel.Get(service); } protected override IEnumerable<object> GetAllInstances(Type service) { return kernel.GetAll(service); } }
Its constructor takes the ElementHost as argument and then starts CM using the Start method on the base class. We need to hook up the ViewModel manually and its done like.
var model = kernel.Get<TModel>(); var view = ViewLocator.LocateForModel(model, null, null); ViewModelBinder.Bind(model, view, null);
First we create the ViewModel using Ninject, this way any dependecies for that model will be injected by Ninject. Then we ask CM to locate the WPF view using its convention based helper class ViewLocator. After we get the view we Bind it to the model using another CM helper class called ViewModelBinder.
Last but not least, we need to hook up the WPF element to the Winforms ElementHost.
host.Child = view;
Embedded resources
Alan Rutter asked me how to load embedded resources like themes etc.
App.xaml wont load in a none WPF project so you need to-do this manually like
var dict = new ResourceDictionary {Source = new Uri("Resources.xaml", UriKind.Relative)}; var app = new System.Windows.Application(); //This will load Application.Current Application.Current.Resources.MergedDictionaries.Add(dict);