我要寻找一个干净的方式开始的动画,将有动态值。 基本上我想要做其中元素的变化宽度根据另一个元素的数据的动画。 说我有一个TextBlock这就是Text属性绑定。 当此属性更改我希望有一个视觉元素说一个矩形为我们着想做DoubleAnimation是改变由前值的宽度为新值。
我试图从把代码如果可能的话我看来望而却步。 我看着DataTriggers但他们似乎需要你知道什么价值将如枚举。 在我的情况下,它只是值变更需要触发故事板和动画就需要开始在目前(先前)值并很好地移动到新的价值。
有任何想法吗。 也许我只是错过了一个属性。
这里是我结束了该解决方案。 要根据我的ViewModel我使用了DataTrigger数据做动画。 下面是我的控制方式。
<Style TargetType="Grid" x:Key="DetailRotation" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AnimationState}" Value="New">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="EndAnimation" />
<BeginStoryboard Name="NewAnimation">
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,30,0,0" To="0,0,0,0" Duration="0:0:1" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=AnimationState}" Value="End">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="NewAnimation" />
<BeginStoryboard Name="EndAnimation">
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,0,0,0" To="0,-20,0,0" Duration="0:0:1"/>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
你可以探索利用附加属性挂钩必要的逻辑到情节提要/动画,你的愿望。
这不一定是从编写代码阻止你,但它会保持它从视图中分离出来,并使其能够跨越多个视图重新使用。
由于通过动画修改属性不能动画“上下文”之外的设置,我想出了一个代码解决方案,因为我不能有效地做同样的XAML。
private void UserControl_IsVisibleChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
DoubleAnimation fadeIn = new DoubleAnimation();
fadeIn.From = 1d;
fadeIn.To = 1d;
fadeIn.Duration = new Duration(new TimeSpan(0, 0, 0));
DoubleAnimation fade = new DoubleAnimation();
fade.From = 1d;
fade.To = 0d;
fade.BeginTime = TimeSpan.FromSeconds(5);
fade.Duration = new Duration(new TimeSpan(0, 0, 1));
NameScope.SetNameScope(this, new NameScope());
this.RegisterName(this.Name, this);
Storyboard.SetTargetName(fadeIn, this.Name);
Storyboard.SetTargetProperty(fadeIn, new PropertyPath
(UIElement.OpacityProperty));
Storyboard.SetTargetName(fade, this.Name);
Storyboard.SetTargetProperty(fade, new PropertyPath
(UIElement.OpacityProperty));
Storyboard sb = new Storyboard();
sb.Children.Add(fadeIn);
sb.Children.Add(fade);
sb.Completed += new EventHandler(sb_Completed);
sb.Begin(this);
}
}
void sb_Completed(object sender, EventArgs e)
{
this.Visibility = Visibility.Hidden;
}
其实你要绑定的DoubleAnimation.ToProperty
到ViewModel
属性和动画的实际控制。 问题是,当动画应继续ToProperty
改变。 我的解决方案封装所有这一逻辑的MarkupExtenstion
它包装一个Binding
。
public class AnimateBindingExtension : MarkupExtension {
static DependencyPropertyDescriptor dpd =
DependencyPropertyDescriptor.FromProperty(DoubleAnimation.ToProperty,
typeof(DoubleAnimation));
public AnimateBindingExtension(PropertyPath path) {
Path = path;
}
public bool ValidatesOnExceptions { get; set; }
public IValueConverter Converter { get; set; }
public object ConverterParamter { get; set; }
public string ElementName { get; set; }
public RelativeSource RelativeSource { get; set; }
public object Source { get; set; }
public bool ValidatesOnDataErrors { get; set; }
[ConstructorArgument("path")]
public PropertyPath Path { get; set; }
public object TargetNullValue { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider) {
var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (valueProvider == null) {
throw new Exception("could not get IProviderValueTarget service.");
}
var bindingTarget = valueProvider.TargetObject as FrameworkElement;
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
if (bindingProperty == null || bindingTarget == null) {
throw new Exception();
}
var binding = new Binding {
Path = Path,
Converter = Converter,
ConverterParameter = ConverterParamter,
ValidatesOnDataErrors = ValidatesOnDataErrors,
ValidatesOnExceptions = ValidatesOnExceptions,
TargetNullValue = TargetNullValue
};
if (ElementName != null) binding.ElementName = ElementName;
else if (RelativeSource != null) binding.RelativeSource = RelativeSource;
else if (Source != null) binding.Source = Source;
// you can add a Duration property to this class and use it here
var anim = new DoubleAnimation {
Duration = new Duration(TimeSpan.FromSeconds(0.1)),
AccelerationRatio = 0.2,
DecelerationRatio = 0.8
};
// this can be a new subclass of DoubleAnimation that
// overrides ToProperty metadata and add a property
// change callback
dpd.AddValueChanged(anim, (s, e) => bindingTarget.BeginAnimation(bindingProperty, anim));
BindingOperations.SetBinding(anim, DoubleAnimation.ToProperty, binding);
// this is because we need to catch the DataContext so add animation object
// to the visual tree by adding it to target object's resources.
bindingTarget.Resources[bindingProperty.Name] = anim;
// animation will set the value
return DependencyProperty.UnsetValue;
}
}
你可以做同样的与其他动画类动画等类型。