在 TabItems 之间选择时如何实现正确的下划线动画?

How to achieve correct underline animation when selecting between TabItems?

我总共有四个选项卡项,带下划线的矩形具有不同的宽度,具体取决于 selected 四个选项卡项中的哪一个。但是我的数据触发器绑定不起作用。

预计:

假设我 select 第二个选项卡项,在我 select 第四个选项卡项之后,下划线矩形应该从第二个选项卡项移动到第四个选项卡项并正确输入退出动画以及正确的宽度。

我有下面的代码,但我不知道怎么做。

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>

        <TabControl Grid.Row="0"     x:Name="TestTabs">
            <TabItem Header="News"/>
            <TabItem Header="Files"/>
            <TabItem Header="Settings"/>
            <TabItem Header="Help"/>

        </TabControl>
        <DockPanel x:Name="rp" Grid.Row="0" LastChildFill="False" HorizontalAlignment="Stretch">
            <Canvas DockPanel.Dock="Left">
                <Rectangle x:Name="MySeparator3" Fill="Orange"  VerticalAlignment="Top" Width="40" Height="4" Margin="3,25,0,0"   SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.EdgeMode="Aliased" RenderOptions.BitmapScalingMode="HighQuality" >
                    <Rectangle.Style>
                        <Style TargetType="{x:Type Rectangle}">
                            <Setter Property="SnapsToDevicePixels" Value="True"/>
                            <Setter Property="RenderOptions.EdgeMode" Value="Aliased"/>
                            <Setter Property="Visibility" Value="Visible"/>
                            <Setter Property="IsEnabled" Value="True"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ElementName=TestTabs, Path=SelectedIndex}" Value="1">
                                    <Setter Property="SnapsToDevicePixels" Value="True"/>
                                    <Setter Property="RenderOptions.EdgeMode" Value="Aliased"/>
                                    <Setter Property="Visibility" Value="Visible" />
                                    <Setter Property="IsEnabled" Value="True" />
                                    <DataTrigger.EnterActions>
                                        <BeginStoryboard Name="MyBeginStoryboard11">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" From="0" To="40" Duration="0:0:0.2"></DoubleAnimation>
                                                <DoubleAnimation Storyboard.TargetProperty="Width"   From="40" To="35" Duration="0:0:0.2"></DoubleAnimation>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </DataTrigger.EnterActions>
                                    <DataTrigger.ExitActions>
                                        <BeginStoryboard Name="MyBeginStoryboard1">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" From="40" To="0" Duration="0:0:0.2"></DoubleAnimation>
                                                <DoubleAnimation Storyboard.TargetProperty="Width"   From="35" To="40" Duration="0:0:0.2"></DoubleAnimation>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </DataTrigger.ExitActions>
                                </DataTrigger>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition  Binding="{Binding ElementName=TestTabs, Path=SelectedIndex}" Value="2"/>
                                    </MultiDataTrigger.Conditions>
                                    <MultiDataTrigger.EnterActions>
                                        <BeginStoryboard Name="MyBeginStoryboard19">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" From="0" To="73" Duration="0:0:0.2"></DoubleAnimation>
                                                <DoubleAnimation Storyboard.TargetProperty="Width"   From="40" To="50" Duration="0:0:0.2"></DoubleAnimation>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </MultiDataTrigger.EnterActions>
                                    <MultiDataTrigger.ExitActions>
                                        <BeginStoryboard Name="MyBeginStoryboard5">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" From="73" To="0" Duration="0:0:0.2"></DoubleAnimation>
                                                <DoubleAnimation Storyboard.TargetProperty="Width"   From="50" To="40" Duration="0:0:0.2"></DoubleAnimation>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </MultiDataTrigger.ExitActions>
                                </MultiDataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Rectangle.Style>
                </Rectangle>
            </Canvas>
        </DockPanel>
    </Grid>

实际结果:

MainWindow.xaml:

 <Grid>
     <Grid.RowDefinitions>
         <RowDefinition Height="*"/>
         <RowDefinition Height="50"/>
     </Grid.RowDefinitions>
     <TabControl Grid.Row="0"   x:Name="TestTabs" Loaded="TestTabs_Loaded"  SelectionChanged="TestTabs_SelectionChanged">
         <TabItem Name="Tab1" Header="News"/>
         <TabItem Name="Tab2" Header="Files"/>
         <TabItem Name="Tab3" Header="Settings"/>
         <TabItem Name="Tab4" Header="Help"/>
     </TabControl>
     <DockPanel x:Name="rp" Grid.Row="0" LastChildFill="False" HorizontalAlignment="Stretch">
         <Canvas DockPanel.Dock="Left">
             <Rectangle x:Name="MySeparator3" Fill="Orange"  VerticalAlignment="Top"  Height="4" Margin="3,25,0,0"   Visibility="Visible"  IsEnabled="True"
                        SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.EdgeMode="Aliased" RenderOptions.BitmapScalingMode="HighQuality" >
             </Rectangle>
         </Canvas>
     </DockPanel>
     <TextBlock Grid.Row="1" Text="{Binding ElementName=Tab1,Path=ActualWidth}" Height="50" Width="100"/>
 </Grid>

