0
votes

I have a WPF/prism application similar to the mockup shown below:

Layout

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?

3

3 Answers

1
votes

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.

0
votes

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.

0
votes

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.