tags:

views:

384

answers:

4

I am having difficulty trying to get a very simple scenario working with PRISM 2.0 for WPF. I want the main workarea of my application to be a TabControl. Each time I add a view, I want it to appear as a TabItem on the TabControl.

Sounds easy right?

My region, which is in my Shell.XAML looks like this:

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

The style: "ShellTabItemStyle" looks like this:

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

This should set the Header of the TabItem to the HeaderInfo property on the DataContext of the view. (I got this idea from this article) The DataContext of my View is a very simple Presenter which has a HeaderInfo property on it:

public string HeaderInfo = "The Header Text";

My view is a simple WPF usercontrol and looks like this:

  <StackPanel>
    <TextBox Text="Hello World" Name="MyTextBox"></TextBox>
    <Image Source="..SomeImage.PNG" Name="MyImage"></Image>
  </StackPanel>

So far, so good. If I add the view to the region I get a tab control and I get a tab with the text set to "The Header Text". My problem is that there is absolutely no content appearing on the tab. My view contains a simple Image and a TextBox, but neither of them show up in the TabItem. If I break out Snoop and look around, there isn't an image in sight.

What am I missing here - is there an easier way?

A: 

You might have a look at the source code of this sample project:

Test Suite reference sample for PRISM 2

jbe
+2  A: 

If you are using RegionManager, you need to Activate your view. There's likely some piece of code where you are adding the view to the region, you just additionally need to tell that region to activate it.

public void AddViewToRegion(IRegion region, object view)
{
     region.Add(view);
     region.Activate(view);
}

It seems silly, but you get the behavior you are seeing if you don't do this. I found this kinda frustrating, but it was easy enough to fix. The behavior is even stranger when you add multiple tabs if you don't at least Activate the first view you add.

My understanding is that if you don't do this, the view never becomes part of the visual tree (this is a side-effect of the fact that the TabControl deactivates (removes from the visual tree) when a tab isn't "in front". This is good for certain operations, but makes things like this be a little wonky.

Anderson Imes
I am activating the view - still no usercontrol showing up in the UI
Steve
A: 

I was unable to get any of the suggested answers to work. Extensive googling didn't help either. I gave the problem some thought over the weekend and more I thought about it, the more it occured to me that there is a bit of a code smell about this approach. You inject a view into your Tab Region... some magic stuff happens and a tab gets added... you have to add some imcomprehensible dynamic binding to some XAML styling stored in a file somewhere and this may or may not set your header text. If any one single element of this is just a little bit wrong you won't get an error but it just won't work.

In my view this is both brittle (i.e. very easy to break) and pretty inpenetrable unless you have a deep understanding PRISM, the model, and of XAML. Fortunately there is a much nicer and simpler way to do this:

Simply create a view called TabRegionView which contains only a blank TabControl. You probably want to add this to your Shell.xaml. Create an Event called InjectTabView which has a Payload of type UserControl and subscribe to this event in your TabRegionView control. When the event fires in TabRegionView, you create the TabItem manually and add the view to the TabItem like so:

public void TabAdded(UserControl view)
{
    var item = new TabItem();
    item.Content = view;
    item.IsSelected = true;
    item.Header = "Header Text";
    mainTab.Items.Add(item);
}

When you want to display a view as a new tab, your code looks something like this:

    var view = new View(params);
    _eventAggregator.GetEvent<InjectTabViewEvent>()
        .Publish(view);

This will be picked up by TabRegionView and the view will be added as a new tab. You could easily wrap the View in harness of some type that contains header text, an image and bool to indicate whether or not the tab should be autoselected.

IMHO this technique has the dual advantages of giving you direct control of what is going on AND it is much easier to follow.

I'd be very interested to get an opinion on this from any PRISM officianados.

Steve
This is fine. You are still mostly control agnostic here. I have not found this to be brittle at all, but I'm using view injection rather than discovery. I've got the exact setup it sounds like you have. Maybe you could post a complete codesample?
Anderson Imes
A: 

Some random thoughts:

  • try to remove the style from TabControl
  • check visual tree with help of Snoop tool. You should see your TabItem with view's UserControl under the TabControl. Next you can check what's wrong with that UserControl and its children (your view's content). They are probably hidden for some reason.
  • other thing to think over - RegionAdapter. RegionAdapters are responsible for adapting regions' views to host UIControl.
Shrike