EventAggregator & Design challenges in Prism

Topics: Prism v4 - Silverlight 4
Mar 8, 2011 at 3:11 PM
Edited Mar 8, 2011 at 3:14 PM

Hello dear community,

I am experiencing some weird behaviour with event aggregators and would like to share my design and relevant code to hopefully tackle the issue. I am not using any background threading, yet the side effects look very similar...

I have two Modules within my Prism app.
1) Contact Module (includes a ContactView)
2) Navigation Module (incl. NavigationView and also a ToolBarView)

The Shell has three regions (MainRegion, ToolbarRegion and NavRegion). MainRegion is a TabControl. Whenever a ContactView is added it will be added as a new TabItem.

My NavigationView has an ObservableCollection<Contact> Contacts. Whenever I want to create a new Contact, I would add a new contact to the Contacts and also send the contact object wrapped inside a new instance of ContactView to the tabitem.  It is easier to understand it through code:

In Code:

User clicks on New Button within Toolbar:

private void OnNewContact()
{
     _eventAggregator.GetEvent<NotifyNavigationViewModelEvent>().Publish(null);
}

NavigationViewModel:

ctor()
{
     _eventAggregator.GetEvent<NotifyNavigationViewModelEvent>().Subscribe(OnAddNewContact, ThreadOption.UIThread);  
}

public void OnAddnewContact(object o)
{
   var contact = new Contact();
   Contacts.Add(contact);
   //NavigationViewModel creates a new contact, adds it to the collection and sends it to the Contact Module in order to wrap it as a tabitem.
   _eventAggregator.GetEvent<NotifyContactModuleEvent>().Publish(contact);
}

Contact Module:

ctor()
{
     _eventAggregator.GetEvent<NotifyContactModuleEvent>().Subscribe(DisplayContact, ThreadOption.UIThread);
}

public void DisplayContact(Contact contact)
{
     var contactViewModel = _container.Resolve<ContactViewModel>();
     var view = new ContactView(contactViewModel);
     view.Initialize(contact);
     _regionManager.Regions[Constants.MainRegion].Add(view);    OR  _regionManager.RegisterViewWithRegion(Constants.MainRegion, () => view);
     // Sometime this works, sometimes I get an argument exception "Value does not fall wihin expected range", why?  
}

The CompositePresentationEvent is done as expected like this:

public
class NotifyNavigationViewModelEvent : CompositePresentationEvent<object> { }

Bootstrapper:

protected
override void ConfigureContainer()
{
     base.ConfigureContainer();
     Container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
}

Idea:

By having the contact reference inside the ContactView within the TabItem, whatever the user input is, it would affect the new created contact object within the collection right away and I have less trouble saving its (new) state later on by RIA Services.

Do you see any problem with this design and why do I get this error message sometimes. EventAggregator in combination with RegionManager doesn't seem to work consistently.

Your help on this would be highly appreciated,
Houman

Mar 9, 2011 at 8:31 AM

I have found the solution: check out Roddles Answer: here

You have to give each View a unique name before inserting them into an ItemsControl Region. You should really put this into the documentation, unless its there and I have overlooked it. Alternatively a better error message for the exception could be very helpful for other Prism users out there pulling their hair out. :)

Thanks,
Houman

Developer
Mar 9, 2011 at 3:38 PM

Hi Houman,

Thank you for sharing this with the rest of the community, as other users might benefit from knowing this.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi