Using the TabControl on Windows Phone 7
Join the DZone community and get the full member experience.
Join For FreeBy default, the Windows Phone 7 SDK doesn't have a TabControl. It is a quite useful component already available in Silverlight and although it doesn't quite follow the Metro style, it can have its use. For example, some Android applications have a similar UI:
Adding Relevant Features
It is so very important to remember that relevant features sometimes need to be added to a phone to make it as fully operational as we would all like for it to be. Sadly, there are some people who don’t realize that they need to put this kind of time and effort in, and they may end up using a phone that doesn’t have all of the functionality that they deserve it.
Those who find themselves in this boat need to know what they can do to add back some of the functionality that they have lost to it. It is best to try to put in features such as the TabControl and other codes into one’s phone when possible to make it work in all of the best ways possible. Those who do so are giving themselves a leg up that they might not otherwise have had if they didn’t take the time to add in these relevant and cool features right from the start.
In order to use this control, a complete rewrite is not necessary. All that needs to be done is add a reference to System.Windows.Controls - a standard Silverlight library that is located at:
C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client
If the development environment is set up on a 32-bit system, the x86 part in the location should be excluded.
The next step is adding the assembly reference as a namespace pointer in the work XAML:
xmlns:cc="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
To add the control to the workspace:
<cc:TabControl> <cc:TabItem Height="80" Width="80" Header="Tab 1" Foreground="Black"></cc:TabItem> <cc:TabItem Height="80" Width="80" Header="Tab 2" Foreground="Black"></cc:TabItem> <cc:TabItem Height="80" Width="80" Header="Tab 3" Foreground="Black"></cc:TabItem> <cc:TabItem Height="80" Width="80" Header="Tab 4" Foreground="Black"></cc:TabItem> <cc:TabItem Height="80" Width="80" Header="Tab 5" Foreground="Black"></cc:TabItem> </cc:TabControl>
What I get at this point is not exactly the type of UI style I want to see on my Windows Phone:
I worked a little bit with Blend and got it to look just like any other Metro-compatible control. The style is shown at the bottom of this article - it can be included in the Resources section of the app or page and then bound to as a StaticResource. After the redesign, I got this appearance:
Much better! What I really like about the Silverlight TabControl is the fact that I can position the tab headers wherever I want by simply changing the TabStripPlacement property - it can be Top (default), Bottom, Left and Right. Here is how it looks like with custom placement:
The contents of each TabItem should be placed inside a Canvas:
<cc:TabItem Style="{StaticResource TabItemStyle1}" Height="80" Width="80" Header="Tab 1" Foreground="Black"> <Canvas> <StackPanel> <Button Height="100" Width="100" Content="Test"></Button> <TextBlock Text="This is a test"></TextBlock> </StackPanel> </Canvas> </cc:TabItem>
With the help of a short DataTemplate I can set the HeaderTemplate to show an icon along with the text:
<DataTemplate x:Key="Header"> <StackPanel> <Image Height="32" Width="32" Source="/AppIcon2.png"></Image> <TextBlock>Sample</TextBlock> </StackPanel> </DataTemplate>
Here is the basic Metro style that should be applied to the TabControl to be more WP7-like:
<Style x:Key="TabItemStyle1" TargetType="cc:TabItem"> <Setter Property="IsTabStop" Value="False"/> <Setter Property="Background" Value="#FF1F3B53"/> <Setter Property="BorderBrush" Value="#FFA3AEB9"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Padding" Value="6,2,6,2"/> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <Setter Property="MinWidth" Value="5"/> <Setter Property="MinHeight" Value="5"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="cc:TabItem"> <Grid x:Name="Root"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="0"/> <VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/> </VisualStateGroup.Transitions> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="FocusVisualTop"> <SplineDoubleKeyFrame KeyTime="0" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="FocusVisualBottom"> <SplineDoubleKeyFrame KeyTime="0" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="FocusVisualLeft"> <SplineDoubleKeyFrame KeyTime="0" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="FocusVisualRight"> <SplineDoubleKeyFrame KeyTime="0" Value="0"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualTopSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualTopUnSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualBottomSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualBottomUnSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualLeftSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualLeftUnSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualRightSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualRightUnSelected"> <SplineDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="SelectionStates"> <VisualState x:Name="Unselected"/> <VisualState x:Name="Selected"/> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualTop"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualBottom"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualLeft"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualRight"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Unfocused"> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid x:Name="TemplateTopSelected" Visibility="Collapsed" Canvas.ZIndex="1"> <Border BorderBrush="White" BorderThickness="1,1,1,0" Background="White" CornerRadius="3,3,0,0" Margin="-2,-2,-2,0"> <Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1,1,0,0"> <Border.Background> <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0"> <GradientStop Color="#FFFFFFFF" Offset="0"/> <GradientStop Color="#F9FFFFFF" Offset="0.375"/> <GradientStop Color="#E5FFFFFF" Offset="0.625"/> <GradientStop Color="#C6FFFFFF" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid> <Rectangle Fill="Black" Margin="0,0,0,-2"/> <ContentControl x:Name="HeaderTopSelected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="FocusVisualTop" BorderBrush="White" BorderThickness="1,1,1,0" CornerRadius="3,3,0,0" IsHitTestVisible="false" Margin="-2,-2,-2,0" Visibility="Collapsed"/> <Border x:Name="DisabledVisualTopSelected" Background="#8CFFFFFF" CornerRadius="3,3,0,0" IsHitTestVisible="false" Margin="-2,-2,-2,0" Opacity="0"/> </Grid> <Grid x:Name="TemplateTopUnselected" Visibility="Collapsed"> <Border x:Name="BorderTop" BorderBrush="White" BorderThickness="1" Background="White" CornerRadius="3,3,0,0"> <Border x:Name="GradientTop" BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1,1,0,0" Background="#FF272727"> <Grid> <ContentControl x:Name="HeaderTopUnselected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="DisabledVisualTopUnSelected" Background="#8CFFFFFF" CornerRadius="3,3,0,0" IsHitTestVisible="false" Opacity="0"/> </Grid> <Grid x:Name="TemplateBottomSelected" Visibility="Collapsed" Canvas.ZIndex="1"> <Border BorderBrush="White" BorderThickness="1,0,1,1" Background="White" CornerRadius="0,0,3,3" Margin="-2,0,-2,-2"> <Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="0,0,1,1"> <Border.Background> <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0"> <GradientStop Color="#FFFFFFFF" Offset="0"/> <GradientStop Color="#F9FFFFFF" Offset="0.375"/> <GradientStop Color="#E5FFFFFF" Offset="0.625"/> <GradientStop Color="#C6FFFFFF" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid> <Rectangle Fill="Black" Margin="0,-2,0,0"/> <ContentControl x:Name="HeaderBottomSelected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Background="Black"/> </Grid> </Border> </Border> <Border x:Name="FocusVisualBottom" BorderBrush="White" BorderThickness="1,0,1,1" CornerRadius="0,0,3,3" IsHitTestVisible="false" Margin="-2,0,-2,-2" Visibility="Collapsed"/> <Border x:Name="DisabledVisualBottomSelected" Background="#8CFFFFFF" CornerRadius="0,0,3,3" IsHitTestVisible="false" Margin="-2,0,-2,-2" Opacity="0"/> </Grid> <Grid x:Name="TemplateBottomUnselected" Visibility="Collapsed"> <Border x:Name="BorderBottom" BorderBrush="White" BorderThickness="1" Background="White" CornerRadius="0,0,3,3"> <Border x:Name="GradientBottom" BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="0,0,1,1" Background="#FF272727"> <Grid> <ContentControl x:Name="HeaderBottomUnselected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="DisabledVisualBottomUnSelected" Background="#8CFFFFFF" CornerRadius="0,0,3,3" IsHitTestVisible="false" Opacity="0"/> </Grid> <Grid x:Name="TemplateLeftSelected" Visibility="Collapsed" Canvas.ZIndex="1"> <Border BorderBrush="White" BorderThickness="1,1,0,1" Background="White" CornerRadius="3,0,0,3" Margin="-2,-2,0,-2"> <Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1,0,0,1"> <Border.Background> <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0"> <GradientStop Color="#FFFFFFFF" Offset="0"/> <GradientStop Color="#F9FFFFFF" Offset="0.375"/> <GradientStop Color="#E5FFFFFF" Offset="0.625"/> <GradientStop Color="#C6FFFFFF" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid> <Rectangle Fill="Black" Margin="0,0,-2,0"/> <ContentControl x:Name="HeaderLeftSelected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="FocusVisualLeft" BorderBrush="White" BorderThickness="1,1,0,1" CornerRadius="3,0,0,3" IsHitTestVisible="false" Margin="-2,-2,0,-2" Visibility="Collapsed"/> <Border x:Name="DisabledVisualLeftSelected" Background="#8CFFFFFF" CornerRadius="3,0,0,3" IsHitTestVisible="false" Margin="-2,-2,0,-2" Opacity="0"/> </Grid> <Grid x:Name="TemplateLeftUnselected" Visibility="Collapsed"> <Border x:Name="BorderLeft" BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" Background="White" CornerRadius="3,0,0,3"> <Border x:Name="GradientLeft" BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1,0,0,1" Background="#FF272727"> <Grid> <ContentControl x:Name="HeaderLeftUnselected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="DisabledVisualLeftUnSelected" Background="#8CFFFFFF" CornerRadius="3,0,0,3" IsHitTestVisible="false" Opacity="0"/> </Grid> <Grid x:Name="TemplateRightSelected" Visibility="Collapsed" Canvas.ZIndex="1"> <Border BorderBrush="White" BorderThickness="0,1,1,1" Background="White" CornerRadius="0,3,3,0" Margin="0,-2,-2,-2"> <Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="0,1,1,0"> <Border.Background> <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0"> <GradientStop Color="#FFFFFFFF" Offset="0"/> <GradientStop Color="#F9FFFFFF" Offset="0.375"/> <GradientStop Color="#E5FFFFFF" Offset="0.625"/> <GradientStop Color="#C6FFFFFF" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid> <Rectangle Fill="Black" Margin="-2,0,0,0"/> <ContentControl x:Name="HeaderRightSelected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="FocusVisualRight" BorderBrush="White" BorderThickness="0,1,1,1" CornerRadius="0,3,3,0" IsHitTestVisible="false" Margin="0,-2,-2,-2" Visibility="Collapsed"/> <Border x:Name="DisabledVisualRightSelected" Background="#8CFFFFFF" CornerRadius="0,3,3,0" IsHitTestVisible="false" Margin="0,-2,-2,-2" Opacity="0"/> </Grid> <Grid x:Name="TemplateRightUnselected" Visibility="Collapsed"> <Border x:Name="BorderRight" BorderBrush="White" BorderThickness="1" Background="White" CornerRadius="0,3,3,0"> <Border x:Name="GradientRight" BorderThickness="1" CornerRadius="0,1,1,0" Background="#FF272727"> <Grid> <ContentControl x:Name="HeaderRightUnselected" Cursor="{TemplateBinding Cursor}" Foreground="White" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/> </Grid> </Border> </Border> <Border x:Name="DisabledVisualRightUnSelected" Background="#8CFFFFFF" CornerRadius="0,3,3,0" IsHitTestVisible="false" Opacity="0"/> </Grid> <Border x:Name="FocusVisualElement" BorderBrush="White" BorderThickness="1" CornerRadius="3,3,0,0" IsHitTestVisible="false" Margin="-1" Visibility="Collapsed"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
Opinions expressed by DZone contributors are their own.
Comments