Anders Juul
Anders Juul

Reputation: 2604

How to create event subscribers in prism (eventaggregator)

I have a recurring pattern in my projects.

I have commands which publish eventaggregator-events and I have classes which explicitly subscribe to the events and handle them.

Problem: In the past I have referenced each and every eventhandler from my application root object to ensure that they get created and thus 'live' to be able to catch the event. Is there a way in which I do not have to do this with every event handling class? All the event handlers are named *EventHandler, if that could be of use...

I use Unity for IOC container.

Thanks for any input,

Anders, Denmark

    public class PickWishListCommand : BaseCommand, IPickWishListCommand
    {
        private readonly IEventAggregator _eventAggregator;

        public PickWishListCommand(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _eventAggregator
                .GetEvent<PickWishListEvent>()
                .Publish(parameter);
        }
    }

    public class PickWishListEventHandler : IPickWishListEventHandler
    {
        public PickWishListEventHandler(IEventAggregator eventAggregator)
        {
            eventAggregator.GetEvent<PickWishListEvent>().Subscribe(OnEvent);
        }

        private void OnEvent(object obj)
        {
            throw new System.NotImplementedException();
        }
    }

public partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var container = new UnityContainer();
        container
            .RegisterTypes(
                AllClasses.FromAssembliesInBasePath(),
                WithMappings.FromMatchingInterface,
                WithName.Default,
                WithLifetime.ContainerControlled);

        var executionContext = container.Resolve<IExecutionContext>();
        var configurationApplicationService = container.Resolve<IConfigurationApplicationService>();

        configurationApplicationService.SetupMainWindow();

        //Thread.Sleep(3000);
        var mainWindow = new MainWindow
        {
            DataContext = executionContext.MainWindowViewModel
        };
        mainWindow.Show();
    }
}

Edit: I've found a way to auto-instantiate -- but keep the question open; can it be done more elegantly?

     protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var container = new UnityContainer();
            container
                .RegisterTypes(
                    AllClasses.FromAssembliesInBasePath(),
                    WithMappings.FromMatchingInterface,
                    WithName.Default,
                    WithLifetime.ContainerControlled);

            var eventHandlers = new List<object>();

            foreach (var registration in container.Registrations)
            {
                var nameOfRegType = registration.RegisteredType.Name;
                var overrides = new ResolverOverride[] { };
                if (!nameOfRegType.EndsWith("EventHandler") || !nameOfRegType.StartsWith("I")) continue;

                var t = container.Resolve(registration.RegisteredType, overrides);
                eventHandlers.Add(t);
            }
            var executionContext = container.Resolve<IExecutionContext>();
            executionContext.EventHandlers = eventHandlers;

            var configurationApplicationService = executionContext.ConfigurationApplicationService;
            configurationApplicationService.SetupMainWindow();

            var mainWindow = new MainWindow
            {
                DataContext = executionContext.MainWindowViewModel
            };

            mainWindow.Show();
        }

Upvotes: 2

Views: 829

Answers (1)

Mashton
Mashton

Reputation: 6415

Just to clarify my comment with some code, when I use the Prism EventAggregator it will be in the following way:

// A library class holding event classes
public class ThisClassDefinesMyEvents
{
  public class MyImportantEvent : CompositePresentationEvent<string>{};
}

// An example viewmodel, that subscribes to an event
public class SomeRecievingVm
{
  private readonly IEventAggregator _eventAggregator;
  public SomeRecievingVm(IEventAggregator eventAggregator)
  {
    _eventAggregator = eventAggregator;
    _eventAggregator.GetEvent<MyImportantEvent>().Subscribe(MyEventHandlingMethod);
  }

  public void MyEventHandlingMethod(string whatHappened)
  {
    Console.WriteLine(whatHappened);
  }
}

// An example VM that publishes an event, under a couple of different circumstances
public class SomeSendingVm
{
  private readonly IEventAggregator _eventAggregator;
  public SomeSendingVm(IEventAggregator eventAggregator)
  {
    _eventAggregator = eventAggregator;
    _eventAggregator.GetEvent<MyImportantEvent>().Publish("I am alive");
  }

  private void SomeMethodThatHappensSometimes()
  {
    _eventAggregator.GetEvent<MyImportantEvent>().Publish("I've done something");
  }
}

Upvotes: 1

Related Questions