Navigation between views - command / events

Topics: CAB & Smart Client Software Factory
Mar 12, 2007 at 4:39 AM

What is the preferred way for an action on one view to cause navigation to another?

For example, let's suppose the canonical example -
View A = list of customers.
View B = customer details.

Select a customer on A and navigate through to B.

Reading the Smart Client Software Factory documentation I'm told to use the Event Broker where Presenter A raises an event which is picked up by Presenter B causing the navigation.
(see ms-help://ms.scsf.2006jun/SCSF/html/03-070-View%20Navigation.htm)

Reading Mario Szpuszta's article -
he suggests that the CommandPattern is the preferred way to transfer control to another component and that I should "Keep relationships between components as events at a minimum—as few as possible and as much as necessary."

But there's more... Looking at the reference application (BankBranchWorkbench) they use an Action Catalogue to show views in the workspace where a control called LinkLabel has an action tied to its click event - (_actionCatalog.Execute(ActionNames.ShowPurchaseCDView)

Is there a definitive answer on best practices for doing Navigation in CAB?



Mar 12, 2007 at 3:25 PM
Hi Graeme,
There is definitively no definite answer about this, but there are some hints about better practices; but always remember, you should always do what it is better suited for your current project, as this is not the solution for every project, just a guidance for a majority (or at least we expect) of them.
What p&p recommends in this case is to use the EventBroker. Following your example, View A contains the list of customers and is responsible (with this I don’t mean just the view, but its presenter really) for managing only that view, and allowing the selection of any of them, but that’s it. It does not care about what happens when a customer is selected, nor where its details are shown, nor if the only consequence of selecting a customer is just to show its details. In other words, this is the perfect example of the need of an event, not just with an Event Broker, but even for .NET events if you didn’t have the benefits of CAB.
The commandpattern, instead, is used when a component (in this case Presenter A) needs to perform an action which belongs to a different module (or not) but you want to keep decoupled. But with “needs”, I mean that it passes the control to the other component, and maybe when the command finishes executing, it provides feedback to the caller.
What Mario Szpuszta meant in his article is that you have to be aware the consequences of using the Event Broker. As he wrote in that same paragraph: “If you need immediate response or need to know exactly who a component is talking to, the event broker is the wrong system. Do not implement immediate response by raising events back and forward between components.”
An action is used when there is the need to allow different modules to decide whether an action could be executed. The caller tries to execute an action (which is in fact a method with a special signature, decorated with the Action attribute with an action name). When this happens, all action conditions previously registered vote on whether to allow it or not (CanExecute is called on each condition which returns true or false). If all of the conditions return true, the action gets executed, otherwise (at least one condition returns false) it is not. As you can see, you could use actions to solve problems like what the Event Broker or Command-pattern does, but it is in fact there for a different thing. You could actually mix them up, and call an event or command and then execute an action for example.
In the case of the BankBranchWorkbench example, the action is used to determine whether the user has authorization to perform that action as you can see in EnterpriseLibraryAuthorizationActionCondition class.
You could even use an action for preventing the user from navigating away from unsaved changes to the customer’s details for example.
Please let me know if this helps,

Julián Domínguez
Mar 13, 2007 at 1:25 AM
Hi Julian, Thanks for the quick response.

That does help a lot - coupled with a moment of clarity last night when I think it dawned on me a nice way of doing this that follows the CAB guidelines.

I've been pretty clouded from Web-land as most of my recent projects have been Asp.Net but I think I understand CAB / smart client world a little more.

Using the same example -

Module 1
View A
View B

Module 2
View C

I think where I went wrong was my belief that the links on View A are put there by View A implying that it either has knowledge of where it might navigate to (View B via a command, or a direct Workspace.Show), or it raises an event like 'CustomerClicked' which is subscribed to by Module 2, resulting in View C.

The way I see it now is that View A would use a Command or a WorkSpace.Show to show View B. And there will probably be a command to show View C. The difference is how these links get there.

I see Module 2 subscribing to the CustomerDisplayed event from View A (presenter) which is fired when View A is shown. This could be subscribed to by Module 2 which would use a UIExtension registered on View A, or some service, to add its own links onto the page.

The CustomerDisplayed event would be documented that it will set x, y and z in the WorkItem meaning View C can use ComponentDependency attributes for the IOC container to inject the dependencies.

That approach seems pretty elegant to me (although re-reading it, it sounds very View-A-B-C-1-2-3!!!)

Again thanks for your help.

Mar 13, 2007 at 5:57 PM
How do you use a command for cross-module communication? I've tried this before and failed. What I did is add the command to the root work item. Is there a different way?

I'm also confused why CAB needs commands when it already has events. Don't they do the same thing? Command.Execute() essentially publishs and event that multiple anonymous subscribers listen for. It sounds like the Observer Pattern all over again to me.
Mar 14, 2007 at 1:04 AM
I struggled a bit yesterday but eventually realised what my problem was -
When a WorkItem in Module-A tried to get a Command (WorkItem.Commands"foo") created in the ModuleInit of Module-B it did find a Command, but the ExecuteAction was null. It looked like CAB scopes the Command to the WorkItem which it was created it but doesn't hide it from other WorkItems (can someone elaborate on what actually happens there?)

The method I used for cross module commands was

1) Raise an Event when the View was shown (OnCustomerDisplayed<EventArgs<WorkItem>>).
2) This was subscribed to by the ModuleController in Module-B
3) Module-B-Controller added a class called ModuleBCommands to the workItem on the EventArgs.
4) These were then available to the View in Module-A.

Admittedly this still implies that Module-A has some knowledge of B in-order to call the Commands by name. That's a problem with our design (we all have them!) The proper approach would be for Module-B to register it's own UI widgits in View-A using a UIExtension Site. To the user these widgits added by Module-B that execute actions in Module-B visually appear to be part of View-A.

As for the difference between Commands and Events - a command is a way of telling something to do something whereas an event is a way to broadcast that something has happened but not caring what happens as a result. That's what Mario Szpuszta was talking about when he said "If you need immediate response or need to know exactly who a component is talking to, the event broker is the wrong system. Do not implement immediate response by raising events back and forward between components."

@the_community - is that too simplisitic a view?


Mar 14, 2007 at 2:18 PM
Hi Julian,
The BankBranch application uses a combination of an Event and Commands to link into Views in different modules.

The View is the PurchaseCD view and link which causes this view to display is added using a UIExtensionSite when the original view is displayed.

Do you see a difference in a link which says PurchaseCD (very explicit and you know exactly what will happen) and selecting a customer from a list causing its details to show?

And if in the list of Customers each had a button saying 'Show Details' would you then see the navigation becoming more explicit - not using an event because the View now has the responsibility to show the Customer Details, not just to tell whoever is listening that a customer was clicked?

... and if the second view was in a different module? Say you had a list of customers and each had a link to show their orders. How would you envisage this sort of linking between Views in CAB?

Sorry for all the questions but I really appreciate any help / hints,