WPF Tab Control + Animations
I'm trying to style/animate a TabControl such that when a tab is selected, the old one fades out, and the new one fades/slides in. I have the tab control styled, to a point, but now I'm trying to work out how to animate the panel. Blend doesn't seem to be much help: there are references to styling "target-element", and references to "Panel" in the xaml, but neither of these seem to work when attempting to animate properties of this element.
I'm attempting to animate the Opacity property, and the transform property. Can anyone please help? Thanks in advance.
XAML attached:
<Style x:Key="HeaderTabControlItem" TargetType="{x:Type TabItem}">
<Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="6,1,6,1"/>
<Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<ControlTemplate.Resources>
<Storyboard x:Key="FadeTabIn">
<!-- This is where I am trying to put the animation code, the following (commented) line is an example. -->
<!--<DoubleAnimation By="0.6" From="0.5" To="1" Storyboard.TargetName="target-element" Storyboar开发者_高级运维d.TargetProperty="(UIElement.Opacity)" /> -->
</Storyboard>
</ControlTemplate.Resources>
<Grid x:Name="layoutRoot" SnapsToDevicePixels="true" Opacity="0.6" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.9" ScaleY="0.9"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<ContentPresenter x:Name="Content" ContentSource="Header" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="0,0,8,0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true"/>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Opacity" TargetName="layoutRoot" Value="1"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsMouseOver" Value="true"/>
</MultiTrigger.Conditions>
<Setter Property="Opacity" TargetName="layoutRoot" Value="0.4"/>
</MultiTrigger>
<Trigger Property="TabStripPlacement" Value="Bottom"/>
<Trigger Property="TabStripPlacement" Value="Left"/>
<Trigger Property="TabStripPlacement" Value="Right"/>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Top"/>
</MultiTrigger.Conditions>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Bottom"/>
</MultiTrigger.Conditions>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Left"/>
</MultiTrigger.Conditions>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Right"/>
</MultiTrigger.Conditions>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="layoutRoot" Value="0.25"/>
<Setter Property="RenderTransform" TargetName="layoutRoot">
<Setter.Value>
<TransformGroup>
<ScaleTransform ScaleX="0.8" ScaleY="0.8"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="Selector.IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard x:Name="FadeTabIn_BeginStoryboard" Storyboard="{StaticResource FadeTabIn}"/>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem here is that the tab control is not as versatile as it could be. Your best bet in this situation is to use custom controls for each tab item, and to create handoff storyboards for fading in/out.
My trick for this is to use visual states and behaviours, and custom templated radio buttons as switchers.
Create storyboards to animate the visibility from collapsed > visible, then fade up the opacity from 0 > 100.
You can see an example of this exact technique on my blog, under the Websites section of the homepage Silverlight xap on http://www.blackspike.com
Use SelectionChanging
and SelectionChanged
, and you can apply this to multiple tabcontrols. I am using Devexpress, but it should work with any WPF 4.0 tab control, since I am only using the SelectionChanging
and SelectionChanged
events.
VB:
Private Sub TabControl_SelectionChanging(sender As Object, e As DevExpress.Xpf.Core.TabControlSelectionChangingEventArgs) Handles tcMaterials.SelectionChanging, tcSymbols.SelectionChanging, myTabControl1.SelectionChanging
Try
If Not e.OldSelectedItem Is Nothing Then
Dim Duration = New TimeSpan(0, 0, 0, 0, 500)
Dim FromOpac As New DoubleAnimation(1, 0, Duration)
Storyboard.SetTarget(FromOpac, CType(CType(e.OldSelectedItem, DXTabItem).Content, Grid))
Storyboard.SetTargetProperty(FromOpac, New PropertyPath((CType(CType(e.OldSelectedItem, DXTabItem).Content, Grid).OpacityProperty)))
Dim s As New Storyboard()
s.AccelerationRatio = 0.2
s.DecelerationRatio = 0.8
s.Children.Add(FromOpac)
s.Begin()
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub TabControl_SelectionChanged(sender As Object, e As DevExpress.Xpf.Core.TabControlSelectionChangedEventArgs) Handles tcMaterials.SelectionChanged, tcSymbols.SelectionChanged, myTabControl1.SelectionChanged
Try
If Not e.OldSelectedItem Is Nothing Then
Dim Duration = New TimeSpan(0, 0, 0, 0, 500)
Dim ToOpac As New DoubleAnimation(0, 1, Duration)
Storyboard.SetTarget(ToOpac, CType(CType(e.NewSelectedItem, DXTabItem).Content, Grid))
Storyboard.SetTargetProperty(ToOpac, New PropertyPath((CType(CType(e.NewSelectedItem, DXTabItem).Content, Grid).OpacityProperty)))
Dim s As New Storyboard()
s.AccelerationRatio = 0.2
s.DecelerationRatio = 0.8
s.Children.Add(ToOpac)
s.Begin()
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
精彩评论