TabControl as a region

Jul 2, 2008 at 7:17 AM
Have anyone tried to define a TabControl as a region in shell and add TabItems to the TabControl (region) as Composite WPF modules?
Jul 2, 2008 at 10:40 AM
I am interested too in this topic. I need to dynamic compose every tab of a ribbon-like tabcontrol, loading autonomous modules (each module is a tab).
Jul 2, 2008 at 2:17 PM

I have done it, but it took some spelunking in the stock trader RI to understand what they were doing.

First notice that the Stock Trader RI uses a TabControl as a region at the bottom of the shell.xaml

Take a look at the XAML in StockTraderRI/Resources/TabItemResource.xaml, this defines the template for the TabItems.

Notice the line in the template that sets the "Header" property in the template to 

 

{

 

Binding Content.DataContext.HeaderInfo, RelativeSource={RelativeSource Self}}

 

The header property is used by the TabControlItem as the text or visual in the tab. 

In the views put into the region ( StockTraderRI.Modules.Position.PositionSummary.PositionSummaryView.xaml ) they set their data context to the PresentationModel.

 

The Content.DataContext.HeaderInfo says, in english, to call the method HeaderInfo on the DataContext of the view used for the Tab to get the header.  In the presentation model ( PositionSummaryPresentationModel.cs ) it has a method called HeaderInfo that returns a string.  Because the model is set as the DataContext on the view, this method is called by the TabItemControl template via the binding shown above.

So all of that is a round about way of allowing each view that is loaded into the region to set the header for a tab.

I am not sure if this make sense to you, but all you have to do is to load a view into the TabControl region.  It goes in no problem.  The problem is the header.  You have to come up with a convention for your app that allows each view to specify the header.  What I described above is how they did it in the RI.  You dont have to do it that way, but you can.

Paul

Jul 2, 2008 at 2:47 PM


kiarz wrote:
Have anyone tried to define a TabControl as a region in shell and add TabItems to the TabControl (region) as Composite WPF modules?

One other thing that helped me a lot was to go through an example of how to style and template a tab control.  Once I had that down, then finding how they did it in the StockTraderRI was much easier.

Here is one that was easy to follow.

http://blog.paranoidferret.com/index.php/2008/01/18/the-wpf-tab-control-inside-and-out/

Jul 3, 2008 at 8:25 AM
Hi guys, I've done this but in a bit of a different way, basically what I've done is create my own document controller, the document controller basically requires that a view model be provided that implements a document contract which simply has a header and a view, both of which are FrameworkElement. This is dead simple to bind to within the UI as you can create DataTemplates for the manager.

Take a look at my samples here to see how I've done it, be sure to check out the source from svn as there's a bit more in it than the last build I made. Have a look at LateNight.Infrastructure/DocumentModel for my implementation.

I'm putting together an example that works with a customer, and has multiple tab detail items for the customer that child modules can register into, this is a similar use-case to the SCSF bank branch RI with the map etc. Currently I've done this using a Progress App-Server with their sample (sports2000) DB and I can't make it part of the source, will be converting this to a SQL server equivelant so I can put it into the app :)

I hope this helps you out.
-Brett
Jul 3, 2008 at 11:12 AM



 
And once y'all have all of that working, go grab the dll from the Transitionals project ( www.codeplex.com/Transitionals ) and then read what this guy did with the TabControl ( http://www.hardcodet.net/2008/05/wpf-tab-effects-with-transitionals ).  You end up with a tab control, that doesn't have to look anything like a tab control, filled from dynamically loaded Prism Modules, who's content does a 3d rotational transition to become visible.

What a country, what a product.  Anybody who says vista sucks, has no clue of the potential of wpf.  This stuff is staggering and I am in awe of the thought that went into it.

Paul
Jul 3, 2008 at 9:37 PM
Nice, I'll try putting the transitionals concept into my samples. Some comments on your statement though. What a country? I'm from Australia :P And I've upgraded to XP, I couldn't stand vista, especially the windows file explorer, that's no longer keyboard friendly *gruff*

-Brett.

pmont wrote:

And once y'all have all of that working, go grab the dll from the Transitionals project ( www.codeplex.com/Transitionals ) and then read what this guy did with the TabControl ( http://www.hardcodet.net/2008/05/wpf-tab-effects-with-transitionals ).  You end up with a tab control, that doesn't have to look anything like a tab control, filled from dynamically loaded Prism Modules, who's content does a 3d rotational transition to become visible.

What a country, what a product.  Anybody who says vista sucks, has no clue of the potential of wpf.  This stuff is staggering and I am in awe of the thought that went into it.

Paul



Jul 4, 2008 at 12:31 PM


brettryan wrote:
Nice, I'll try putting the transitionals concept into my samples. Some comments on your statement though. What a country? I'm from Australia :P And I've upgraded to XP, I couldn't stand vista, especially the windows file explorer, that's no longer keyboard friendly *gruff*

-Brett.

pmont wrote:

And once y'all have all of that working, go grab the dll from the Transitionals project ( www.codeplex.com/Transitionals ) and then read what this guy did with the TabControl ( http://www.hardcodet.net/2008/05/wpf-tab-effects-with-transitionals ).  You end up with a tab control, that doesn't have to look anything like a tab control, filled from dynamically loaded Prism Modules, who's content does a 3d rotational transition to become visible.

What a country, what a product.  Anybody who says vista sucks, has no clue of the potential of wpf.  This stuff is staggering and I am in awe of the thought that went into it.

Paul







>> What a Country

http://en.wikipedia.org/wiki/Yakov_Smirnoff  A common expression by a comedian that was popular in America for a while.

>> What a product - Vista

