EventAgg or COmmand

Topics: Prism v4 - Silverlight 4
Dec 28, 2010 at 5:50 PM

Hi Guys,

I am confused which one of the above will be useful. I have following scenario

ModuleA 

  ButtonAView -> Target to NavigationRegion

ModuleAView Implements INavigatioAware-> Target to MainRegion 

 

ModuleB

  ButtonBView -> Target to NavigationRegion

ModuleBView Implements INavigatioAware-> Target to MainRegion 

INavigationAware is used to work like navigation.

 

My target is to now now implement MVVM in such a way that ModuleAView has one button and ModuleBView has textbox. When button in ModuleAview is clicked something should be written in ModelBView textbox. how this can be achieved using MVVM and how communicate should be done. EventAgg or Command.

 

In future there will be multiple modules with different functionalities. Since I am learning now your help would highly be appreciated. I looked in Prism TK and QuickStart was not able to get good example implementing both.

 

Thanks.

Dec 28, 2010 at 7:19 PM

Hi,

Commanding is useful when in your application you need to handle interaction in components that don´t have direct relation on the visual tree elements, like viewmodels. This means you could trigger a command at specific point in the visual tree and handle it at a higher level.

Event Aggregation allows you to communicate between different modules along your application. This communication approach provides multicast publish/subscribe functionality. This means there can be multiple publishers that raise the same event and there can be multiple subscribers listening to the same event. As documentation shows “…Consider using the EventAggregator to publish an event across modules and when sending a message between business logic code, such as controllers and presenters.

You can read more about Commanding and Event Aggregation in Chapter 9: Communicating Between Loosely Coupled Components.

Regarding your scenario, it depends on your requirements. If you need to modify the text on a TextBox in another module when pressing a button, you could for example, bind that button to a DelegateCommand in your ViewModel and make it publish an event through the Event Aggregator. You should have your other module subscribe to that event and modify the TextBox when the event is received.

The code for the command in your ViewModel could look like this:

public class SomeViewModelOnModuleA
{
     (…)
     public DelegateCommand MyCommand { get; set;}
 
     public SomeViewModelOnModuleA()
     {
         MyCommand =new DelegateCommand(PublishEvent);
     }
 
     private void PublishEvent()
     {
         ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<SomeEvent>().Publish(“content”);
     }
      
     (…)
}

And the code in your other module, which would be subscribed to that event, could look like this:

public SomeViewModelOnModuleB
{
     public string TextBoxContent {get; set;}
     
     (…)

     public SomeViewModelOnModuleB()
     {
        ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<SomeEvent>().Subscribe(ModifyTextBox);
     }

     public ModifyTextBox(string content)
     {
        this.TextBoxContent=content;
         // Assuming you have a RaisePropertyChanged implementation
        RaisePropertyChanged(“TextBoxContent”);
     }

     (…)
}

Then you could have your TextBox’s Text property bind to the TextBoxContent property.

If your requirement involves any other kind of navigation, you might find the Navigation Chapter useful. Note that you can pass parameters on a navigation request, which might be handy for your scenario.

Also, it might be worth noting that there are QuickStarts for navigation:

I hope you find this information useful.

Thanks,

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

 

Dec 29, 2010 at 8:19 PM

Thanks for the sample code. While implementing this i am getting following exception

he composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) Cannot create an instance of type 'Test.Modules.ModuleA.Views.ModuleAView' because a constructor could not be selected for construction. Ensure that the type either has a default constructor, or a single constructor marked with the 'System.ComponentModel.Composition.ImportingConstructorAttribute'.
Resulting in: Cannot activate part 'Test.Modules.ModuleA.Views.ModuleAView'.Element: Test.Modules.ModuleA.Views.ModuleAView -->  Test.Modules.ModuleA.Views.ModuleAView -->  AssemblyCatalog (Assembly="Test.Modules.ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
Resulting in: Cannot get export 'Test.Modules.ModuleA.Views.ModuleAView (ContractName="System.Object")' from part 'Test.Modules.ModuleA.Views.ModuleAView'.Element: Test.Modules.ModuleA.Views.ModuleAView (ContractName="System.Object") -->  Test.Modules.ModuleA.Views.ModuleAView -->  AssemblyCatalog (Assembly="Test.Modules.ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Dec 30, 2010 at 12:20 PM
Hi mbronzovic,
PLease find the attached scenario i wanted to achieve. The Green Colored things goes to contentRegion in Shell and Brown Color things goes to navigation region. Now my Module A has two Views one for navigation region and other for content region. The ConentAView has textblock that displays 'SomeText'. Another module B has also two views one for navigationregion i.e. simple button and other is ContenView that has one button. When this button is clicked i wanted to see 'SomeText' in ContentAView. But the issue is when i click on button and then click on navigationregion for ContentAView nothing is there.

I hope u got what i am trying to achieve.

Your help in this regard will highly be appreiciated

Thanks



From: [email removed]
To: [email removed]
Date: Tue, 28 Dec 2010 12:19:58 -0800
Subject: Re: EventAgg or COmmand [CompositeWPF:239794]

From: mbronzovic
Hi,
Commanding is useful when in your application you need to handle interaction in components that don´t have direct relation on the visual tree elements, like viewmodels. This means you could trigger a command at specific point in the visual tree and handle it at a higher level.
Event Aggregation allows you to communicate between different modules along your application. This communication approach provides multicast publish/subscribe functionality. This means there can be multiple publishers that raise the same event and there can be multiple subscribers listening to the same event. As documentation shows “…Consider using the EventAggregator to publish an event across modules and when sending a message between business logic code, such as controllers and presenters.
You can read more about Commanding and Event Aggregation in Chapter 9: Communicating Between Loosely Coupled Components.
Regarding your scenario, it depends on your requirements. If you need to modify the text on a TextBox in another module when pressing a button, you could for example, bind that button to a DelegateCommand in your ViewModel and make it publish an event through the Event Aggregator. You should have your other module subscribe to that event and modify the TextBox when the event is received.
The code for the command in your ViewModel could look like this:
public class SomeViewModelOnModuleA
{
     (…)
     public DelegateCommand MyCommand { get; set;}
 
     public SomeViewModelOnModuleA()
     {
         MyCommand =new DelegateCommand(PublishEvent);
     }
 
     private void PublishEvent()
     {
         ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<SomeEvent>().Publish(“content”);
     }
      
     (…)
}
And the code in your other module, which would be subscribed to that event, could look like this:
public SomeViewModelOnModuleB
{
     public string TextBoxContent {get; set;}
     
     (…)

     public SomeViewModelOnModuleB()
     {
        ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<SomeEvent>().Subscribe(ModifyTextBox);
     }

     public ModifyTextBox(string content)
     {
        this.TextBoxContent=content;
         // Assuming you have a RaisePropertyChanged implementation
        RaisePropertyChanged(“TextBoxContent”);
     }

     (…)
}
Then you could have your TextBox’s Text property bind to the TextBoxContent property.
If your requirement involves any other kind of navigation, you might find the Navigation Chapter useful. Note that you can pass parameters on a navigation request, which might be handy for your scenario.
Also, it might be worth noting that there are QuickStarts for navigation:
I hope you find this information useful.
Thanks,
Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

Read the full discussion online.
To add a post to this discussion, reply to this email (CompositeWPF@discussions.codeplex.com)
To start a new discussion for this project, email CompositeWPF@discussions.codeplex.com
You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.
Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com
Dec 30, 2010 at 12:22 PM

forgot to mention i am using mef in my scenarios.

Dec 30, 2010 at 5:17 PM

Hi,

The CompositionException you’ve reported seems to be caused by the fact that your ModuleAView is trying to be composed by MEF, but it doesn’t have a constructor that is viable for MEF to construct it. In order for your class to be able to be constructed by MEF, you should have either a default constructor (one with no parameters) or a constructor marked with the ImportingConstructor attribute.

For example, a constructor with the ImportingConstructor attribute could look like this:

[ImportingConstructor]
public MyClass(ISomeService service, IEventAggregator eventAggregator)
{
    (…)
}

Note that, when MEF composes your class, injecting dependencies through the use of an importing constructor, each of the dependencies injected is also composed by MEF, so it should also follow the criteria mentioned above (about having a default constructor or one marked as ImportingConstructor).

Also, note that every class that will be composed by MEF must be marked as an export, by decorating it with the Export attribute. You can read more about this in the following articles from the MEF Programming Guide:

You might also find the following blog post by Geoff Cox handy. The suggestions in #10 Learn to debug composition errors could help you debug further composition errors that may arise.

As for your specific scenario, based on my understanding of your description, you’re trying to modify the value of a TextBox’s text property in a view, based on the press of a button in another view. However, at the time you press the button, the view with the TextBox may not have been loaded. In order to achieve this, you could make use of Region Context (more information in this chapter), which is a mechanism that allows providing contextual information between views in the same region (regardless of the fact that they could be placed on different modules). So, when clicking your button in ModuleBView, you could store that value in the Region Context, and then when ModuleAView is created, you could retrieve the value from the Region Context as well.

Please let us know if we have misunderstood your scenario. In case we did, it could be helpful if you could provide us with a repro sample so that we could help you further with your case.

Dec 30, 2010 at 8:07 PM

Hi,

Thanks for the reply. The View is loaded i am sure about the because when i click on buttonA in navigationRegion i can see viewA and when i click on buttonB in navigation i can see viewB but when i click on CountButton on ViewB and then I click on ButtonA in order to see the ViewA then I cannot see the textbox modified on ViewA.

Regarding my scenario your understanding is almost right

Regarding the RegionContext it has open new doors of information for me thanks for the information It would be very helpful if you can provide the simple example with mef using REgionContext. because i tried the link above and some blogs but was not of great help.

Once again thnx for providing me the info and opening doors of information.

thnx

Developer
Jan 3, 2011 at 5:08 PM
Edited Jan 5, 2011 at 1:28 PM

Hi,

There are no changes with MEF when using Region Context. You could obtain a reference to the region's context by using the Context property of the IRegion object, which you can obtain through the RegionManager's Regions collection. This could look like this:

 

object regionContext = regionManager.Regions["YourRegion"].Context;

 

In order for you to gain better understanding of the concepts explained in this thread, I've prepared a sample with a similar scenario as yours, using Region Context alongside with Commanding, Event Aggregation, Navigation and MEF. You can download it from here.

I hope you find this helpful.

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

Jan 5, 2011 at 9:30 AM

Hi Guido Maliandi,

The link for download the code is not working. :-(

Developer
Jan 5, 2011 at 1:29 PM

Hi,

I've updated the download link. I'm sorry for the inconveniences.

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