Search code examples
wpfmoduleprismeventaggregator

How can I initialize a Prism module without View and ViewModel for working with EventAggregator?


I am writing an application using Prism that contains three modules. First one has a view to configure a "Person", second one is a service that generates that "Person" and third one is the visualization of all people. These three modules communicate with EventAggregator system. But I have problems with the messages on the service one.

In this service module I only have the service implementation and the module definition. This service is a people manager that receives a message from EventAggregator, creates a "Person" with a task and send a message to the third module with this "Person".

Service:

private List<Person> people = new();

public PeopleControllerService(IEventAggregator eventAggregator, ICommonParametersService commonParameters)
{
    this._eventAggregator = eventAggregator;
    eventAggregator.GetEvent<GeneratePersonEvent>().Subscribe(GeneratePerson);

    this._commonParameters = commonParameters;
}

private void GeneratePerson()
{
    Person newPerson = new(this._commonParameters.DefaultPersonTask);
    this.People.Add(newPerson);

    this._eventAggregator.GetEvent<AssignedPersonEvent>().Publish(newPerson);
}

Module definition:

private PeopleControllerService moduleController;

public void OnInitialized(IContainerProvider containerProvider)
{
    IEventAggregator eventAggregator = containerProvider.Resolve<IEventAggregator>();
    ICommonParametersService commonParametersService = containerProvider.Resolve<ICommonParametersService>();
    this.moduleController = new(eventAggregator, commonParametersService);
}

public void RegisterTypes(IContainerRegistry containerRegistry)
{
    
}

The problem is that when I send the "GeneratePersonEvent" message it never reaches the PeopleControllerService and the "GeneratePerson" method is never executed.

I've tried using a view and a viewModel, programming the service in the viewModel and assigning the view to a dummy and hidden region in the app and I've verified that it works that way.

Modified module definition:

public void OnInitialized(IContainerProvider containerProvider)
{
    IRegionManager regionManager = containerProvider.Resolve<IRegionManager>();
    regionManager.RequestNavigate(RegionNames.DummyRegion, "PeopleController");
}

public void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<PeopleController>();
}

How can I use the EventAggregator without using a dummy view? Do I have to add something in the "RegisterTypes" method? I've tried with:

public void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.Register<PeopleControllerService>();    
}

but it doesn't work either.

I've checked this post: Can I get EventAggregator Subscribe Message without view, viewmodel in prism?, and there it says that it is possible, but doesn't describe how to implement.


Solution

  • Most of the time you want exactly one instance of a service, and you have to tell the container:

    public void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterSingleton<PeopleControllerService>();    
    }
    

    Also, you want your service to implement an interface so that you can pass different implementations to the consumers of your service, the most obvious case is your tests.

    You need to actually create the instance of your service, too. Normally, you inject it into some consumer, but if it's completely decoupled and only talks through the event aggregator, you have to create the instance manually:

    // in App.xaml.cs
    protected override void OnInitialized()
    {
        Container.Resolve<PeopleControllerService>();
    
        base.OnInitialized();
    }
    

    Hint: if the service implements an interface, the application doesn't need to personally know the controller module.