wpf prism composite command - wpf

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.

Related

Intercept Deactivation Strategy of a Closing window?

I'm using the latest version of Caliburn Micro (4.0.173) in an application leveraging IoC.
I do not have a sample project yet has my sandbox is using nugets from Telerik that are not easily findable. But I think a detailed explanation can get the point across:
I have a ProfileEditorViewModel : Conductor<IScreen>.Collection.OneActive resolved by the container (singleton) through the constructor of my ShellViewModel and I use the I use the WindowsManager to open my ProfileEditorViewModel in a different window:
public class ShellViewModel : IShellViewModel{
private readonly IProfileEditorViewModel _profileEditor;
private readonly IWindowManager _windowManager;
public ShellViewModel(IWindowManager windowManager, IProfileEditorViewModel profileEditor){
_windowManager = windowManager;
_profileEditor = profileEditor;
}
//Method triggered by an Action from the View
public void OpenProfileEditor(){
_windowManager.ShowWindowAsync(_profileEditor, null, null);
}
}
When I close the ProfileEditor window (clicking on the top right red cross), it triggers a closing type deactivation, which is coherent with the implementation of a conductor (not being conducted itself) being shutdown. The Screens collection is being wiped and some more cleaning is being done through the Screen.cs implementation of Caliburn.
However, for this application, I'm facing "the view not being unbound" issue (https://github.com/Caliburn-Micro/Caliburn.Micro/issues/361) and next time I open the ProfileEditor, it'll bind a new view (because the Views Collection of my viewmodel was empty) and it create some issue related to UI components used in the view (basically one event from the viewmodel triggers similar actions, on the view(s) side, that all come back to the viewmodel, which create some identification issue)
Reading through the issue 361, I'm currently able to catch the Unloaded event of my ProfileEditor (once closed), and basically clean the DataContext of any view associated to the viewmodel (before Screen cleans the Screens collections). Next time I open the ProfileEditor, it'll bind a new view and it'll be the only one = it works.
However clearing the DataContext may produce some other issue down the road.
What I would like to do, is to avoid clearing the View collection of the ProfileEditorViewModel upon closing. So Caliburn can use this reference the next time it needs to resolve a window/view for the ProfileEditorViewModel (instead of looking for a new one).
Is it possible to intercept the Deactivation / Closing strategy and change the close parameter to false ?
Another solution may be for my ShellView to be a Conductor<>.Collection.AllActive but I can't wrap my head around teh management of a window closing. How to intercept the ProfileEditor windows closing and proceeding with a deactivation of the ProfileEditorViewModel instead of a closing.
I hope it make sense :)
Thank you in advance for your help

How do I solve the following design in the MVVM paradigm? (newb)

I'm still starting out with MVVM and read through all the MSDN Prism examples but I'd nonetheless like some guidance with the following design problem which I feel will help me latch onto the Prism concepts and reinforce what I just learnt
I have a multi-window application - each window has a filter drop down control. The value of this filter control will affect the display of other controls within that same window, eg grids, charts etc.
Certain interactions (eg double clicking a row on a grid) will spawn another window which will have its own separate filter control, which will similarly affect the display of other controls only within that window
How do I implement this behavior of the filter driving the display of other user controls it has no idea of and have it restrict its behavior to only the window hosting it? How do I keep these interactions loosely coupled?
I'm thinking I need to use the EventAggregator and for the filter control to publish an update event when the selection changes? Am I thinking about this the right way? Would each window need a separate EventAggregator?
Yes, you are thinking about this the right way. The EventAggregator is a good tool for what you're doing. You'll need to have the EventAggregator on every window you plan to raise an event from. You can inject the EA into your constructor or use the ServiceLocator. Here are 2 examples:
// Ctor injection
private IEventAggregator _eventAggregator;
public ViewModelBase(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
// Service Locator
ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<YourEvent>().Publish();
Now, you'll need to create a CompositePresentationEvent for the EA to publish. You can minimize the number of these that get created by including a payload in the CPE. Something like this:
public class NavigationSelectedEvent : CompositePresentationEvent<NavigationEnum.Destination>{}
So now you're ready to publish the event:
_eventAggregator.GetEvent<NavigationSelectedEvent>().Publish(NavigationEnum.Destination.Home);
And then subscribe to it - using an optional filter on the payload so you're not wasting resources:
this.EventAggregator.GetEvent<NavigationSelectedEvent>().Subscribe(HandleNavigationEvent, ThreadOption.UIThread, false, i => i == NavigationEnum.Destination.Home);
You should publish the filter notification using the EventAggregator, that is the best way to do it from my experience. You should be using only one EventAggregator to serve as a hub between all the subscribing objects.
Something like:
MyNotificationChangedArgs args = new MyNotificationChangedArgs();
args.Payload = GetThePayload(someParameters);
myEventAggregator.GetEvent<NotificationFilterChangedEvent>().Publish(args);
Another thing that really helps is to dependency-inject the EventAggregator, for instance via Unity. This way all of your controls can simply access the common EventAggregator by calling on the UnityContainer.Resolve method:
var myEventAggregator = myUnityContainer.Resolve<MyEventAggregator>();
Every View has access to the Model through the ViewModel. Model your filters. Then the Views bind to ViewModel representations that use the filters. Your Views don't have to know about each other, they just have to bind to the Model.

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()));

