Ninject

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);
Advertisements

Why overriding JsonSerializer no longer work in SignalR 2.0

I see almost everyday people having problem with overriding JSON serializer settings in SignalR. In SignalR 1.x they used an interface, IJsonSerializer, that you could override to set the JSON settings. In SignalR 2.x they instead use a concrete type JsonSerializer.

Ninject

The problem starts if you use a dependency injection framework like Ninject. The Dependency resolver that most people use for Ninject together with SignalR is doing this to get a type.

return kernel.TryGet(serviceType) ?? base.GetService(serviceType);

In SignalR 1.x this worked because when Ninject is doing TryGet on an interface it will return null and instead call base.GetService which in turn will use the type registered with SignalR’s internal IoC (GlobalHost.DependencyResolver).

In SignalR 2.x this will no longer work because we are now using a concrete type and Ninject will create instances of unregistered concrete types without complaining. base.GetService will never be called and the types registered in GlobalHost.DependencyResolver will not be used.

Remedy

One way of solving this is to register the JsonSerializer with the Ninject kernel instead of register it with GlobalHost.DependencyResolver.Register

The other is to check if the type is registered with Ninject, if it is use kernel.Get otherwise use base.GetService. This can be done like

kernel.GetBindings(serviceType).Any();