Silverlight 4: PRISM TabControlRegionAdapter ItemTemplate

The TabControlRegionAdapter is really awesome but what happens when you want to provide a simple way to change the content of the TabItem without completely overriding the entire ItemContainerStyle. In the version of PRISM that I bundle with the Avanade Silverlight Accelerator I modified the TabControlRegionAdapter to include a property for the ItemTemplate. It was a very simple change and makes using the TabControlRegionAdapter much more convenient to use.

Another thing is if you want to apply an implicit Style or Theme to your TabControls that happen to be PRISM Regions you will need to make sure fix something inside the TabControlRegionSyncBehavior so that PRISM doesn’t blow away your Theme’s TabItem Style.

1. Add ItemTemplate Dependency Property

        #region ItemTemplate
        /// <summary>
        /// <see cref="DataTemplate"/> to set to the created <see cref="TabItem"/>.
        /// </summary>
        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.RegisterAttached("ItemTemplate", typeof(DataTemplate), typeof(TabControlRegionAdapter), null);
        
        /// <summary>
        /// Gets the <see cref="ItemTemplateProperty"/> property value.
        /// </summary>
        /// <param name="target">Target object of the attached property.</param>
        /// <returns>Value of the <see cref="ItemTemplateProperty"/> property.</returns>
        public static DataTemplate GetItemTemplate(DependencyObject target)
        {
            return (DataTemplate)target.GetValue(ItemTemplateProperty);
        }

        /// <summary>
        /// Sets the <see cref="ItemTemplateProperty"/> property value.
        /// </summary>
        /// <param name="target">Target object of the attached property.</param>
        /// <param name="value">Value to be set on the <see cref="ItemTemplateProperty"/> property.</param>
        public static void SetItemTemplate(DependencyObject target, DataTemplate value)
        {
            target.SetValue(ItemTemplateProperty, value);
        }
        #endregion

 

Need the attached property to be able to specify the ItemTemplate using our TabControlRegionAdapter.

2. Attach the ItemTemplate to the each TabItem as it is generated in the TabControlRegionSyncBehavior

        protected virtual TabItem PrepareContainerForItem(object item, DependencyObject parent)
        {
            TabItem container = item as TabItem;
            if (container == null)
            {
                object dataContext = GetDataContext(item);
                container = new TabItem();
                container.Content = item;
                
                container.Style = TabControlRegionAdapter.GetItemContainerStyle(parent);
                // This will look for our new ItemTemplate and set it as the HeaderTemplate of the TabItem.
                DataTemplate itemTemplate = TabControlRegionAdapter.GetItemTemplate(parent);
                if (itemTemplate != null)
                {
                    container.HeaderTemplate = itemTemplate;
                }

                container.DataContext = dataContext; // To run with SL 2
                container.Header = dataContext; // To run with SL 3                  
                container.SetValue(IsGeneratedProperty, true);
            }

            return container;
        }

 

This gives you the flexibility to specify just a measly little DataTemplate instead of the entire ItemContainerStyle. As stated earlier, setting the Style on the TabItem will stomp all over any implicit or Theme based styling you are using in your solution.

3. Do a NULL check on the ItemContainerStyle before setting it to the Style of the new TabItem

protected virtual TabItem PrepareContainerForItem(object item, DependencyObject parent)
        {
            TabItem container = item as TabItem;
            if (container == null)
            {
                object dataContext = GetDataContext(item);
                container = new TabItem();
                container.Content = item;
                
                Style itemContainerStyle = TabControlRegionAdapter.GetItemContainerStyle(parent);
                if (itemContainerStyle != null)
                {
                    container.Style = itemContainerStyle;
                }

                DataTemplate itemTemplate = TabControlRegionAdapter.GetItemTemplate(parent);
                if (itemTemplate != null)
                {
                    container.HeaderTemplate = itemTemplate;
                }

                container.DataContext = dataContext; // To run with SL 2
                container.Header = dataContext; // To run with SL 3                  
                container.SetValue(IsGeneratedProperty, true);
            }

            return container;
        }

 

This will ensure that your Theme or Implicit Style is not obliterated by PRISM.

That’s it. Now you have a TabControl friendly version of PRISM V2.2. Enjoy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s