为什么WPF中的TextBox.Text不能进行动画处理?

11

好的,我遇到了一件真的让我措手不及的事情。

我正在帮助一位开发者解决几个无关的问题,在他的项目中,他将一些文本动画化到了 TextBlock 中。于是,我回到我的桌子上重新创建了这个项目(为了回答他的问题),但我不小心使用了 TextBox 而不是 TextBlock。我的文本根本没有动画效果!(我真是太没用了!)

最终,我发现他的 xaml 使用的是 TextBlock,而我的使用的是 TextBox。有趣的是,当我使用 TextBox 时,Blend 没有创建关键帧。因此,我在 Blend 中使用 TextBlock 成功让它工作,然后手动修改了 xaml,将 TextBlock 转换为 TextBox。当我运行项目时,出现了以下错误:

InvalidOperationException: '(0)' Storyboard.TargetProperty path contains nonanimatable property 'Text'.

好吧,看来 Blend 足够聪明,知道这一点...并且不会在动画中生成关键帧(它只会直接修改 TextBox 上的值)。+1 给 Blend。

因此,问题变成了:为什么不能对 TextBox.Text 进行动画处理?通常的答案是,您要动画处理的特定属性不是一个 DependencyProperty。但这不是事实,TextBox.Text DependencyProperty。

所以,现在我感到困惑了!为什么不能对 TextBox.Text 进行动画处理呢?


让我用一些 xaml 来说明问题。以下 xaml 可以工作...但使用的是 TextBlock(s)。

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="TextBoxTextQuestion.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640"
    Height="480"
>
    <Window.Resources>
        <Storyboard x:Key="animateTextStoryboard">
            <StringAnimationUsingKeyFrames Storyboard.TargetProperty="(TextBlock.Text)" Storyboard.TargetName="textControl">
                <DiscreteStringKeyFrame KeyTime="0:0:1" Value="Goodbye"/>
            </StringAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource animateTextStoryboard}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid x:Name="LayoutRoot">
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock x:Name="textControl" Text="Hello" FontFamily="Calibri" FontSize="32"/>
            <TextBlock Text="World!" Margin="0,25,0,0" FontFamily="Calibri" FontSize="32"/>
        </StackPanel>
    </Grid>
</Window>

以下 XAML 代码无法正常工作,并使用了 TextBox.Text:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="TextBoxTextQuestion.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640"
    Height="480"
>
    <Window.Resources>
        <Storyboard x:Key="animateTextStoryboard">
            <StringAnimationUsingKeyFrames Storyboard.TargetProperty="(TextBox.Text)" Storyboard.TargetName="textControl">
                <DiscreteStringKeyFrame KeyTime="0:0:1" Value="Goodbye"/>
            </StringAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource animateTextStoryboard}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid x:Name="LayoutRoot">
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBox x:Name="textControl" Text="Hello" FontFamily="Calibri" FontSize="32"/>
            <TextBox Text="World!" Margin="0,25,0,0" FontFamily="Calibri" FontSize="32"/>
        </StackPanel>
    </Grid>
</Window>

有趣...从来没有需要过这个,但总是认为它会有用。希望有人能回答。很抱歉我不能提供帮助。 - Chris Nicol
谢谢您的关注。我承认...这是一个有点学术性的问题...但我非常好奇,想看看一个无法动画化的DependencyProperty。 - cplotts
1个回答

28

试图手动地对TextBox进行动画处理...

var timeline = new StringAnimationUsingKeyFrames();
timeline.KeyFrames.Add(new DiscreteStringKeyFrame("Goodbye", KeyTime.FromTimeSpan(new TimeSpan(0,0,1))));
textControl.BeginAnimation(TextBox.TextProperty, timeline);

......揭示了一个更有用的错误信息。最后一行抛出以下 ArgumentException:

'Text' 属性在 'System.Windows.Controls.TextBox' 类上因为 IsAnimationProhibited 标志已经设置在 UIPropertyMetadata 上,用来将属性与该类关联而无法进行动画。
参数名称: dp

UIPropertyMetadata.IsAnimationProhibited 的文档如下:

通常,在 Windows Presentation Foundation (WPF) 框架的实现 API 中可用的默认依赖项属性可以进行动画处理。您可以在自己的自定义依赖项属性元数据中将此属性设置为 true,以禁用其上的动画。

显然,WPF 库的设计者决定不对 TextBox 的 Text 依赖属性进行动画处理,并明确禁用它。

这就是为什么该属性不能被动画处理的技术答案。他们为什么要禁用它?我不知道...

附:通过 Reflector 快速查看 TextBoxTextBoxBaseControl 的静态构造函数会发现,Text 是唯一不能进行动画处理的 TextBox 依赖项属性。


1
很棒的答案!这让我感到非常困扰。有趣的是,我在 TextBox 的静态构造函数中(使用 Reflector)没有看到设置该属性元数据。事实上,在发布问题之前,我检查了是否有任何类似的属性。我想知道 Text 属性的属性元数据是在哪里设置的。 - cplotts
TextBox 的静态构造函数使用 FrameworkPropertyMetadata 构造函数的这个重载:http://msdn.microsoft.com/en-us/library/ms557303.aspx,并将 isAnimationProhibited 参数设置为 true - Heinzi
啊,我错过了。再次,干得好。 - cplotts
5
我注意到设置文本属性似乎会创建许多对象,它们的类型表明TextBox在幕后可能实际上正在创建完整的文档。我猜想他们决定防止动画化文本属性,因为每次文本更改时都必须重新创建文档,然后处理更新TextPointers到新文档等问题。但是,没有任何阻止你使用绑定将TextBox的文本属性绑定到本地附加的字符串属性并进行动画处理。这样做效果很好。 - Ray Burns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接