我是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>
答案 0 :(得分:3)
在Style
触发器中无法使用TargetName
这样的动画对象。为此,将它们放在触发器模板<ControlTemplate.Triggers>
中。引自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>
请注意TargetName
中指定的模板中现在Border
:<Border x:Name="button1" .../>
。
Note:
或者,您可以删除Storyboard.TargetName
,因为它不支持触发样式。
答案 1 :(得分:3)
你是正确的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>
因此问题似乎与Storyboard
部分中声明的Resources
在Loaded
事件触发时尚未准备就绪有关。 this post中也提到了类似的问题。
但是,如果我们将Animation
的完整声明放入Style
部分中声明的Resources
,那么只是为了让事情更加混乱,那么现在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中,有四个地方我们可以定义Triggers
; Style.Triggers
,ControlTemplate.Triggers
,DataTemplate.Triggers
和FrameworkElement.Triggers
(例如Button.Triggers
)。
基本上,FrameworkElement.Triggers
TriggerCollection
存在一个巨大缺陷,因为它只接受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
区域是一个复杂,凌乱的地方。我自己不是专家,我只是倾向于使用任何一种声明Trigger
的方法。
我希望在某种程度上有所帮助。