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!