动画ContentControl的DataTemplate中的元素

时间:2014-10-13 19:06:58

标签: c# wpf xaml animation

我有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);

当我运行它(用“TheBlock”替换“MyContentControl”)时,我得到以下内容:

  

InvalidOperationException:在'StoryboardTesting.Stage'的名称范围内找不到'TheBlock1'名称。

哪个有道理。有没有办法使用属性名称解决任何一个块?我需要避免代码隐藏,因为这是在运行时生成的XAML。

1 个答案:

答案 0 :(得分:1)

我强烈建议您在使用WPF项目时学习使用Blend。虽然键盘技巧的XAML确实很有用,但Blend也非常有用。我花了大约5分钟为你构建以下示例,它是一个DataTemplate,它有状态。

(首先我创建了一个空的DataTemplate,然后我在Blend中编辑了)

用户可以按下底部的任意2个按钮,当前状态将会改变。

enter image description here enter image description here

正如您在下面看到的那样,行为被证明对处理状态非常有帮助,完全没有代码隐藏。

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;在它之外定义这些状态并没有任何意义,正如你所经历的那样甚至是不可能的,这是有充分理由的!

想象一下,你在两个不同的地方使用这个模板,它们会共享相同的状态吗?当然没有,因此必须在其中定义状态,而不是在外部。