I have a TabControl
where each TabItem
has a separate control as its Content
element. Now, I can easily execute a storyboard when switching to a tab by using a UserControl.Loaded
EventTrigger. However, I also want to run an exit animation when switching from one tab to another (i.e. allow the old Content control to animate away, followed by the new Content control's entrance animation).
Is it possible to do this with standard WPF constructs?
If not, how would I go about developing a custom solution that handles this?
Edit:
I went ahead and made a modified TabControl that extends the base TabControl and overrode its OnSelectionChanged
method as follows:
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 1 && e.RemovedItems.Count == 1)
{
var oldTab = e.RemovedItems[0] as TabItem;
if (oldTab != null)
{
var exitStoryboard = /** code to find the storyboard **/
if (exitStoryboard != null)
{
exitStoryboard.Completed = (_, __) => base.OnSelectionChanged(e);
exitStoryboard.Begin();
return;
}
}
}
base.OnSelectionChanged(e);
}
This works, except when I click between the tabs too quickly in which case the base.OnSelectionChanged never gets called, presumably because the storyboard is not active any more. Tips?
Here's a solution for 2 tabs, the general idea is to pop up an image of the last tab after the selection changes, and then fade the current tab in.
With a little effort you could probably genericize it for any number of tabs by tracking the last tab for the VisualBrush in a property instead of the hardcoded "other" tab used here.
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabControl>
<TabItem x:Name="tab1" Header="Tab 1">
<Border Background="Transparent">
<Grid>
<TextBlock FontSize="40" Foreground="Red" Text="Tab 1 Contents">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0.0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation
Duration="0:0:0.25"
From="1"
Storyboard.TargetName="tab2Shadow"
Storyboard.TargetProperty="Opacity"
To="0"/>
<DoubleAnimation
BeginTime="0:0:0.25"
Duration="0:0:0.25"
From="0"
Storyboard.TargetProperty="Opacity"
To="1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<Rectangle x:Name="tab2Shadow">
<Rectangle.Fill>
<VisualBrush
AlignmentX="Left"
AlignmentY="Top"
AutoLayoutContent="False"
Stretch="None"
Visual="{Binding ElementName=tab2, Path=Content}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Border>
</TabItem>
<TabItem x:Name="tab2" Header="Tab 2">
<Border Background="Transparent">
<Grid>
<TextBlock FontSize="40" Foreground="Red" Text="Tab 2 Contents">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0.0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation
Duration="0:0:0.25"
From="1"
Storyboard.TargetName="tab1Shadow"
Storyboard.TargetProperty="Opacity"
To="0"/>
<DoubleAnimation
BeginTime="0:0:0.25"
Duration="0:0:0.25"
From="0"
Storyboard.TargetProperty="Opacity"
To="1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<Rectangle x:Name="tab1Shadow">
<Rectangle.Fill>
<VisualBrush
AlignmentX="Left"
AlignmentY="Top"
AutoLayoutContent="False"
Stretch="None"
Visual="{Binding ElementName=tab1, Path=Content}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Border>
</TabItem>
</TabControl>
</Grid>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With