MVVM question: handling ribbon commands in a child VM?

Ribbon for WPF Forum

Posted 8 years ago by SledgeHammer01
Version: 11.1.0543
Avatar
What is the recommended pattern to follow for this? MainWindow.xaml defines the ribbon, but I want ChildViewVM.cs to handle the command. Specifically, ChildViewVM.cs is going to represent a document window in the MDI tabbed interface, so there is going to be many instances of it. Seems like ChildViewVM.cs would need to expose a static control and have the active document passed in as the param?

Comments (8)

Posted 8 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hello,

Prism has the concept of a CompositeCommand, which can have any number of DelegateCommand registered with it. The CompositeCommand can then be used as the commands in the Ribbon, and it will proxy any calls to the registered and active DelegateCommands. The DelegateCommands generally reside in the view-models and are active aware, so only the active view-model's commands would be executed (even if the other view-models have commands registered).

The CompositeCommands are effectively a proxy between the Ribbon and the active view, but really a DelegateCommand can be active even if it's view is not. This also allows you to use the RibbonCommandUIManager.Register method to tie the CompositeCommand to UI attributes (i.e. images, screen tips).

The following link describes this concept a bit more:
http://msdn.microsoft.com/en-us/library/ff921159(v=pandp.20).aspx


Actipro Software Support

Posted 8 years ago by Tony Pulokas
Avatar
Hello, I could use some more advice regarding this approach. In a nutshell, I don't know how to make my DelegateCommands active when the tab associated with the command's view/viewmodel becomes the active tab.

To provide a little background, I have set up a globally available CompositeCommand, and my viewmodel instances are each registering local DelegateCommands (as per the above post). In a TabbedMdiContainer I have multiple views of the same type (each with their own viewmodel instance). I need to set this up so that when the CompositeCommand is called, only the view/viewmodel associated with the active tab responds.

For example, if each tab has a listbox with an item selected, when the user clicks the 'delete this item' button that is linked to my CompositeCommand, only the tab the user is looking at should respond by deleting its selected item. The listboxes in the other tabs should not be changed.

I think that I need to implement IActiveAware on the viewmodel. The viewmodel would then set the DelegateCommand's IsActive property when the tab associated with that view/viewmodel becomes the active tab. Finally, I'd declare the CompositeCommands with monitorCommandActivity set to true so that CanExecute will only be checked when the delegate command is active.

I guess the problem is that I don't know how best to associate each tab with a view/viewmodel. For example, if the viewmodel subscribes to the LastActiveDocumentChanged event (see: http://www.actiprosoftware.com/support/forums/viewforumtopic.aspx?ForumTopicID=3820), how does it know whether its view lives in the active document?
Posted 8 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Tony,

If you are using Prism and our Interop assembly, then you'd just need to add your view-models to the DockSite region. Our Prism sample (included as part of our installer) indicates how you can specifiy whether it should be presented as a document or tool window. Aside from that, you'd just need implement IActiveAware on your view-model. The rest should be handled for you. As documents are activated/deactivated, our region adapter will notify Prism, which in turn will activate/deactivate your view-models.

The rest of your thoughts are correct. You'd implement IActiveAware on your view-model. When a view is activated you'd set DelegateCommand.IsActive to true, for all commands in your view-model. Likewise, you'd set IsActive to false when your view-model is deactivated. Finally, the CompositeCommand would need to watch for command changes.

If you run into specific issues please put together a small sample project that reproduces the issue and email it over then we can take a closer look. Be sure to remove any executables or change the extension of the zip file to ensure it gets past our email filters.


Actipro Software Support

Posted 8 years ago by Colin Kemp
Avatar
Instead of looking at PRISM you could take the easy route & create a custom class that inherits the ribbon button and create a Dependency Property to bind too.

Just a thought......
Posted 8 years ago by Tony Pulokas
Avatar
I've set up a docksite region and the viewmodel activation/deactivation works properly as do the commands. However, I have now run into the issue where the views are not persisted when the user changes tabs.

I see that there has been an addition in build 0544 to handle this issue (the ItemContainerRetentionMode); however, I am guessing that this fix is not an option for me since I am no longer using a DocumentItemsSource but instead I am adding viewmodels to the docksite region. When I set the ItemContainerRetentionMode to Wrapped it results in an exception when the viewmodel becomes active (either by clicking on the view or calling region.Activate(myVM)). I imagine this is because there is no DocumentItemsSource.

Large diagrams are loaded into some of the tabs in my application and it is necessary that they persist when the user changes tabs. Do you have any ideas on how I can make sure the views are not reloaded? I'd hate to have to abandon the prism-region approach because it is now working well for ensuring that only the active viewmodel responds to commands.
Posted 8 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Tony,

The ItemContainerRetentionMode will work if you are using our Prism Interop assembly. This uses DocumentItemsSource and ToolItemsSource under the hood when you add items to the DockSite region.

There was one issue with our Prism Interop that we had to correct when adding the ItemContainerRetentionMode. That change still needs to be pushed to Codeplex though. So if you built the Prism Interop for use with Prism 4, then you'd need to make that change manually (until we get the update in) and rebuild.

The change was to the DockSiteRegionBehavior.cs file on line 96 (the last line of the OnDockSiteWindowActivated method). It currently has:
region.Activate(dockingWindow.Content);
But this should be:
region.Activate(dockingWindow.DataContext);
Once that change is done, then everything should work fine. If not please put together a small sample project that reproduces your issue and email it over then we can take a closer look. Be sure to remove any executables or change the extension of the zip file to ensure it gets past our email filters.


Actipro Software Support

Posted 8 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Sorry, just to be clear. The fix mentioned above will be included in the next maintenance release. We will be updating Codeplex shortly with the fix as well.


Actipro Software Support

Posted 8 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Just fyi, we've updated the Codeplex project to include the fix mentioned above.


Actipro Software Support

The latest build of this product (v2018.1 build 0675) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.