其實你要綁定的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;
}
}
您可以對其他動畫類執行相同的動畫來爲其他類型創建動畫。
我真的不確定這是我需要的方向。我幾乎到了必須使用routedevent命令發生故事板並將PreviousWidth和CurrentWidth綁定到動畫的to和from屬性的位置。這可能是做到這一點的唯一方法。仍然不確定。 DataTriggers只適用於狀態更改而非動態更改。這是我傾向於脫離一點模式的地方。 – cjibo