【问题标题】:EventTrigger Not Working When Declared in Window.Resources in WPF在 WPF 中的 Window.Resources 中声明时,EventTrigger 不起作用
【发布时间】:2013-07-23 04:11:18
【问题描述】:

我是 WPF 的新手,所以我可能遗漏了一些重要的东西,但我已经尝试并试图对以下现象提出解释,但无济于事。 基本上,以下代码有效(显示动画):

    <Window.Resources>
    <Storyboard x:Key="LoadStoryBoard"
AutoReverse="True"
RepeatBehavior="Forever">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="button1" 
                Storyboard.TargetProperty="(Button.Opacity)">
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.4" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
...
<Button x:Name="button1" Grid.Column="0" Grid.Row="1" Style="{StaticResource Load}">
<Button.Triggers>
    <EventTrigger RoutedEvent="Loaded">
                <BeginStoryboard Storyboard="{StaticResource LoadStoryBoard}" />
            </EventTrigger>
</Button.Triggers>
</Button>

但是,当我尝试将事件触发器放在下面的加载样式中时,动画不再出现:

    <Window.Resources>
    <Storyboard x:Key="LoadStoryBoard"
AutoReverse="True"
RepeatBehavior="Forever">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="button1" 
                Storyboard.TargetProperty="(Button.Opacity)">
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.4" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
...
<Style x:Key="Load" TargetType="Button">
...
<Style.Triggers>
    ...
    <EventTrigger RoutedEvent="Loaded">
                <BeginStoryboard Storyboard="{StaticResource LoadStoryBoard}" />
            </EventTrigger>
</Style.Triggers>
</Style>

【问题讨论】:

  • 嘿克莱门特,正如@AnatoliyNikolaev 所说,您需要做的就是从DoubleAnimationUsingKeyFrames 对象的声明中删除Storyboard.TargetName 属性。

标签: wpf events triggers styles


【解决方案1】:

Style的触发器中不能使用带有TargetName的对象,这样的动画。为此,它们被放置在触发器模板&lt;ControlTemplate.Triggers&gt; 中。引用link:

TargetName 不适合在 Style 的 Triggers 集合中使用。样式没有名称范围,因此在那里按名称引用元素是没有意义的。但是模板(DataTemplate 或 ControlTemplate)确实有一个名称范围。

以下作品:

<Window.Resources>
    <Storyboard x:Key="LoadStoryBoard" AutoReverse="True" RepeatBehavior="Forever">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="button1" Storyboard.TargetProperty="(Button.Opacity)">
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.4" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>       

    <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Green" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontSize" Value="14" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        <Setter Property="SnapsToDevicePixels" Value="True" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border x:Name="button1" CornerRadius="0" Background="{TemplateBinding Background}">
                        <Grid>
                            <ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />                                
                        </Grid>
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="Orange" />
                        </Trigger>

                        <EventTrigger RoutedEvent="Button.Loaded">
                            <BeginStoryboard Storyboard="{StaticResource LoadStoryBoard}" />
                        </EventTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<Grid>
    <Button Name="TestButton" Style="{StaticResource ButtonStyle}" Width="100" Height="30" Content="Test" Grid.Column="0" Grid.Row="1" />
</Grid>

注意现在TargetNameBorder指定的模板中:&lt;Border x:Name="button1" .../&gt;

Note: 或者,您可以只删除Storyboard.TargetName,因为它会触发样式不受支持。

【讨论】:

  • 感谢您的快速回复。我刚刚尝试将我的 eventtrigger 放入 controltemplate.triggers,但动画不起作用。我也直接复制粘贴了你的代码,但是好像不行。
  • @Clement Hoang:到底什么不起作用?我可以提供项目的链接。
  • 我可以确认,当我将这个代码示例复制并粘贴到一个新项目中时,它对我来说工作得很好。
  • 抱歉,现在可以使用了。 :) 在不相关的说明中,假设我希望情节提要在发生某个触发器时针对另一个控件,那么 eventtrigger 是这样做的正确方法,还是应该使用其他方法?
  • @Clement Hoang:我想是的。当你为特定的控件做动画时,比如Button,并且这个行为是标准的并且是静态的(例如:MouseOver、Loaded等),那么最好在@987654332中使用动画@ (例如我的示例)。当动画在面板中使用任意数量的控件如GridStackPanel时,最好在(例如面板Grid&lt;Grid.Triggers&gt;中使用EventTriggers,预先指定TargetName
【解决方案2】:

EventTrigger 不起作用是正确的,但这不是因为它是在 Resources 部分中声明的。要看到这一点,您可以将您的样式直接移动到 Button 声明中,但它仍然不起作用:

<Button x:Name="button1" Grid.Column="0" Grid.Row="1">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Triggers>
                <EventTrigger RoutedEvent="Button.Loaded">
                    <BeginStoryboard Storyboard="{StaticResource LoadStoryBoard}" />
                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

但是,如果我们将 Animation 的声明从 Resources 部分移开,它会再次起作用:

<Button x:Name="button1" Grid.Column="0" Grid.Row="1">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Triggers>
                <EventTrigger RoutedEvent="Button.Loaded">
                    <BeginStoryboard>
                        <Storyboard AutoReverse="True" RepeatBehavior="Forever">
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Button.Opacity)">
                                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.4" />
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