MainWindow.xaml.cs:

    using System;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Media;
 using System.Windows.Media.Animation;
    
 namespace RectangleWidthAndSlide
 {
   public partial class MainWindow : Window
   {
     public MainWindow()
     {
       InitializeComponent();
     }
     public int Start{ get;set;}
     private void TestTabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
     {
         TabItem ti = ((sender as TabControl).SelectedItem as TabItem);
       double sz1 = ti.ActualWidth;
       MySeparator3.Width = sz1;
       MySeparator3.UpdateLayout();
       if (e.RemovedItems.Count > 0)
       {
         var oldTabItem = e.RemovedItems[0] as TabItem;
         DoubleAnimation translate_x = null;
         if (oldTabItem.Name == "Tab1")
         {
           switch (ti.Name)
           {
             case "Tab2":
               translate_x = new DoubleAnimation()
               {
                 From = 0,
                 To = 40,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab3":
               translate_x = new DoubleAnimation()
               {
                 From = 0,
                 To = 75,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab4":
               translate_x = new DoubleAnimation()
               {
                 From = 0,
                 To = 130,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
           }
           var translate_y = new DoubleAnimation()
           {
             From = 0,
             To = 0,
             Duration = TimeSpan.FromSeconds(1),
           };
           TranslateTransform translateTransform1 = new TranslateTransform();
           translateTransform1.BeginAnimation(TranslateTransform.XProperty, translate_x);
           translateTransform1.BeginAnimation(TranslateTransform.YProperty, translate_y);
           MySeparator3.RenderTransform = translateTransform1;
         }
         if (oldTabItem.Name == "Tab2")
         {
           switch (ti.Name)
           {
             case "Tab1":
               translate_x = new DoubleAnimation()
               {
                 From = 40,
                 To = 0,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab3":
               translate_x = new DoubleAnimation()
               {
                 From = 40,
                 To = 75,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab4":
               translate_x = new DoubleAnimation()
               {
                 From = 40,
                 To = 130,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
           }
           var translate_y = new DoubleAnimation()
           {
             From = 0,
             To = 0,
             Duration = TimeSpan.FromSeconds(1),
           };
           TranslateTransform translateTransform1 = new TranslateTransform();
           translateTransform1.BeginAnimation(TranslateTransform.XProperty, translate_x);
           translateTransform1.BeginAnimation(TranslateTransform.YProperty, translate_y);
           MySeparator3.RenderTransform = translateTransform1;
         }
         if (oldTabItem.Name == "Tab3")
         {
           switch (ti.Name)
           {
             case "Tab1":
               translate_x = new DoubleAnimation()
               {
                 From = 75,
                 To = 0,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab2":
               translate_x = new DoubleAnimation()
               {
                 From = 75,
                 To = 40,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab4":
               translate_x = new DoubleAnimation()
               {
                 From = 75,
                 To = 130,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
           }
           var translate_y = new DoubleAnimation()
           {
             From = 0,
             To = 0,
             Duration = TimeSpan.FromSeconds(1),
           };
           TranslateTransform translateTransform1 = new TranslateTransform();
           translateTransform1.BeginAnimation(TranslateTransform.XProperty, translate_x);
           translateTransform1.BeginAnimation(TranslateTransform.YProperty, translate_y);
           MySeparator3.RenderTransform = translateTransform1;
         }
         if(oldTabItem.Name == "Tab4")
         {
           switch (ti.Name)
           {
             case "Tab1":
               translate_x = new DoubleAnimation()
               {
                 From = 130,
                 To = 0,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab2":
               translate_x = new DoubleAnimation()
               {
                 From = 130,
                 To = 40,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
             case "Tab3":
               translate_x = new DoubleAnimation()
               {
                 From = 130,
                 To = 75,
                 Duration = TimeSpan.FromSeconds(0.2),
               };
               break;
           }
           var translate_y = new DoubleAnimation()
           {
             From = 0,
             To = 0,
             Duration = TimeSpan.FromSeconds(1),
           };
           TranslateTransform translateTransform1 = new TranslateTransform();
           translateTransform1.BeginAnimation(TranslateTransform.XProperty, translate_x);
           translateTransform1.BeginAnimation(TranslateTransform.YProperty, translate_y);
           MySeparator3.RenderTransform = translateTransform1;
         }
       }
     }
     private void TestTabs_Loaded(object sender, RoutedEventArgs e)
     {
       var tabControl = (TabControl)sender;
       tabControl.SelectedItem = Tab1;
       TabItem ti = (tabControl.SelectedItem as TabItem);
       double sz1 = ti.ActualWidth-5;
       MySeparator3.Width = sz1;
       MySeparator3.UpdateLayout();
     }
   }
 }

结果: