3

I am developing a 'tabbed' GUI for my application, using XAML to present the GUI to the user.

I am currently displaying a few tabs, with a different aspect of the application displayed on each one.

I have a couple of icons that display the 'connectivity status' of the application to a remote server (i.e. one image is displayed if the application is connect to the server, and another image is displayed if it's not connected). These images are currently displayed inside one of the tabbed displays, but I want to move them onto the 'tab' bar (on the far right hand side of the application window), so that they will always be visible, no matter what tab the user is currently viewing.

My XAML is currently structured like this:

<Grid>
    <TabControl ...>
        <TabItem>
            ...
        </TabItem>
        <TabItem ...>
            <StackPanel>
                <Grid>
                    ...
                    <Image ... />
                    <Image ... />
                </Grid>
            </StackPanel>
        </TabItem>
    </TabControl>
</Grid>

Basically, one of the images in the <Image> tags is displayed to indicate that the application is connected to the server, and the other image is displayed to indicate that the application is not connected to the server. They have both been placed in the same location inside the application, and there is a method that checks whether the application is connected to the server or not, and displays the appropriate image based on the value that the method returns.

What I want to do, is move these <Image> tags into the main <TabControl> tag, so that these images can be displayed on the 'tab menu', but on the far right hand side of the window (as the various tabs available to the user are displayed on the far left). This would then mean that those images are displayed no matter what tab the user is currently viewing.

Is there a way that I can do this? I have tried adding the <Image> tags directly inside the <TabControl> tags, but the images are not displayed when I run my application... Anyone have any suggestions for how I can achieve what I'm looking to do here?

Noble-Surfer
  • 3,052
  • 11
  • 73
  • 118

1 Answers1

2

To add imaginary TabBar, you should create new RowDefinition in Template of TabControl. Let me show an example:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="WpfApplication2.MainWindow"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
    <SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
    <Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
        <Setter Property="Padding" Value="2"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
        <Setter Property="BorderBrush" Value="{StaticResource TabItem.Selected.Border}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabControl}">
                    <Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition x:Name="ColumnDefinition0"/>
                            <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                            <RowDefinition x:Name="RowDefinition2" Height="0.1*"/>
                            <RowDefinition x:Name="RowDefinition1" Height="*"/>
                        </Grid.RowDefinitions>
                        <TabPanel x:Name="headerPanel" Background="Yellow" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
                        <StackPanel Grid.Row="1" Orientation="Horizontal" FlowDirection="RightToLeft">
                            <Image Source="/Images/1.png" />
                            <Image Source="/Images/2.png" />
                            <Image Source="/Images/3.png" />                                
                        </StackPanel>
                        <Border x:Name="contentPanel" BorderBrush="Green" BorderThickness="5" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="2" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
                            <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="TabStripPlacement" Value="Bottom">
                            <Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
                            <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                            <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                            <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
                            <Setter Property="Margin" TargetName="headerPanel" Value="2,0,2,2"/>
                        </Trigger>
                        <Trigger Property="TabStripPlacement" Value="Left">
                            <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                            <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                            <Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
                            <Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
                            <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
                            <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
                            <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                            <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                            <Setter Property="Margin" TargetName="headerPanel" Value="2,2,0,2"/>
                        </Trigger>
                        <Trigger Property="TabStripPlacement" Value="Right">
                            <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                            <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                            <Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
                            <Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
                            <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
                            <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
                            <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                            <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                            <Setter Property="Margin" TargetName="headerPanel" Value="0,2,2,2"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="FooTabControl" TargetType="{x:Type TabControl}">
        <!--This style is intended to be empty just for show that you can declare as many styles as you want-->
    </Style>
    <Style x:Key="FooButton"  TargetType="{x:Type Button}">
        <!--This style is intended to be empty just for show that you can declare as many styles as you want-->
    </Style>
</Window.Resources>
<Grid Name="grid">
    <TabControl Style="{DynamicResource TabControlStyle1}">
        <TabItem Header="1">1</TabItem>
        <TabItem Header="2">2</TabItem>
        <TabItem Header="3">3</TabItem>
    </TabControl>
</Grid>
</Window>
StepUp
  • 36,391
  • 15
  • 88
  • 148
  • Hey, thanks for your answer. The thing is, I don't want to display the image(s) just in a single `` `Header`, but want to display them in the top level ``, so that they are visible on the 'tab bar' no matter which tab the user is currently viewing. For example, if I have three tabs open in the application window, these will be displayed on the left hand side of the 'tab bar', and the user can select which one to view by clicking it, and then content of the page will then be updated depending on which tab is selected. – Noble-Surfer May 13 '16 at 14:22
  • What I want to do, is add these images to the right hand side of the 'tab bar', so that they are always visible, no matter what tab the user has currently selected, as they indicate the connectivity of the application as a whole, and are not just relevant to one particular aspect of the application. – Noble-Surfer May 13 '16 at 14:23
  • Hey, thanks for the update- that looks like it is what I want to do. However, I already have a `` tag in my XML, so when trying to add ``, I get a compile error that says: `The property 'Value' is set more than once.`, or if I add all of the code you've written, that displays one of the images I want, but then stops the rest of the content I had from being displayed, and I get an error in the Design view in VS which says "The element "{Button}" could not be displayed because of a problem with – Noble-Surfer May 13 '16 at 16:08
  • System.Windows.Controls.Button: 'TabControl' ControlTemplate TargetType does not match templated type 'Button'. – Noble-Surfer May 13 '16 at 16:09
  • Can I add two `ControlTemplate`s? If so, do I need to give them different names or something? Or, if not, can I add all of the controls you mentioned in the code in your post to the same `ControlTemplate` that I'm already using? – Noble-Surfer May 13 '16 at 16:10
  • @someone2088 I've uppdated my answer with full code to avoid any errors:). **You cannot set two ControlTemplate's in one Style, you should create new style for new controlTemplate.** to differentiate various `ControlTemplate's` just use `x:Key"` property. Do not forger mark as answer my reply if it helps to you you to simplify the future search by other people and to close this thread. – StepUp May 13 '16 at 19:33
  • Hey, thanks for your updated answer. I given it a try, however, I still get a compile error on the line ``, which says: `The attachable property 'Triggers' was not found in type 'ControlTemplate'`... any ideas why that is? – Noble-Surfer May 16 '16 at 08:24
  • @someone2088 I double checked the code and it perfectly works. Try to set your `Image` addresses. I am just copied this style to new `Window` your wishful `TabControl` is appeared with all your conditions. – StepUp May 16 '16 at 08:55
  • I tried just altering my XAML to reflect what you had done, but keeping the content that I wanted from what I already had... I'll give it a go now starting from scratch with your code, and just adding the parts of mine that I want... I'll let you know how I get on. – Noble-Surfer May 16 '16 at 09:09
  • Hey, thanks for your answer, and for explaining it all through. I've given it a go, starting with your code, and editing it slightly to include a few other elements I wanted in there. From the 'preview' panel in VS, it looks like that XAML markup will work (i.e. the images I've added to the `` are displayed in the preview panel), but I am getting a compile error in the `.xaml.cs` file (i.e. the code-behind file) for this markup... where I'm calling `image.Visibility = Visibility.Visible;`, which says: `The name 'image' does not exist in the current context`... – Noble-Surfer May 16 '16 at 13:17
  • Is there something I need to do to make the `image` visible in my `.cs` file? – Noble-Surfer May 16 '16 at 13:17
  • @someone2088 yeah, you can. Just read this http://stackoverflow.com/questions/820201/how-to-access-a-wpf-control-located-in-a-controltemplate – StepUp May 16 '16 at 14:05