有没有办法在XAML(例如,作为一种资源),一旦某处定义动画,然后再用它多次吗? 我有很多跨独立需要开始根据datatrigger同一种动画的不同的充的DataTemplates独立的画笔。 现在,因为它似乎是一个动画必须定义一个Storyboard.TargetName和Storyboard.TargetProperty。 这几乎违背了可重用性的目的。 我会以某种方式想申报“用这个动画形成资源,但其应用到另一个元素这个时候”。
对我来说,这似乎是一个相当基本的,重要的和基本要求,我惊讶的是它不是直截了当地acomplish。 我失去了一些东西在这里?
同样的道理也适用于触发器。 假设我有很多不同的充视觉元素都代表同一类型的使用状态的颜色动画的。 如褪色变为绿色时“主动”变脸为“红色”,当“错误”等视觉效果之间的唯一区别是它们的形状/视觉树中选择所需的动画行为是相同的,他们都在各自的可视化树的地方有一个元素有型彩色的属性。 我想是不是很难想象它是多么乏味的一遍又一遍的重新定义相同的动画和datatrigger套。 每个开发人员都讨厌这个。 我拼命地寻找,不需要背后没有(或至少很少)C#代码更容易的解决方案。
我想出了到目前为止是这样的:
定义动画中的资源LIK这(重复此对所有的基本状态,有一样激活,活跃,不活跃,错误):
<ColorAnimationUsingKeyFrames x:Key="deactivatingColorAnimation"
Storyboard.TargetProperty="Material.(MaterialGroup.Children)[0].Brush.(SolidColorBrush.Color)"
FillBehavior="HoldEnd" RepeatBehavior="Forever" AutoReverse="True">
<ColorAnimationUsingKeyFrames.KeyFrames>
<LinearColorKeyFrame KeyTime="00:00:00" Value="Gray"/>
<LinearColorKeyFrame KeyTime="00:00:0.25" Value="Gray"/>
<LinearColorKeyFrame KeyTime="00:00:0.5" Value="Gray" />
<LinearColorKeyFrame KeyTime="00:00:0.75" Value="Gray" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
在触发器中使用它在故事板(重复的次数不计其数这对每个国家每个X不同的充stateviusal,总是能想出的故事板的新名称):
<DataTrigger Binding="{Binding SubstrateHolder.State}" Value="Deactivating">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="someStateVisualDeactivatingStoryboard">
<Storyboard Storyboard.TargetName="someStateVisual">
<StaticResource ResourceKey="deactivatingColorAnimation" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="someStateVisualDeactivatingStoryboard" />
</DataTrigger.ExitActions>
</DataTrigger>
你可以很容易地想象我有多么膨胀XAML不得不多次复制并粘贴所有这些数不胜数的DataTriggers。
这将是冷静地界定这触发一次,它适用于不同状态的视觉效果。 如何这样的事情在WPF解决了吗? 任何提示?
目前似乎没有任何好处只有XAML的解决这个普遍问题。 我最后写的是定义所有给定元素的动画行为我自己的附加属性。 事情是这样的:
<DataTemplate>
<!-- ... -->
<Rectangle Fill="Gray">
<v:AnimationHelper.Animations>
<v:StandardColorStateAnimation TargetColorProperty="(Rectangle.Fill).(SolidColorBrush.Color)" TargetStateProperty={Binding State} />
</v:AnimationHelper.Animations>
</Rectangle>
<DataTemplate>
其余的(创建动画等)的代码隐藏完成。
我意识到这个问题是在此张贴的时间有点死了,但我没有找到需要的背后很少的代码的解决方案。
你可以做一个与自定义属性用户控件 (向下滚动至图8),其中包含您的矩形,以及动画和状态触发器。 这个用户控件将定义一个公共属性,例如状态改变时,将触发颜色变化。
唯一需要的代码隐藏在代码来创建你的变量。
用户控制可以在它们被重新使用一遍又一遍,不重写的XAML故事板或数据触发器。
最“XAML的方式”来实现这一目标,我能想到的是建立专门MarkupExtension
这将拉动从资源字典中的动画,并设置必要的属性-我认为那些被限制的一个子集Storyboard.Target
, Storyboard.TargetName
和Storyboard.TargetProperty
。 虽然这需要一些代码的背后,则是一次性的工作,而且, MarkupExtension
s的设计与XAML使用。 下面是最简单的版本:
[MarkupExtensionReturnType(typeof(Timeline))]
public class AnimationResourceExtension : StaticResourceExtension
{
//This property is for convienience so that we
//don't have to remember to set x:Shared="False"
//on all animation resources, but have an option
//to avoid redundant cloning if it is
public bool IsShared { get; set; } = true;
public DependencyObject Target { get; set; }
public string TargetName { get; set; }
public PropertyPath TargetProperty { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (base.ProvideValue(serviceProvider) is Timeline animation)
{
//If the animation is shared we shall clone it
//Checking if it is frozen is optional and we can
//either clone it or throw an exception
//(or simply proceed knowing one will be thrown anyway)
if (IsShared || animation.IsFrozen)
animation = animation.Clone();
Storyboard.SetTarget(animation, Target);
Storyboard.SetTargetName(animation, TargetName);
Storyboard.SetTargetProperty(animation, TargetProperty);
return animation;
}
else
throw new XamlException("The referenced resource is not an animation");
}
}
用法很简单:
<FrameworkElement.Resources>
<DoubleAnimation x:Key="MyAnimation" From="0" To="1" Duration="0:0:1" />
</FrameworkElement.Resources>
(...)
<Storyboard>
<utils:AnimationResource ResourceKey="MyAnimation" TargetName="SomeElement" TargetProperty="Opacity" />
</Storyboard>
作为简单,因为它可能是这个解决方案有其局限性-它不支持既不Binding
,也不DynamicResource
扩展上述性能。 然而,这是可以实现的,但需要一些额外的努力。 Binding
的支持应该是很简单-正确使用的问题XamlSetMarkupExtensionAttribute
(加上一些样板代码)。 DynamicResource
支持将是一个有点麻烦,而且除了使用XamlSetMarkupExtensionAttribute
需要包裹IServiceProvider
返回足够IProvideValueTarget
实现,但仍然是可能的。