2
votes

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();
        }
1
What are you trying to achieve? Anyway, you need to subscribe if you want to handle the events. You could use reflection to fetch all your EventHandler types (classes), to create instances and to do the subscribing job, but I wouldn't recommend that. It's hard to maintain and to test.dymanoid
Hi dymanoid, I wish to achieve, that I avoid referencing each and every event handler in my application root or sub-objects. By instantiating the event handlers automatically, I can just introduce new events and event handlers and have them working without further ado.Anders Juul
I'm not too sure what problem you are experiencing, and when I use EventAggregator I certainly don't have to reference every event handler in application root. The constructors of my various VMs all take a handle to EventAggregator, using the Unity IoC, and subscribe to any events they are interested in (within their constructor, in my case). Most of those VMs will only be created based on user interaction in the running program. They are then able to respond to events published by various other Vms.Mashton
What's the point in using dedicated EventHandlers classes? Why don't you consume your events in the ViewModels like @Mashton suggests?dymanoid
It's a matter of taste, I guess. I use the events for handling business logic, which is placed in an assembly of it's own, while references from viewmodels are more rare. My events would typically represent a user action. Nothing wrong with your approach, I just prefer another way, which then presents me with a challenge :)Anders Juul

1 Answers

1
votes

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");
  }
}