WPF: выбор цели анимации - PullRequest
5 голосов
/ 30 апреля 2010

Я пытаюсь создать простой (я думаю) эффект анимации, основанный на изменении свойства в моей ViewModel. Я хотел бы, чтобы целью был конкретный текстовый блок в шаблоне элемента управления пользовательского элемента управления, который наследуется от Window.

Из примеров статей, которые я видел, DataTrigger - самый простой способ сделать это. Похоже, что Window.Triggers не поддерживает DataTriggers, что привело меня к попытке применить триггер в стиле. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что я не могу настроить таргетинг на TextBlock (или любой другой дочерний элемент управления) - в результате код, приведенный ниже, заключается в том, что анимация применяется к фону всего окна.

Если я полностью отключу StoryBoard.Target, эффект будет точно таким же.

Это правильный подход с неправильным синтаксисом или есть более простой способ сделать это?

<Style x:Key="MyWindowStyle" TargetType="{x:Type Window}">
    <Setter Property="Template" Value="{StaticResource MyWindowTemplate}"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding ChangeOccurred}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard BeginTime="00:00:00" Duration="0:0:2" Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}}"
                                    Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
                        <ColorAnimation FillBehavior="Stop" From="Black" To="Red" Duration="0:0:0.5" AutoReverse="True"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>
    </Style.Triggers>
</Style>

Обновление

Следует также упомянуть, что я пытался назвать TextBlock и сослаться на него через StoryBoard.TargetName (как предложил Тиморес), и получил ошибку «Свойство TargetName нельзя установить в Setter Style.»

Ответы [ 2 ]

5 голосов
/ 30 апреля 2010

РЕДАКТИРОВАТЬ: Я наблюдал за тем, что TextBlock находится в ControlTemplate вашего пользовательского окна / элемента управления. Я не думаю, что можно нацелить элемент управления в пределах на ControlTemplate из Storyboard вне этого ControlTemplate. Однако вы можете определить свойство в вашем пользовательском окне, которое затем привязываете к свойству ChangeOccurred, а затем добавить триггер к своему ControlTemplate, который теперь будет вызываться свойством пользовательского элемента управления, а не свойством окна ViewModel (конечно, косвенно он запускается ViewModel, потому что ChangeOccurred связан со свойством пользовательского окна, которое, в свою очередь, запускает анимацию - ну, сложное предложение, надеюсь, вы понимаете). Это вариант? Не могли бы вы следовать? ; -)

Может быть, какой-то код поможет:

public class MyCustomWindow : Window
{
    public static readonly DependencyProperty ChangeOccurred2 = DependencyProperty.Register(...);

    public bool ChangeOccurred2 { ... }

    // ...
}

И немного XAML:

<local:MyCustomWindow ChangeOccurred2="{Binding ChangeOccurred}" ... >
    <!-- Your content here... -->
</local:MyCustomWindow>

<!-- Somewhere else (whereever your ControlTemplate is defined) -->
<ControlTemplate TargetType="{x:Type local:MyCustomWindow}">

    <!-- your template here -->

    <ControlTemplate.Triggers>
        <Trigger Property="ChangeOccurred2" Value="True">
            <Trigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard BeginTime="00:00:00" Duration="0:0:2"
                                Storyboard.TargetName="txtWhatever"
                                Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
                        <ColorAnimation FillBehavior="Stop"
                                        From="Black" To="Red"
                                        Duration="0:0:0.5"
                                        AutoReverse="True"/>
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.EnterActions>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Примечание: Я назвал свойство окна ChangeOccurred2, потому что хотел, чтобы оно отличалось от свойства ChangeOccurred ViewModel. Конечно, вы должны выбрать лучшее имя для этой собственности. Однако мне не хватает фона для такого решения.


Мой старый ответ:

Итак, вы хотите анимировать TextBlock, который находится в содержимом (пользовательского) окна?!

Почему вы хотите установить стиль для окна, а не для самого TextBlock? Может быть, вы должны попробовать что-то вроде этого (не проверял это!):

<local:MyCustomWindow ... >
    <!-- ... -->
    <TextBlock x:Name="textBlockAnimated" ... >
        <TextBlock.Style>
            <Style TargetType="{x:Type TextBlock}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ChangeOccurred}" Value="True">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard BeginTime="00:00:00" Duration="0:0:2"
                                            Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
                                    <ColorAnimation FillBehavior="Stop"
                                                    From="Black" To="Red"
                                                    Duration="0:0:0.5"
                                                    AutoReverse="True"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
    <!-- ... -->
</local:MyCustomWindow>

{Binding ChangeOccurred} может быть недостаточно. Возможно, вам придется добавить DataContext к TextBlock или добавить RelativeSource или что-то еще.

0 голосов
/ 30 апреля 2010

Является ли TextBlock в MyWindowTemplate?

Если это так, присвойте TextBlock имя и используйте Storyboard.TargetName для ссылки на него.

См. другой вопрос в SO

...