因此,问题似乎与Resources 部分中声明的StoryboardLoaded 事件触发时尚未准备好有关。 this post 中提到了类似的问题。

但是,为了让事情更加混乱,如果我们随后将 Animation 的完整声明放入 Resources 部分中声明的 Style 中,那么现在 Style 有效:

<Window.Resources>
    <Style x:Key="Load" TargetType="Button">
        <Style.Triggers>
            <EventTrigger RoutedEvent="Button.Loaded">
                <BeginStoryboard>
                    <Storyboard AutoReverse="True" RepeatBehavior="Forever">
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Button.Opacity)">
                            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.4" />
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Button x:Name="button1" Grid.Column="0" Grid.Row="1" Style="{StaticResource Load}" />

我可以推测为什么会发生这种情况,但我猜很少有 WPF 开发人员真正知道为什么一切都是这样的......我了解到,如果特定的声明方法有效,使用它,如果没有,请尝试其他的。

背景

在WPF中,有四个地方可以定义TriggersStyle.TriggersControlTemplate.TriggersDataTemplate.TriggersFrameworkElement.Triggers(例如Button.Triggers)。

基本上,FrameworkElement.TriggersTriggerCollection 有一个巨大的缺陷,它只接受EventTrigger 类型的触发器。这可以在 MSDN 的 FrameworkElement.Triggers Property 页面上看到,其中对该属性可以接受的内容给出了以下定义:

一个或多个已定义的 EventTrigger 元素。每个这样的触发器都是 预期包含有效的故事板动作和参考。注意 这个集合只能建立在页面的根元素上。

其他触发器属性的 MSDN 属性页各自声明它们可以接受零个或多个 TriggerBase 对象,或一个或多个 TriggerBase 对象

此外,不同的触发器遵循不同的规则 - 统一的方法肯定会帮助 WPF 的新手。来自FrameworkElement.Triggers Property 页面:

此属性不允许您检查存在于 此元素上使用的部分样式。它只报告集合 从字面上添加到集合中的触发器的数量,无论是在 标记或代码。元素通常不存在此类元素 默认情况下(例如通过模板);它更常见于 来自控制合成的触发器在 样式。

就行为而言(并试图确定哪种效果来自 哪个元素声明的 Triggers 集合),两者都是触发 条件和触发效果可能在这个元素上,或者可能是 在其逻辑树中的子元素上。请注意,如果您使用 生命周期事件如 Loaded 获取此集合,子 元素的触发器可能尚未完全加载,并且集合 会比运行时的实际值小。

请注意,仅在元素上建立的触发器集合 支持EventTrigger,而不是属性触发器(Trigger)。如果您需要 属性触发器,您必须将它们放在样式或模板中,并且 然后将该样式或模板直接分配给元素 通过 Style 属性,或间接通过隐式样式 参考。

来自 MSDN 的 DataTemplate.Triggers Property 页面:

如果您在数据模板中创建触发器,则 触发器应该设置范围内的属性 数据模板。否则,它可能更适合创建 使用以包含数据的类型为目标的样式触发。 例如,如果要绑定 ListBox 控件,则容器是 ListBoxItem 对象。如果您使用触发器来设置属性 不在DataTemplate的范围内,那么可能更多 适合创建 ListBoxItem 样式并在其中创建触发器 风格。

不幸的是,所有这些额外的信息实际上并没有回答您关于为什么动画资源在 Style 资源中不起作用的问题,但希望现在,您可以看到整个 Trigger 区域有点一个复杂、混乱的区域。我自己不是专家,我只是倾向于使用任何有效的声明Triggers 的方法。

我希望这在某种程度上有所帮助。

【讨论】:

  • 他不是工作示例,因为它指向TargetName 的样式,但不受支持。如果他删除它,他将不得不在这两种情况下工作。
  • @AnatoliyNikolaev,他已经有一个工作示例......他在问为什么另一个示例不起作用,而不是一个工作示例。
  • 就是这样,如果在不工作的示例中,它将删除 Storyboard.TargetName="button1" 示例什么会起作用。
  • 哦,我明白你的意思了……哇!我怎么没注意到?!!?为你+1,我的朋友!
猜你喜欢
  • 2012-07-11
  • 1970-01-01
  • 2011-07-31
  • 2012-06-24
  • 2014-01-25
  • 2017-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多