It has worked wonderfully for me.  I was more commenting on the work that has been done on WPF, and WCF and WF, and all of the "W"'s by MS.  I am staggered by the amount of thought and attention to detail that I constantly see in WPF.

Transitionals is an easy way to get that "WOW" factor that is sometimes needed in apps that you demo to upper managment.  The fact that it easily plugs into Prism is very very nice.

Paul  ( The next couple of days are a holiday for me )
Jul 7, 2008 at 11:52 PM

Does anyone have a good model for create closeable tab items using regions?

I'm new to WPF and Prism so correct me if I'm missing something.

The example above for adding metadata such as a tabItem header is simple enough,
but what if I want a view to be closed when a button on the tab item header is clicked?

The CAB was easy because the workspace knew about the items it hosted, but Prism workspaces don't, they're managed, and the control (or Shell) can't get its IRegion.
Even the collection that is bound to the TabControl doesn't give me access to modify its collection.

How do I wire up this logic with only defining the close button in XAML and keep my code clean?

Or is it better for me to use the LateNight strategy and not use regions?

Jul 18, 2008 at 9:52 AM

There's a couple of things that you can do to get this scenario working:

  1. Modify the headertemplate of a tabitem to show a close button.
  2. Hook up the click event and retrieve the instance of the tabcontrol on which the tabitem that is the parent of the button is hosted.
  3. Retrieve the region name by invoking RegionManager.GetRegionName(tabControl)
  4. Remove the view from the found region

This should do it.

Sep 4, 2008 at 8:41 PM
I'm dissecting the StockTrader RI to figure out how to use tab controls and loading views into tabs. I'm looking for a simpler example of how to load a view into a tab item and a) add it if it's not there or b) activate it if it already is.

I can spend the night building my own spike and trying to figure out how to do this with the RI but there must be an easier way? Creating a TabControl with a region name added to it just creates a new tab anytime your module is loaded (and there's the question of how to set the header). Is there a simple example out there to do this? Any links here talk about it, but I'm missing something in what they actually do.
Sep 5, 2008 at 1:30 AM
Edited Sep 5, 2008 at 1:32 AM
Hi bsimser, earlier in this post I mentioned a way of achieving this through my samples project found here. While this doesn't use a region manager it does show of a way to create modular tab components with ease. Basically it works as a document model where each document is rendered as a tab item, the header is then taken from the document header.$0$0$0$0I have been very busy on other projects and haven't had a chance to get back to the samples to create more examples of how to do things with WPF and CompositeUI. I appologize for this and hope to do more on this soon.$0$0$0$0$0-Brett$0$0$0$0
Oct 23, 2009 at 4:25 PM

I have followed this approach to the letter and although it results in TabItems being added for each view I inject into the region, I don't get any content on my TabItems. My (very simple) view simply has a TextBox and an Image on it, but these don't show up in the Tab Control.

Any ideas?

Region Definition:

<Controls:TabControl 
    Name="MainRegion" 
    cal:RegionManager.RegionName="{x:Static Infrastructure:RegionNames.TabRegion}"
    ItemContainerStyle="{StaticResource ShellTabItemStyle}" />

Style Definition:
<Style x:Key="ShellTabItemStyle" TargetType="{x:Type TabItem}">
    <Setter Property="Header" Value="{Binding Content.DataContext.HeaderInfo, RelativeSource={RelativeSource Self}}" />
</Style>



Feb 21, 2011 at 10:39 PM

Just to make it clear, here is the code I used to get this to work (taken from the Prism StockTrader RI and adapted). The key is to have the Setter for the Header property in the TabItem Style have a value bound to the HeaderInfo property of the Content's DataContext. (In my code, the View's DataContext is set to the ViewModel, which has a HeaderInfo property.)

XAML:

 

<Window x:Class="ModularityWithMef.Desktop.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:Regions="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism" x:Name="Window">
    <Window.Resources>
        <!-- TabItem -->
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="Header" Value="{Binding Content.DataContext.HeaderInfo, RelativeSource={RelativeSource Self}}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid>
                            <Border BorderThickness="1" BorderBrush="Gray" Padding="2">
                                <ContentPresenter x:Name="Content" ContentSource="Header" RecognizesAccessKey="True"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter TargetName="Content" Property="Opacity" Value="1"/>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="false">
                                <Setter TargetName="Content" Property="Opacity" Value="0.5"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <TabControl Regions:RegionManager.RegionName="ContentRegion">
            <TabItem Header="HeaderInXaml" />
        </TabControl>
    </Grid>
</Window>

 

My module (that goes in as a TabItem):

 

namespace ModuleB
{
    public partial class ModuleBView
    {
        public ModuleBView()
        {
            InitializeComponent();
            DataContext = new ModuleBViewModel();
        }
    }

    public class ModuleBViewModel
    {
        private const string _title = "Module B";
        public string HeaderInfo { get { return _title; } }
    }

    [ModuleExport(typeof(ModuleB), InitializationMode = InitializationMode.WhenAvailable)]
    public class ModuleB : IModule
    {
        [Import(AllowRecomposition = false)]
        private IRegionManager _regionManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="ModuleB"/> class.
        /// </summary>
        public ModuleB()
        {
        }

        /// <summary>
        /// Notifies the module that it has be initialized.
        /// </summary>
        public void Initialize()
        {
            _regionManager.RegisterViewWithRegion("ContentRegion", () => new ModuleBView());
        }
    }
}

 

 

Jun 16, 2011 at 9:24 AM

Hi pckujawa,

How about your shell project? did you code anything there? I'd do exactly the same thing as yours but could not make it work (The Tab's header is Empty).And I found that the datacontext of the Tabcontrol in the shell is null, is there anything I missed? How should I bind the Tabcontrol's datacontext to ModuleB? 

 

Thank you.