Pregunta

¿Hay una manera de definir una animación en algún lugar de XAML (por ejemplo. Como recurso) una vez y luego reutilizarlo varias veces? Tengo un montón de cepillos independientes en todo DataTemplates diferentes personas que necesitan de forma independiente para iniciar el mismo tipo de animación basada en un DataTrigger. Ahora ya que parece que tiene una animación para definir un Storyboard.TargetName y Storyboard.TargetProperty. Esto más o menos en contra del propósito de la reutilización. Me gustaría de alguna manera para declarar "utilizar esta animación formar el recurso, sino que se aplica a otro elemento de este tiempo".

Para mí esto parece ser una petición bastante básico, importante y esencial y Me sorprende que no es tan sencillo a acomplish. Me estoy perdiendo algo aquí?

Lo mismo se aplica para los factores desencadenantes. Supongamos que tengo una gran cantidad de elementos visuales diferentes personas que todos representan el mismo tipo de animaciones de color estado utilizando. P.ej. desvanecerse a verde cuando se desvanecen "activa" a "rojo" cuando "error", etc. La única diferencia entre las imágenes es su forma / árbol visual el comportamiento de animación deseado es el mismo, todos ellos tienen un elemento en algún lugar de su árbol visual que tiene una propiedad de tipo de color. Creo que no es difícil imaginar lo tedioso que es redefinir las mismas animaciones y juegos DataTrigger una y otra vez. Cada desarrollador odia esto. Busco desesperadamente una solución más fácil que no requiere ninguna (o al menos muy poco) c # código detrás.

Lo que he encontrado hasta el momento es la siguiente:

Definir las animaciones en un recurso lik este (repetir esta operación para todos los estados básicos que hay, como la activación de, activo, inactivo, error):

<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>

El uso en guión gráfico en los disparadores (repetir esta infinidad de veces para cada estado de cada X stateviusal differnt, siempre vienen con un nuevo nombre para el guión gráfico):

<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>

Se puede imaginar fácilmente la cantidad de XAML hinchazón que tengo que copiar y pegar para todos aquellos DataTriggers trillón en repetidas ocasiones.

Sería genial para definir todo esto dispara una vez y aplicarlo a diferentes representaciones visuales del estado. ¿Cómo se resuelve algo como esto en WPF? Cualquier consejo?

¿Fue útil?

Solución 2

No parece haber ninguna buena solución XAML sólo a este problema general. Terminé de escribir mis propias propiedades adjuntas que definen todos los comportamientos de animación para un elemento dado. Algo como esto:

<DataTemplate>
   <!-- ...  -->
   <Rectangle Fill="Gray">
     <v:AnimationHelper.Animations>
        <v:StandardColorStateAnimation TargetColorProperty="(Rectangle.Fill).(SolidColorBrush.Color)" TargetStateProperty={Binding State} />
     </v:AnimationHelper.Animations>
   </Rectangle>
<DataTemplate>

El resto (la creación de la animación etc.) se realiza en el código subyacente.

Otros consejos

Podría intentar algo como esto?

  • Envuelva todas las plantillas de control de corriente con un elemento raíz invisible, por ejemplo, Un borde o un StackPanel, cuyo cuadro delimitador cubrirá todo el control.
  • Crea un estilo o una plantilla de control para esta caja invisible que contiene todos los factores desencadenantes y animaciones.
  • ¿Las animaciones animar una propiedad Color arbitrario en la caja invisible.
  • En los árboles visuales para todas sus diferentes controles, se unen las propiedades que desea animar a la propiedad Color en el elemento raíz invisible.

Me doy cuenta de este problema es un poco muerta en el momento de esta publicación, pero encontré una solución que requiere muy poco código atrás.

Se puede hacer una control de usuario con propiedades personalizadas (baje a alrededor de la Figura 8) que contiene su rectángulo, así como las animaciones y disparadores de estado. Este control de usuario definiría una propiedad pública como el estado que activaría el cambio de color cuando se alteran.

El único código subyacente se requiere es crear las variables en el código.

El control de usuario se les puede reutilizar una y otra vez sin reescribir el los storyboards XAML o datos activa.

La mayoría de los " XAML camino" para lograr este objetivo se me ocurre es crear MarkupExtension dedicado que se tire de la animación del diccionario de recursos y establecer las propiedades necesarias - Asumo que los están limitados a una subconjunto de Storyboard.Target, Storyboard.TargetName y Storyboard.TargetProperty. A pesar de que requiere un poco de código subyacente, que es el esfuerzo de una sola vez, por otra parte, MarkupExtensions están diseñados para ser utilizados con XAML . Aquí está la versión más simple:

[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");
    }
}

Su uso es muy sencillo:

<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>

Al ser tan simple como puede ser esta solución tiene sus limitaciones - que no admite ni extensiones ni Binding DynamicResource para las características antes mencionadas. Sin embargo, esto se puede lograr, pero requiere un poco de esfuerzo extra. Binding soporte debe ser bastante simple - una cuestión de uso adecuado de XamlSetMarkupExtensionAttribute  (Más algo de código repetitivo). apoyo DynamicResource sería un poco más complicado, y además de utilizar XamlSetMarkupExtensionAttribute requeriría envolver el IServiceProvider de retorno adecuado aplicación IProvideValueTarget , pero es todavía posible.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top