tabcontrol not activated with view discovery

Topics: Prism v4 - WPF 4
Oct 24, 2011 at 9:39 PM
Edited Oct 24, 2011 at 10:07 PM

Hello.

In my shell, I have a tabcontrol, with region's name defined in xaml inside tabcontrol (<tabcontrol ps:RegionManager.RegionName="myTabControl"...>). A separate xaml (let's say mainplugin.xaml_, containing two content controls with their own regions and region names defined in xaml, just like for the tabcontrol in the shell, is registered via view discovery (...RegisterViewWithRegion("myTabControl", () => <MainPlugIn>). There are two more xamls for injecting into those content control - which, in similar fashion, are registered via view discovery (...RegisterViewWithRegion("area1", () => <Area1PlugIn>).

Now, the problem is - the MainPlugIn does not become active until the tab item is clicked. That is, when I run the program, I see a tab added to the tab control, but the associated view does not become active - and therefore is not displayed - until I actually click on the tab.

Any ideas?

 

 

Developer
Oct 25, 2011 at 8:00 PM

Hi,

It seems that, when using a TabControl in WPF, the views are not activated by default when they're added to a region (using either view discovery or view injection). Instead, you need to explicitly activate the view invoking the Activate method of the region like this:

regionManager.Regions["myTabControl"].Activate( mainPlugIn );
Where mainPlugIn is the view injected in the TabControl region.

Also, you can activate the first view contained in the TabControl region without having an explicit reference to it doing something like this:

regionManager.Regions["myTabControl"].Activate( regionManager.Regions["myTabControl"].Views.FirstOrDefault() );

Note that the Activate method should be invoked after the view/s had been added to the region.

I hope you find it useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Oct 25, 2011 at 10:56 PM

Thank you Damian. But where would I call this from? Cant call it from the viewmodel - not until my region becomes active, which in turn initializes and activates the viewmodel - seems like a catch-22.

Developer
Oct 26, 2011 at 6:57 PM

Hi,

When and where you should activate the corresponding (or any) view depends mostly of the requirements of your scenario and your personal preferences.

A possible approach to activate a view as soon as it's added to the region could be to implement something like this:

public class MyComponent
    {
        IRegionManager regionManager;
        
        public MyComponent(IRegionManager regionManager)
        {
            this.regionManager = regionManager;
            this.regionManager.Regions.CollectionChanged += Regions_CollectionChanged;
        }

        void Regions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                if ((e.NewItems[0] as IRegion).Name.Equals("MainRegion"))
                {
                    this.regionManager.Regions["MainRegion"].Views.CollectionChanged += Views_CollectionChanged;
                    this.regionManager.Regions.CollectionChanged -= Regions_CollectionChanged;
                }
            }
        }

        void Views_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                object view = e.NewItems[0];
                this.regionManager.Regions["MainRegion"].Activate( view );
            }
            else if( e.Action == NotifyCollectionChangedAction.Remove)
            {
                this.regionManager.Regions["MainRegion"].Activate(this.regionManager.Regions["MainRegion"].Views.LastOrDefault());
            }
            
        }

    }

This code snippet subscribes to the CollectionChanged event of the Regions collection of the RegionManager. When a region is added, the Regions_CollectionChanged method is invoked, which check if the the name of the region added is "MainRegion." If it's, it subscribes to the CollectionChanged event of the Views collection of the Region and unsubscribes for the previous event. This is because the subscription to the CollectionChanged event of the Regions collection was made only to be able to subscribe to the CollectionChanged event of the Views collection when the region is available.

Then, when the Views collection is changed (like for exampling adding a view) the Views_CollectionChanged method is invoked. If a view was added, that view will be selected as the active view and if a view is removed, the last view in the region will be the active one.

This is just an example of how to activate a view, you can implement you own approaches to fulfill the requirements of your scenario.

I hope you find it useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Regions_CollectionChanged
Oct 26, 2011 at 7:19 PM

Yes that's very helpful, thank you. I actually found a way to achieve this by attaching a triggeraction - intercepting tab item added and setting it to selected when count of tab items is 1. But your example will certainly help me with other things. Thanks again!