In realtà si desidera associare il DoubleAnimation.ToProperty
alla proprietà ViewModel
e animare controllo effettivo. Il problema è che l'animazione deve essere continuata quando è stato modificato ToProperty
. La mia soluzione racchiude tutta questa logica in un MarkupExtenstion
che racchiude un 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;
}
}
È possibile fare lo stesso con altre classi di animazione per animare altri tipi.
Io non sono davvero sicuro questa è la direzione che ho bisogno. Sono quasi al punto in cui dovrò utilizzare un routedevent per comandare che lo storyboard avvenga e associare la larghezza precedente e la larghezza attuale alle proprietà di e dell'animazione. Questo potrebbe essere l'unico modo per farlo. Ancora non sono sicuro. DataTriggers funzionerebbe solo per le modifiche allo stile di stato e non per le modifiche dinamiche. È qui che tendo a staccarmi un po 'dal modello. – cjibo