Почему TextBox.Text в WPF не анимируется?

Хорошо, я только что столкнулся с чем-то, что действительно застало меня врасплох.

Я помогал коллеге-разработчику с парой несвязанных вопросов, и в его проекте он анимировал текст в несколько текстовых блоков. Итак, я вернулся к своему столу и воссоздал проект (чтобы ответить на его вопросы), но случайно использовал TextBox вместо TextBlock. Мой текст вообще не анимировался! (Большая помощь, я был!)

В конце концов я понял, что его xaml использует TextBlock, а мой использует TextBox. Что интересно, Blend не создавал ключевые кадры, когда я использовал TextBox. Итак, я заставил его работать в Blend, используя TextBlock (s), а затем вручную изменил xaml, преобразовав TextBlock (s) в TextBox (es). Когда я запустил проект, я получил следующую ошибку:

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

Ну, похоже, что Blend был достаточно умен, чтобы знать это... и не генерировать ключевые кадры в анимации (он просто изменил бы значение непосредственно в TextBox). +1 за смесь.

Итак, возник вопрос: почему 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>

person cplotts    schedule 08.04.2010    source источник
comment
Интересно... никогда в этом не нуждался, но всегда предполагал, что будет. Надеюсь, у кого-то есть ответ. Извините, я не могу помочь.   -  person Chris Nicol    schedule 09.04.2010
comment
Спасибо, что посмотрели. Я признаю ... это немного академический вопрос ... но мне очень любопытно увидеть свойство DependencyProperty, которое я не могу анимировать.   -  person cplotts    schedule 09.04.2010


Ответы (1)


Пытаюсь анимировать 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, поскольку в метаданных UIPropertyMetadata, используемых для связывания свойства с классом, установлен флаг IsAnimationProhibited.
Имя параметра: dp

В документации UIPropertyMetadata.IsAnimationProhibited говорится:

Как правило, свойства зависимостей по умолчанию, доступные в API-интерфейсах реализации платформы Windows Presentation Foundation (WPF), можно анимировать. Вы можете установить для этого свойства значение true в метаданных собственного пользовательского свойства зависимостей, чтобы отключить для него анимацию.

Судя по всему, разработчики библиотеки WPF решили, что анимация свойства Text depdendency TextBox не является хорошей идеей, и явно отключили его.

Итак, это технический ответ на вопрос, почему это свойство нельзя анимировать. Почему они отключили его? Я понятия не имею...

PS: Беглый взгляд на статические конструкторы TextBox, TextBoxBase и Control с помощью Reflector показывает, что Text — единственное свойство зависимостей TextBox, которое нельзя анимировать.

person Heinzi    schedule 08.04.2010
comment
Отличный ответ! Это сводило меня с ума. Интересно, что я не вижу, чтобы метаданные свойства были установлены в статическом конструкторе (использующем Reflector) для TextBox. На самом деле, я проверил наличие подобных свойств, прежде чем публиковать вопрос. Интересно, где эти метаданные свойства установлены для свойства Text. - person cplotts; 09.04.2010
comment
Статический конструктор TextBox использует эту перегрузку конструктора FrameworkPropertyMetadata: msdn.microsoft.com /en-us/library/ms557303.aspx и передает true в качестве аргумента isAnimationProhibited. - person Heinzi; 09.04.2010
comment
Ах, я пропустил это. Опять же, хорошая работа. - person cplotts; 09.04.2010
comment
Я заметил, что при установке свойства Text создается довольно много объектов, типы которых указывают на то, что за кулисами TextBox может фактически создавать полный документ. Я предполагаю, что они решили предотвратить анимацию свойства Text, потому что им пришлось бы воссоздавать документ каждый раз, когда текст изменялся, а затем иметь дело с обновлением TextPointers до нового документа и т. д. Однако ничто не мешает вам использовать привязку для привязки свойства Text TextBox к локально прикрепленному строковому свойству и его анимации. Это работает очень хорошо. - person Ray Burns; 12.04.2010