Open dialog in WPF MVVM

I have an application that need to open a dialog from a button where the user enters some information.
At the moment I do it like this (which works fine)
The button click generates a command in the ViewModel.
The ViewModel raises an event which the Controller listens to.
The Controller works out the details of the new window (i.e. View, ViewModel & model) and opens it (ShowDialog)
When the window is closed the Controller adds the result to the eventargs and returns to the ViewModel
The ViewModel passes the information to the Model.
There are a lot of steps but they all make sense and there is not much typing.
The code looks like this (the window asks for the user's name)
ViewModel:
AskUserNameCommand = DelegateCommand(AskUserNameExecute);
...
public event EventHandler<AskUserEventArgs> AskUserName;
void AskUserNameExecute(object arg) {
var e = new AskUserNameEventArgs();
AskUserName(this, e);
mModel.SetUserName(e.UserName);
}
Controller:
mViewModel.AskUserName += (sender,e) => {
var view = container.Resolve<IAskUserNameView>();
var model = container.Resolve<IAskUserNameModel>();
var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model);
if (dlg.ShowDialog() ?? false)
e.UserName = model.UserName;
}
My question is how the horizontal communication works in the MVVM pattern.
Somehow it seems wrong to let the controller be involved in the data transfer between the models.
I have looked at the mediator pattern to let the models communicate directly. Don't like that idea since it makes the model depending on implemetations details of the GUI. (i.e. if the dialog is replaced with a textbox, the model need to change)
I don't like most of the current suggestions for one reason or another, so I thought I would link to a nearly identical question with answers I do like:
Open File Dialog MVVM
Specifically the answer by Cameron MacFarland is exactly what I do. A service provided via an interface to provide IO and/or user interaction is the way to go here, for the following reasons:
It is testable
It abstracts away the implementation of any dialogs so that your strategy for handling these types of things can be changed without affecting constituent code
Does not rely on any communication patterns. A lot of suggestions you see out there rely on a mediator, like the Event Aggregator. These solutions rely on implementing two-way communication with partners on the other side of the mediator, which is both hard to implement and a very loose contract.
ViewModels remain autonomous. I, like you, don't feel right given communication between the controller and the ViewModel. The ViewModel should remain autonomous if for no other reason that this eases testability.
Hope this helps.
i use this approach for dialogs with mvvm.
all i have do do now is call the following from my viewmodel to work with a dialog.
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
I have come across similar problems. Here is how I have solved them, and why I have done what I have done.
My solution:
My MainWindowViewModel has a property of type ModalViewModelBase called Modal.
If my code needs a certain view to be modal, it puts a reference to it in this property. The MainWindowView watches this property through the INotifyPropertyChanged mechanism. If Modal is set to some VM, the MainWindowView class will take the VM and put it in a ModalView window where the appropriate UserControl will be shown through the magic of DataTemplates, the window is shown using ShowDialog. ModalViewModelBase has a property for DialogResult and a property called IsFinished. When IsFinished is set to true by the modal VM, the view closes.
I also have some special tricks for doing interactive things like this from backgroundworker threads that want to ask the user for input.
My reasoning:
The principle of modal views is that other views are disabled, while the modal is shown. This is a part of the logic of the View that is essentially lookless. That's why I have a property for it in the MainWindowViewModel. It I were to take it further, I should make every other property or command for all other VM's in the Main VM throw exceptions, while in modal mode, but I feel this to be excessive.
The View mechanism of actually denying the user any other actions, does not have to be performed with a popup window and showdialog, it could be that you put the modal view in the existing window, but disable all others, or some other thing. This view-related logic belongs in the view itself. (That a typical designer can't code for this logic, seems a secondary concern. We all need help some times.)
So that's how I have done it. I offer it only as a suggestion, there is probably other ways of thinking about it, and I hope you get more replies too.
I've used EventAggregator from Prism v2 in similar scenarios. Good thing about prims is that, you don't have to use entire framework in your MVVM application. You can extract EventAggregator functionality and use it along with your current setup.
You might have a look at this MVVM article. It describes how a controller can communicate with the ViewModel:
http://waf.codeplex.com/wikipage?title=Model-View-ViewModel%20Pattern&ProjectName=waf

Model-View-Presenter and Modal Dialog boxes.... How to?

I am implementing MVP/M-V-VM in WPF and I'm having good luck with it so far. However, I don't see how this model supports implementing Modal dialog boxes. I've derived my work from Crack.NET (http://www.codeplex.com/cracknetproject) to learn how this stuff works.
I have a ShellView view (which is just XAML) that has a menu on it. The menu binds to a command in the ShellModelView that says "EditPreferences".
The ShellModelView implements the ICommand for EditPreferences and here we want to put up a dialog box to let the user edit preferences for the application.
Several problems here:
1. The ShellModelView doesn't have a reference to the ShellView to properly parent the dialog. The ShellModelView is the DataContext of the ShellView but I don't see a backreference that's setup.
2. The ShellModelView shouldn't be loading explicit UI anyway. So what's the proper interaction model here?
3. How do I build up my PreferencesDialog so that it's properly separated between logic and view as well? PreferencesDialog itself needs to be a Window so you can call ShowDialog on it, but that means you need a reference to the Window (e.g. View) in order to instantiate it. Ideally I should be able to unit test the code/validation within PreferencesDialog without instantiating the view (using a Mock view perhaps?).
Perhaps this is not the appropriate way to look at it, but this is the approach I take with M-V-VM in WPF. Opening windows and dialog boxes or an "EditPreferences" view are UI specific functions. If I were to rewrite the your entire UI replacing all of the views, I may wind up combining the "EditPreferences" view with another view, and therefore never want to open it in another screen. If this were tied to the ViewModel, it would be difficult to get around. In this particular situation, I would have a button or menu item in my "ShellView" that creates a new instance of my "EditPreferences" view, and then passes in the "EditPreferences" ViewModel which may either come from a property in my "ShellViewModel", or perhaps my "EditPreferences" view instantiates the ViewModel itself.
Here is a similar question on SO that basically says the same thing: M-V-VM Design Question. Calling View from ViewModel
You will need a controller in your case. The controller should be in charge for showing the preference dialog window.
As I can envision it the controller should be responsible for creating the ShellModelView and binding view's DataContext to it. The controller should be also responsible for handling command execution of EditPreferences. In the execution logic the controller will create a new PreferencesDialog and its corresponding view model.
You can find similar patterns in Prism if you haven't already did it. You can also reuse the DelegateCommand provided there :)
Have the PreferencesDialog implement a interface that is one of the properties of the EditPreference command. The command would interact with the dialog through the interface. For Unit Testing the mock object would implement the interface instead.
The dialog class then can reside on your highest layer.
My 2 cents is:
Pass some kind of viewfactory contract as the command parameter or inject a viewfactory contract into the view model. The view model will them use the viewfactory to create any modal/non modal views it needs. The viewfactory could also take in as a parameter of its Show/ShowModal method a viewmodel to display. Furthermore, the viewfactory could use a datatemplate to display any viewmodal passed in as a parameter.
Add a ShowViewModel property to the viewmodel in question. A DataTrigger could then watch for this property and when it is of a particular type show the view, etc.

Resources