Using Windsor to automatically subscribe to event aggregator with custom facility
Asked Answered
A

4

7

Reading this blog post it mentions you can get your DI container to automatically subscribe to events if it implements IHandle<>. That is exactly what I'm trying to accomplish.

Here is what I have so far.

container.Register(Component
    .For<MainWindowViewModel>()
    .ImplementedBy<MainWindowViewModel>()
    .LifeStyle.Transient
    .OnCreate((kernel, thisType) => kernel.Resolve<IEventAggregator>().Subscribe(thisType)));

While this code is successfully subscribing MainWindowViewModel to receive published messages, come time to actually receive messages nothing happens. If I manually subscribe all works as expected.

Here is my MainWindowViewModel class.

public class MainWindowViewModel : IHandle<SomeMessage>
{
    private readonly FooViewModel _fooViewModel;
    private readonly IEventAggregator _eventAggregator;

    public MainWindowViewModel(FooViewModel fooViewModel, IEventAggregator eventAggregator)
    {
        _fooViewModel = fooViewModel;
        _eventAggregator = eventAggregator;

        //_eventAggregator.Subscribe(this);

        _fooViewModel.InvokeEvent();
    }

    public void Handle(SomeMessage message)
    {
        Console.WriteLine("Received message with text: {0}", message.Text);
    }
}

How can I tell Windsor to automatically subscribe if any class inherits IHandle<>?

I ended up coming up with this custom facility that subscribes.

public class EventAggregatorFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.DependencyResolving += Kernel_DependencyResolving;
    }

    private void Kernel_DependencyResolving(ComponentModel client, DependencyModel model, object dependency)
    {
        if(typeof(IHandle).IsAssignableFrom(client.Implementation))
        {
            var aggregator = Kernel.Resolve<IEventAggregator>();
            aggregator.Subscribe(client.Implementation);
        }
    }
}

Looking at the EventAggregator class provided by Caliburn.Micro I'm able to see that the subcription is successful, however if another class publishes a message the MainWindowViewModel class isn't getting getting handled. Manually subscribing still works but I'd like to automate this process. I have a feeling that it's not subscribing the correct instance. Not sure how to fix that, though.

I've also tried using every other event exposed by the Kernel property. Most of them can't resolve IEventAggregator.

What am I missing?

Addition answered 12/8, 2011 at 13:12 Comment(2)
maybe you can convert this to windsor #6871577Christan
Very interesting link. Looks like I'll need a custom facility.Addition
M
3

"I have a feeling that it's not subscribing the correct instance. Not sure how to fix that, though."

You are subscribing to the type of the implementation (an instance of System.Type), not the actual dependency being resolved. The line:

aggregator.Subscribe(client.Implementation);

should be

aggregator.Subscribe(dependency);
Masonry answered 17/8, 2011 at 11:19 Comment(2)
Awesome. Not sure why I didn't check the type of Implementation. I'll award the bounty in an hour.Addition
Glad I could help! Say if there's anything else :)Masonry
C
1

You probably need to configure your IEventAggregator as a singleton. Not sure exactly how this would be done with Windsor, but with ninject you would do something like

Bind<IEventAggregator>().To<ConcreteEventAggregator>().InSingletonScope()

Having a singleton would ensure that all the events are aggregated into a single underlying dictionary (or the data type of your choice), instead of having a new one created every time you resolve IEventAggregator. HTH.

Couching answered 17/8, 2011 at 11:38 Comment(0)
A
0

this is how to impliment IHandler

public interface IHandle<TClass> : IHandle 
{  
    void Handle(TClass Subscriber);  
}  

and this is how to use it..

    public class MyViewModel : IHandle<SubscriberType >
   {  
         public void Handle(SubscriberType Subscriber)
         {  
            //Do something here.
         }  
   }
Astronomy answered 12/8, 2011 at 13:38 Comment(1)
As the example code I provided suggests I'm already doing this. I want a way to automatically subscribe if a type inherits from IHandle<T>.Addition
I
0

This might be pretty late, but this is how i was able to acheive it

container.AddFacility<StartableFacility>();

container.Register(Component.For<ISubscriber<TagsProcessed>>()
                                    .ImplementedBy<TagsProcessedListener>()
                                    .OnCreate((kernel, instance) => eventAggregator.Subscribe(instance)).Start());
Illaudable answered 25/7, 2014 at 7:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.