如何在动画期间将FrameworkElement保留在中间?

时间:2016-02-22 15:21:17

标签: wpf

我尝试制作一个位于窗口顶部中心的工具栏。

工具栏的宽度可能会在运行时更改。我希望借助VisualStates(这对我来说非常实用)和动画(使用关键帧)来触发宽度。

为了尽可能地简化问题,我将一个DockPanel放在一个窗口里面:

  1. 包含两个按钮的StackPanel(从一个视觉状态切换到另一个视觉状态)。
  2. 一个Button,将由添加到其ControlTemplate的两个VisualStates动画。
  3. 这是此窗口的屏幕截图Screenshot of the Window

    Xaml代码:

    <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:is="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" x:Class="DockPanelIssue.MainWindow"
        Background="LightYellow"
        Title="MainWindow" Height="200" Width="400">
    <DockPanel Background="Blue" HorizontalAlignment="Center" VerticalAlignment="Top">
        <StackPanel Margin="5" DockPanel.Dock="Bottom" Background="Orange" Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Margin="5" Click="Show_Click" Content="Show"/>
            <Button Margin="5" Click="Hide_Click" Content="Hide"/>
        </StackPanel>
        <Button Margin="5" x:Name="theButton" Background="Yellow" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button.Template>
                <ControlTemplate TargetType="{x:Type Button}">
                    <ContentControl>
                        <VisualStateManager.CustomVisualStateManager>
                            <is:ExtendedVisualStateManager />
                        </VisualStateManager.CustomVisualStateManager>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup is:ExtendedVisualStateManager.UseFluidLayout="True">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:3"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="StateHide">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="Chrome">
                                            <DoubleKeyFrameCollection>
                                                <LinearDoubleKeyFrame KeyTime="0%" Value="200"/>
                                                <LinearDoubleKeyFrame KeyTime="50%" Value="150"/>
                                                <LinearDoubleKeyFrame KeyTime="100%" Value="100"/>
                                            </DoubleKeyFrameCollection>
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="StateShow">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="Chrome">
                                            <DoubleKeyFrameCollection>
                                                <LinearDoubleKeyFrame KeyTime="0%" Value="100"/>
                                                <LinearDoubleKeyFrame KeyTime="50%" Value="150"/>
                                                <LinearDoubleKeyFrame KeyTime="100%" Value="200"/>
                                            </DoubleKeyFrameCollection>
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </ContentControl>
                </ControlTemplate>
            </Button.Template>
            Animated Button
        </Button>
    </DockPanel>
    

    以及触发VisualStates的代码:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void Hide_Click(object sender, RoutedEventArgs e)
        {
            ExtendedVisualStateManager.GoToState(theButton, "StateHide", true);
        }
    
        private void Show_Click(object sender, RoutedEventArgs e)
        {
            ExtendedVisualStateManager.GoToState(theButton, "StateShow", true);
        }
    }
    

    我们所期待的是AnimatedButton(黄色的)增加了他的宽度超过3秒,(并保持在中间!)。但结果是:

    1. 实际上,宽度很小,我们点击隐藏按钮。
    2. 立即将动画按钮移到左侧。
    3. 动画按钮仍在左侧,宽度正在增长。
    4. 在动画结束之前,动画按钮仍位于左侧。
    5. 动画完成后,动画按钮现在更高,它又回到中间(P!)
    6. 开始和结束是我们想要的,但过渡(2,3,4)是不正确的。

      这是一张带有步骤1到5截图的图片,以及说明我们想要的图片:

      Screenshots of the Issue and Drawings of what we expect

      如何实现这一目标?

      如果我犯错误,请告诉我。

      他们是其他一些我不太了解的观点:

      1. 为什么当我点击隐藏时,按钮正在增长(我预期它会缩小)
      2. 为什么两个动画中的一个没有播放过渡。
      3. 为什么Blue DockPanel在动画期间占用了这么多的宽度,因此减少了高度(似乎在计算动画期间橙色stackPanel在右边停靠而不是底部)?

0 个答案:

没有答案