Анимация элементов в DataTemplate ContentControl

1

У меня есть ContentControl который я разрабатываю с помощью DataTemplate. Я хотел бы иметь возможность определять анимацию вне ContentControl которая анимирует элементы в DataTemplate. Этот XAML - небольшой, упрощенный пример моего сценария:

<UserControl x:Class="StoryboardTesting.Stage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d">
    <UserControl.Resources>
        <DataTemplate x:Key="MyControlTemplate">
            <StackPanel>
                <TextBlock x:Name="TheBlock1" Text="Foo!" />
                <TextBlock x:Name="TheBlock2" Text="Bar!" />
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup Name="ValueStates">
            <VisualState Name="ToState">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="MyContentControl"
                                     Storyboard.TargetProperty="(UIElement.Opacity)"
                                     Duration="0:0:1"
                                     To="0" />
                </Storyboard>
            </VisualState>
            <VisualState Name="FromState" />
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Grid>
        <Canvas>
            <ContentControl x:Name="MyContentControl"
                            ContentTemplate="{StaticResource MyControlTemplate}" />
        </Canvas>
    </Grid>
</UserControl>

Я хотел бы, чтобы анимация могла нацеливать либо TextBox в шаблоне (вместо "MyContentControl"), либо по положению, либо по имени. Я запускаю анимацию в кодовом коде UserControl с вызовом следующим образом:

VisualStateManager.GoToElementState(this, "ToState", true);

Когда я запускаю это (заменяя "MyContentControl" на "TheBlock"), я получаю следующее:

InvalidOperationException: имя "TheBlock1" не может быть найдено в области имен "StoryboardTesting.Stage".

Это имеет смысл. Есть ли способ адресовать любой блок, используя имена свойств? Мне нужно избегать codebehind, поскольку это XAML, который создается во время выполнения.

  • 0
    Вы нашли решение вашей проблемы?
Теги:
xaml
wpf
animation

1 ответ

1

Я настоятельно рекомендую вам изучить Blend при работе над проектами WPF. В то время как XAML с помощью навыков клавиатуры действительно полезен, Blend также очень полезен. Мне потребовалось около 5 минут, чтобы построить для вас следующий пример: это DataTemplate котором есть состояния.

(сначала я создал пустой DataTemplate, затем я редактировал в Blend)

Пользователь может нажать любую из двух кнопок внизу, и текущее состояние будет изменено.

Изображение 174551Изображение 174551

Как вы увидите ниже, поведение оказалось действительно полезным для работы с состояниями, без кода.

XAML:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:wpfApplication3="clr-namespace:WpfApplication3"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Window.Resources>
        <wpfApplication3:MyObject x:Key="MyObject1" />
        <DataTemplate x:Key="Template1" DataType="wpfApplication3:MyObject">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="37*" />
                    <RowDefinition Height="13*" />
                </Grid.RowDefinitions>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="VisualStateGroup">
                        <VisualState x:Name="Red">
                            <Storyboard>
                                <ColorAnimationUsingKeyFrames Storyboard.TargetName="button" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                    <EasingColorKeyFrame KeyTime="0" Value="Red" />
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Green">
                            <Storyboard>
                                <ColorAnimationUsingKeyFrames Storyboard.TargetName="button" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                    <EasingColorKeyFrame KeyTime="0" Value="Lime" />
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Button x:Name="button"
                        Grid.RowSpan="1"
                        Grid.ColumnSpan="2"
                        Width="100"
                        Height="100"
                        Margin="2"
                        Content="Button"
                        FontSize="26.667" />
                <Button Grid.Row="1"
                        Width="Auto"
                        Margin="2"
                        Content="State1">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <ei:GoToStateAction StateName="Red" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
                <Button Grid.Row="1"
                        Grid.Column="1"
                        Width="Auto"
                        Margin="2"
                        Content="State2">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <ei:GoToStateAction StateName="Green" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ContentControl Content="{StaticResource MyObject1}" ContentTemplate="{StaticResource Template1}" />
    </Grid>
</Window>

Код-за:

namespace WpfApplication3
{
    public partial class MainWindow
    {
        public MainWindow() {
            InitializeComponent();
        }
    }

    internal class MyObject
    {
        public string Category { get; set; }
        public int Value { get; set; }
    }
}

РЕДАКТИРОВАТЬ

Чтобы ответить на вопрос вашего вопроса, эти состояния принадлежат к DataTemplate; определение этих состояний вне его не имеет никакого смысла, и, как вы испытали, это даже невозможно, и это по уважительной причине!

Представьте, что вы используете этот шаблон в двух разных местах, будут ли они иметь одинаковое состояние? Конечно, нет, поэтому в ней должны быть определены состояния, а не снаружи.

  • 0
    Это не очень хорошо отвечает на мой вопрос. Я хотел бы, чтобы анимации, определенные вне элемента управления, анимировали дочерние элементы управления внутри него (из шаблона). Это уже несколько возможно, потому что вы можете использовать навигацию по свойствам в целевых объектах раскадровки. Я думал, что просто не могу понять свойство, чтобы получить на элементы управления, созданные шаблоном.
  • 0
    Я думаю, что вы неправильно понимаете проблему, она связана с типом объекта, который содержит объекты, к которым вы пытаетесь получить доступ. В этом случае DataTemplate - это ресурс, а не объект, который будет непосредственно частью визуального дерева объекта, в котором вы находитесь. Хотя вы действительно можете получить доступ к элементам, как вы говорите, как в этом примере: msdn.microsoft.com/en-us/library/bb613579(v=vs.110).aspx , вы просто неправильно используете то, как все было задумано использоваться. Мой ответ несколько отвечает на ваш вопрос, потому что вы указали * без кода .
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню