3
votes

I have a composite WPF application. I am planning to implement tool bar functionality. There are few toolbar items (basically print, save, hide, expand, undo) which will be common to all views in the main region. For this i have created default toolbar module which will add these items (print, save, hide, expand, undo) to the toolbar region. when user clicks any toolbar item, this need to be handled by all 20 views in the main region.

For each toolbar item, i have associated a prism delegatecommand object.

sample:

private ICommand _printCommand;

public ICommand PrintCommand
{
    get
    {
        if (_printCommand == null)
        {
            _printCommand = 
                new DelegateCommand<object>(**Print**, **CanPrint**);                    
        }

        return _printCommand;
    }
}

Xaml, bind toolbar item to this command.

In the main region, we display close to 20 views. All these views have to subscibe to this command. I am thinking of using event aggregator to publish an event, and all the views will subcribe to this event.

For ex: when the user clicks print, print command executes Print method which will publish print event. This event will be subcribed by 20 views and do further processing.

Am I implementing the toolbar in the right way?

4
do you wish all views to print, or only the current view, .e.g the view with the input focus?Ian Ringrose
For print , i would like to print the view with input focus. But for save & expand , it should be applied to all viewsPraveen

4 Answers

2
votes

I had initially thought of using composite commands. But by going through documentation it may not fit my requirements.

Ex : Application supports 40 views Main region -> 20 Views that are active , all the view models are derived from baseviewmodel.

toolbar -> save button -> databinding to compositesaveallcommand(activeaware monitor enabled) baseviewmodel -> save command -> registers/ unregisters based on specific filter conditions to compositesaveallcommand

when user clicks save button ,compositesaveallcommand looks for all registered commands that are active, and checks for all registered viewmodel commands calls (canexecute method, and all registered commands need to return true) then invokes child commands ( execute method) .

But in my case if the user make modifications in a single view , remaining 19 views there are no modifications. But I would like to execute save for single view. Looks like composite command will not invoke registered comamnds unless it can execute all.

2
votes

If application allows the user to executes multiple commands at the same time, we may want to allow the user to save all the items on different tabs using a single command represented by a ribbon button. In this case, the Save All command will invoke each of the Save commands implemented by the view model instance for each item. In the Stock Trader RI, for example, the Submit and Cancel commands for each buy/sell order are registered with the SubmitAllOrders and CancelAllOrders composite commands, as shown in the following code example (see the OrdersController class).

commandProxy.SubmitAllOrdersCommand.RegisterCommand(
                    orderCompositeViewModel.SubmitCommand );
commandProxy.CancelAllOrdersCommand.RegisterCommand(
                    orderCompositeViewModel.CancelCommand );

The preceding commandProxy object provides instance access to the Submit and Cancel composite commands, which are defined statically. For more information, see the class file StockTraderRICommands.cs.

public class MyViewModel : NotificationObject
{
    private readonly CompositeCommand saveAllCommand;

    public ArticleViewModel(INewsFeedService newsFeedService,
                            IRegionManager regionManager,
                            IEventAggregator eventAggregator)
    {
        this.saveAllCommand = new CompositeCommand();
        this.saveAllCommand.RegisterCommand(new SaveProductsCommand());
        this.saveAllCommand.RegisterCommand(new SaveOrdersCommand());
    }

    public ICommand SaveAllCommand
    {
        get { return this.saveAllCommand; }
    }
}
1
votes

This is exactly what the CompositeCommand does. I believe there are no examples (the Commanding QuickStart or the RI do not show active aware activity anymore, they did in Prism v1), but if you use the active aware stuff, you get what you are asking for. The only thing is that you need to make sure that each of the individual DelegateCommands get their IsActive property correctly updated when they should (i.e. when the view gets activated).

0
votes

I don't really like the idea of using the EventAggregator too much for things like this. Especially if you decided to create a multi document editor interface, each of your editors is going to be responsible for a lot of filtering to get the events that are only appropriate for them.

It might be easy to use EventAggregator for this purpose, but I think it's probably not really the right fit. That said, it's not really wrong... in fact I believe a few of the Prism samples do exactly this, but I think it puts too much responsibility on the constituents for filtering, rather than leveraging framework features.

Your subject suggests you were thinking of using CompositeCommands for this. Is there any reason you aren't doing this instead of using the EventAggregator? If you had a standard place where ViewModels could register their Commands designed to handle each of these buttons with a composite command sitting behind each one, wouldn't that give you the functionality you wanted? In addition to being able to handle the button commands, each of the constituent views/viewmodels would be able to disable buttons when they were inappropriate, etc.

Take a close look at the CompositeCommand samples in the Prism documentation and see if they don't do what you want.