wpfmvvmdependency-injectionprismuielement

Triggering an action of a UIElement from a ViewModel


I've implemented Wiesław Šoltés' awesome ZoomBorder, but I'm struggling a bit with WPF and MVVM. For the questions' completeness sake, ZoomBorder is a UIElement that inherits from Border and gives the user the possibility of zooming and panning the content of the inherited border. It also has the ability to reset the zoom and panning.

I'd like to make ZoomBorder react to an event being published by certain view model, so that when that event is published, ZoomBorder resets the zoom. In my implementation, the ZoomBorder's DataContext is a ContentViewModel, which has an IEventAggregator (Prism.Events) injected via Autofac. Ideally, I would have liked to inject the event aggregator directly into ZoomBorder, so that it can subscribe to the event, but I can't because the constructor needs to be parameterless.

So ContentViewModel has to subscribe to the event, but how would I invoke ZoomBorder's Reset method from ContentViewModel? I understand I'd be transgressing MVVM, but I don't know how else to do it. I thought about making ZoomBorder expose a Command via a dependency property, but then the Reset code would have to be on the view model, which it can't.


Solution

  • You can use the ServiceLocator inside of views or controls to resolve types from the container.

    public ZoomBorder()
    {
       _eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
    }
    

    If you use AutoFac and the event aggregator without Prism, you can use the package Autofac.Extras.CommonServiceLocator and register your container to ServiceLocator.

    var builder = new ContainerBuilder();
    var container = builder.Build();
    
    var csl = new AutofacServiceLocator(container);
    ServiceLocator.SetLocatorProvider(() => csl);