¿Ancho de animación a ancho real en WPF?

¿Cómo puedo animar el ancho de un elemento de 0 a su ancho real en WPF?

Intenté esto:

<ControlTemplate.Triggers>
    <EventTrigger RoutedEvent="Loaded">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0:0:0.3" To="{Binding ElementName=MyElement, Path=ActualWidth}" From="0" Storyboard.TargetProperty="Width" Storyboard.TargetName="MyElement" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</ControlTemplate.Triggers>

Si cambio el enlace a un valor codificado, como 100, entonces el ancho está correctamente animado, excepto que quiero enlazar con el ancho real del elemento.

Si importa MyElement es un borde y estoy animando un elemento de pestaña.

Para el registro, esto tampoco funciona:

To="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"

preguntado el 12 de junio de 12 a las 11:06

2 Respuestas

Estoy seguro de que esto está mal por MUCHAS razones y no dude en decirme cuántas leyes de WPF he violado, pero... Resolví el mismo problema creando mi propia BindableDoubleAnimation.

public class BindableDoubleAnimation : DoubleAnimationBase
{
    DoubleAnimation internalAnimation;

    public DoubleAnimation InternalAnimation { get { return internalAnimation; } }

    public double To
    {
        get { return (double)GetValue(ToProperty); }
        set { SetValue(ToProperty, value); }
    }

    /// <summary>
    /// Dependency backing property for the <see cref="To"/> property.
    /// </summary>
    public static readonly DependencyProperty ToProperty =
        DependencyProperty.Register("To", typeof(double), typeof(BindableDoubleAnimation), new UIPropertyMetadata(0d, new PropertyChangedCallback((s, e) =>
            {
                BindableDoubleAnimation sender = (BindableDoubleAnimation)s;
                sender.internalAnimation.To = (double)e.NewValue;
            })));


    public double From
    {
        get { return (double)GetValue(FromProperty); }
        set { SetValue(FromProperty, value); }
    }

    /// <summary>
    /// Dependency backing property for the <see cref="From"/> property.
    /// </summary>
    public static readonly DependencyProperty FromProperty =
        DependencyProperty.Register("From", typeof(double), typeof(BindableDoubleAnimation), new UIPropertyMetadata(0d, new PropertyChangedCallback((s, e) =>
        {
            BindableDoubleAnimation sender = (BindableDoubleAnimation)s;
            sender.internalAnimation.From = (double)e.NewValue;
        })));


    public BindableDoubleAnimation()
    {
        internalAnimation = new DoubleAnimation();
    }

    protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue, AnimationClock animationClock)
    {
        return internalAnimation.GetCurrentValue(defaultOriginValue, defaultDestinationValue, animationClock);
    }

    protected override Freezable CreateInstanceCore()
    {
        return internalAnimation.Clone();;
    }
}

Ahora soy libre de usar enlaces para las propiedades To From.

<local:BindableDoubleAnimation Storyboard.TargetProperty="Width" From="0" To="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Window}}"/>

Respondido el 12 de junio de 12 a las 12:06

¿Alguien ha conseguido que esto funcione para BindableDoubleAnimations que están dentro de un Storyboard que esta en un VisualState menos ControlTemplate? Para los casos en los que solo tengo un solo BindableDoubleAnimation en la VisualState y codifico el valor "Para" (para decir algo como "100"), nada se anima, y ​​tampoco GetCurrentValueCore ni CreateInstanceCore están siendo llamados. Para los casos en los que uso el enlace de datos en la propiedad "Para", el enlace siempre falla y siempre genera el error "No se puede encontrar el origen del enlace...". Incluso cuando intento todo desde arriba palabra por palabra, falla. - jason franco

... Me encantaría que esto funcione, ¡parece que podría ser una gran solución! - jason franco

Que los enlaces no se puedan usar en animaciones es un problema común.

Una solución sería usar un objeto auxiliar que tenga SourceValue & TargetValue (que puedes enlazar a lo que quieras, incluyendo ActualWidth) a CurrentValue (que devuelve el valor animado) y un Progress que se puede animar de 0.0 a 100.0. Cuando se cambia el progreso, solo necesita calcular el CurrentValue a la que luego puede vincular el Width de tu objeto. No es bonito, pero debería funcionar.

Respondido el 12 de junio de 12 a las 11:06

No tengo clara esta respuesta. ¿Podría proporcionar un ejemplo de código? ¿Estás describiendo algo similar a la solución de @Andy? - Phillip Scott Givens

@PhillipScottGivens: la respuesta de Andy siempre modifica la animación al crear una capa enlazable encima. Lo que sugiero es diferente, sugiero un objeto intermediario que siempre usa la misma animación que anima su Progress propiedad de 0 a 100 (por lo tanto, la animación no cambia), este objeto proporciona el valor de la animación a través de un CurrentValue propiedad que devuelve el valor calculado a partir de su SourceValue, TargetValue y Progress. - media pensión

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.