Execute same command from different views - MMVM - wpf

I have few Views that represent the same data in different ways (Grid, TextBox, etc..) and in different locations in application.
Every view is bindded to different View-Model.
I have a commands like Add-New, Update, Delete, etc... on the selected row/s. The commands can execute on the active View from a main toolbar (different view), a button on that view, right click menu and some other place.
I don't want to rewrite the commands for every scenario that the command can appear.
Is there any other way to preform it without duplicate the code of the commands and without a massive switch for every scenario.
Thank you.

You can either use the CommandBindings which holds commands in one main place (window for example)
and the call it from each view or control under its scope.
Or create a "CommnadViewModel" which each specific viewModel would get on its constructor and bind to it.
It is made even easier using Unity or other containers.

Related

Creating lots of user controls in WPF?

Is it normal in a WPF app to create a lot of user controls in order to separate concerns that would otherwise be crammed in a single window with a huge XAML hierarchy? I'm finding that I keep making new user controls, even though I don't intend to reuse them, just so that each of my sub-components has a separate task. I'm also giving each of them their own view model, instead of binding things to properties on one master view model.
Is this normal? I feel like from a code cleanliness perspective I'm doing the right thing. But from a WPF perspective, I feel that this can't be right.
For example, let's say you have a list on the left side of the window, and when you select an item, it changes what's displayed on the right side. There are also buttons above your list to manipulate it, adding and deleting items for example. I would be inclined to pull that whole list out as a UserControl, which would contain just the list and the control buttons above it. Then the main window would just include my new control.
Am I going overboard?

WPF/Prism: Nested views and toolbar

I have a WPF/prism application similar to the mockup shown below:
Both TabControls contain a separate Prism region, the second one being nested into the first one. Now the toolbar should activate/deactive items depending on which view is currently active.
The toolbar is currently defined in the shell.
I tried using some sort of registry, where each ViewModel could register the toolbar commands it supports. However I then realized that the toolbar cannot know which view (and therefore which viewmodel) is active.
The problem is in the nesting, without that I could probably achieve what I wanted by binding the TabControl.SelectedItem property to the toolbar and use my registry from above.
Maybe there is a better way to do this? Or a way to let the toolbar find out which view is active?
edit: I now tried to use ActiveAware ViewModels as descriped in this article: http://www.codeproject.com/Articles/56826/ViewModel-Active-Awareness-in-a-Prism-Based-Applic, however I now have the problem that when I switch from Tab "One" to Tab "Two" and back, the nested tab's "First Tab" GotFocus event is not fired, meaning the toolbar will represent the wrong view.
Maybe this is the way to go?
edit 2: The problem seems to be that the second tabcontrol is not inside it's own scoped region. I'm using the ViewDiscovery approach to add views to my regions, so I'm not explicity creating the regionmanager in a scope. SyncActiveState seems to work only with scoped regions, as the first tabcontrol viewmodels correctly get updated when switching views.
Is there a way to use XAML to create a scoped region instead of a normal one?
The problem here is that the toolbar does not know anything about the active region; they are deliberately decoupled.
I would (personally) use the Event Aggregator to publish messages from the active ViewModel to say "I am currently active" and have the toolbar subscribe to those messages and update the buttons as appropriate.
If I were attempting to do this, I would probably create an IToolbarManager which has bool properties for each of the available toolbar actions, and an ICommand for the actions themselves.
Then, implement this interface in a concrete type where the bool properties change the CanExecute values of the commands, and call CommandManager.InvalidRequerySuggested. Register this type as a singleton with the container, then use DI to inject it into each of the views and into the shell. The Shell can then databind the Toolbar buttons to the Commands in the IToolbarManager, and the views can then set whether or not the actions are enabled as they get initialized.
I don't have a code sample because I'm just thinking through how I'd solve this, but hopefully you can follow what I'm suggesting, and it proves helpful.
I now ended up with creating an extended TabControl that uses the SelectionChanged event to set IsActive on all items implementing a specific interface. Also it walks down the VisualTree and finds any extended TabControl and does the same for the items of these and so on.
Work pretty well here, we only use TabControls so far, so this solution works for me.

Load view on double-click of row - have bindings working, and event being fired on click, but how do I actually get the view to pop up?

I have a view in Silverlight which contains a telerik:RadGridView with a number of columns.
I have it wired up so that when the user double-clicks on one of these columns, an event is fired. However, I don't know what to put in the event handler.
private void RowClicked()
{
//What goes here?
}
All I wish to do is load a popup view over my current view, with a close button so that the user can return to the previous view. A simple idea that is surely done a billion times everywhere, but I cannot figure it out or find examples of this anywhere.
Can anyone help?
Thanks very much.
You can set a previous view as input parameter to "RowClicked()" method. You will have a reference on previous view in current method. You can use it via Commands (bind a command and a command parameter to some action/event).
I have an one more idea (if you have a lot of views): you can create a navigation service. It is an interface, which contains events and methods. You should use events for navigation and methods - for sending needed data. Everyone of view should implement this interface. Needed event will be raised under view via some action (for example: button click). As for events: you can create a custom event handler, there you will set a sender instance and needed parameters. You should create a Navigation manager, there you should create a property for selected view and subscribe on everyone event. If user want navigate to another view, he will do some action and system will raise an event. You can create a custom container for created views. This container you can use for getting created instance of needed view. As you know, creating a new instance is heavy for system: need a some time and system resources. Will be easy to get a created instance of view instead a create a new. For setting default data or refreshing a binding you can user a custom method, contractor for which will be added to navigation interface.
It is a simple idea, which I used in one project. As for others samples: You can find another navigation frameworks and custom classes in internet. But, process of creating an own system will give you a level up in your work experience.

WPF prism accessing view elements from shell

I have a shell with some buttons and tabs and a few modules in my application. Each module has a view with some elements like datagrids, stackpanels, text boxes, etc. They all have a name attribute. Now when I fire an event on a shell (like click a button) I would like to be able to something with those elements (like clearing all the information written by the user in provided textboxes). The problem is, shell does not see those elements and cannot recognize them. Is there a way to access them?
Thanks for any suggestions.
I'd suggest you take an approach like what the Stocktrader Reference Implementation does with CompositeCommands. Basically a CompositeCommand is an implementation of ICommand that contains a collection of other ICommands. In the RI, the CompositeCommands are exposed as static properties on a centrally available class.
In your case, you could have a composite ClearCommand. The viewmodel for the shell would expose this to the shell view so you could hook up, say, your Clear button to it.
The viewmodels for the various modules would then hook into this ClearCommand:
GlobalCommands.ClearCommand.RegisterCommand(new DelegateCommand(x => ClearAllFields()));

wpf prism composite command

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?
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.
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; }
}
}
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).
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.

Resources