2011-05-26 17 views
8

Estoy construyendo algunos controles WPF con .Net 4.0. Uno de estos controles, llamado LoadingPane, es un control personalizado derivado de ContentControl. El único trabajo de este control LoadingPane es mostrar una capa semitransparente sobre su contenido cuando su propiedad IsLoading está establecida en verdadero. Uso algunas animaciones para hacer el fundido de entrada y el fundido de salida cuando cambia el valor de IsLoading. Cuando se muestra la superposición, una animación gira un círculo de elipses.La animación WPF se inicia pero se muestra demasiado tarde

Hasta ahora, todo bien. Todo esto funciona muy bien. Pero aquí está mi problema: cuando configuro la propiedad Cargando como verdadera, la animación no se muestra directamente. Tarda aproximadamente medio segundo. En este momento, la animación de fundido de entrada ya se ha ejecutado, por lo que la opacidad pasa efectivamente de 0 a 1 en un solo paso.

Aquí está mi código de animación:

<ControlTemplate.Triggers> 
    <Trigger Property="IsLoading" 
      Value="True"> 
     <Trigger.EnterActions> 
      <RemoveStoryboard BeginStoryboardName="EndAnimateLoadingCanvas" /> 
      <BeginStoryboard Name="AnimateLoadingCanvas"> 
       <Storyboard FillBehavior="Stop"> 
        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" 
                Storyboard.TargetName="MyViewBoxje" 
                Storyboard.TargetProperty="Visibility"> 
         <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" /> 
        </ObjectAnimationUsingKeyFrames> 

        <DoubleAnimation BeginTime="00:00:00" 
            Duration="00:00:00.5" 
            Storyboard.TargetName="MyViewBoxje" 
            Storyboard.TargetProperty="Opacity" 
            To="1" /> 

        <DoubleAnimation BeginTime="00:00:00" 
            Duration="00:00:02" 
            Storyboard.TargetName="AnimatedRotateTransform" 
            Storyboard.TargetProperty="Angle" 
            From="360" 
            To="0" 
            RepeatBehavior="Forever" /> 

       </Storyboard> 
      </BeginStoryboard> 
     </Trigger.EnterActions> 
     <Trigger.ExitActions> 
      <RemoveStoryboard BeginStoryboardName="AnimateLoadingCanvas" /> 
      <BeginStoryboard Name="EndAnimateLoadingCanvas"> 
       <Storyboard FillBehavior="Stop"> 
        <DoubleAnimation BeginTime="00:00:00" 
            Duration="00:00:00.5" 
            Storyboard.TargetName="MyViewBoxje" 
            Storyboard.TargetProperty="Opacity" 
            To="0" /> 
        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00.5" 
                Storyboard.TargetName="MyViewBoxje" 
                Storyboard.TargetProperty="Visibility"> 
         <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" /> 
        </ObjectAnimationUsingKeyFrames> 

       </Storyboard> 
      </BeginStoryboard> 
     </Trigger.ExitActions> 
    </Trigger> 
</ControlTemplate.Triggers> 

Lo extraño es que, cuando se utiliza este control en una ventana de prueba y que haga clic en la casilla de verificación de carga en repetidas ocasiones (y antes de la animación ha terminado), el desvanecimiento La animación in/fade-out funciona como espero que funcione.

¿Alguien puede ayudar? Gracias por adelantado!

+0

Tuve este mismo problema (aunque bajo una circunstancia diferente). Una animación que tuve que se ejecutó cuando se cargó una aplicación de Silverlight nunca mostró la animación la * primera * vez. Pero las cargas posteriores a partir de entonces funcionaron. Terminar y volver a iniciar la aplicación obtendría el mismo comportamiento. Nunca encontré una respuesta, así que +1 =) – Smudge202

+0

Bounty agregado, tal vez podamos obtener una respuesta de esa manera. En esencia, creo que la pregunta es cómo evitar que se salten las animaciones de carga, preferiblemente sin alguna forma de solución que imponga un evento de temporizador de bloqueo por primera vez. – Smudge202

+0

+1 como Mancha. Tener los mismos problemas con SL. –

Respuesta

0

finalmente lo he descubierto después de leer la respuesta de Isak. Lamento decir que su respuesta no ayudó en mi caso, pero me ayudó a ir en la dirección correcta.

La razón por la que el primer fade-in no pareció funcionar fue porque mi viewbox conteniendo su visibilidad se colapsó todo el tiempo que se realizó la animación de fade-in. Esto fue causado por el ObjectAnimationUsingKeyFrames:

DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" /> 
</ObjectAnimationUsingKeyFrames> 

No hubo tiempo especificado y el marco de una sola tecla especificada fue animada demasiado tarde.

Adición

Duration="00:00:00" 

resuelto mi problema.

Gracias a todos ustedes ayudando!

+1

Ese no fue el caso para mí, así que, aunque entenderé que marcan su propia respuesta como respuesta, otorgaré la recompensa a Isak por su ejemplo completo que parece funcionar y servirá como una buena referencia si tengo este mismo problema en el futuro. – Smudge202

3

Es difícil ver exactamente cuál es el problema sin ver el resto del código, pero supongo que tiene que ver con los valores de inicio de las propiedades animadas.

Implementé un control personalizado en WPF con un rectángulo dentro de una caja de vista y usé los disparadores + guiones gráficos de la pregunta para ver el efecto. De hecho, mi primer intento no se desvaneció ni se desvaneció.

Lo que hice para resolver era especificando From valores en las animaciones para que funcionen independientemente de lo que fuera el valor original de la DP:

<DoubleAnimation BeginTime="00:00:00" 
     Duration="00:00:00.5" 
     Storyboard.TargetName="MyViewBoxje" 
     Storyboard.TargetProperty="Opacity" 
     From="0" 
     To="1" /> 

Aviso From="0" en la animación anterior. El guión gráfico final se modificó de la misma manera, para pasar de 1 a 0.

Para completar la definición, establecí la opacidad en 0 en la definición del elemento viewbox dentro de ControlTemplate.


Aquí está el código fuente completo para las piezas relevantes. El control es un control personalizado estándar de WPF que hereda de Control. Tiene una sola propiedad de dependencia llamada IsLoading (bool) que por defecto es false:

public bool IsLoading 
{ 
    get { return (bool)GetValue(IsLoadingProperty); } 
    set { SetValue(IsLoadingProperty, value); } 
} 

// Using a DependencyProperty as the backing store for IsLoading. This enables animation, styling, binding, etc... 
public static readonly DependencyProperty IsLoadingProperty = 
     DependencyProperty.Register("IsLoading", typeof(bool), typeof(LoadingControl), new UIPropertyMetadata(false)); 

ControlTemplate - Definido en generic.xaml en el estilo de {x:Type local:LoadingControl}

<ControlTemplate TargetType="{x:Type local:LoadingControl}"> 
    <ControlTemplate.Triggers> 
     <Trigger Property="IsLoading" Value="True"> 
      <Trigger.EnterActions> 
       <RemoveStoryboard BeginStoryboardName="EndAnimateLoadingCanvas" /> 
       <BeginStoryboard Name="AnimateLoadingCanvas"> 
        <Storyboard FillBehavior="Stop"> 
         <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" 
            Storyboard.TargetName="MyViewBoxje" 
            Storyboard.TargetProperty="Visibility"> 
          <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" /> 
         </ObjectAnimationUsingKeyFrames> 

         <DoubleAnimation BeginTime="00:00:00" 
            Duration="00:00:00.5" 
            Storyboard.TargetName="MyViewBoxje" 
            Storyboard.TargetProperty="Opacity" 
            From="0" 
            To="1" /> 

         <DoubleAnimation BeginTime="00:00:00" 
             Duration="00:00:02" 
             Storyboard.TargetName="AnimatedRotateTransform" 
             Storyboard.TargetProperty="Angle" 
             From="360" 
             To="0" 
             RepeatBehavior="Forever" /> 

        </Storyboard> 
       </BeginStoryboard> 
      </Trigger.EnterActions> 
      <Trigger.ExitActions> 
       <RemoveStoryboard BeginStoryboardName="AnimateLoadingCanvas" /> 
       <BeginStoryboard Name="EndAnimateLoadingCanvas"> 
        <Storyboard FillBehavior="Stop"> 
         <DoubleAnimation BeginTime="00:00:00" 
             Duration="00:00:00.5" 
             Storyboard.TargetName="MyViewBoxje" 
             Storyboard.TargetProperty="Opacity" 
             From="1" 
             To="0" /> 
         <ObjectAnimationUsingKeyFrames BeginTime="00:00:00.5" 
            Storyboard.TargetName="MyViewBoxje" 
            Storyboard.TargetProperty="Visibility"> 
          <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" /> 
         </ObjectAnimationUsingKeyFrames> 

        </Storyboard> 
       </BeginStoryboard> 
      </Trigger.ExitActions> 
     </Trigger> 
    </ControlTemplate.Triggers> 

    <Border Background="{TemplateBinding Background}" 
      BorderBrush="{TemplateBinding BorderBrush}" 
      BorderThickness="{TemplateBinding BorderThickness}"> 
     <Viewbox x:Name="MyViewBoxje" Opacity="0"> 
      <!-- BG with 0x50 alpha so that it's translucent event at 100% visibility --> 
      <Grid Width="100" Height="100" Background="#50000000"> 
       <Rectangle Width="70" Height="20" Fill="Green" Stroke="Black" StrokeThickness="2" RenderTransformOrigin="0.5,0.5"> 
        <Rectangle.RenderTransform> 
         <RotateTransform Angle="360" x:Name="AnimatedRotateTransform" /> 
        </Rectangle.RenderTransform> 
       </Rectangle> 
      </Grid> 
     </Viewbox> 
    </Border> 
</ControlTemplate> 

he usado en mi ventana principal como lo siguiente:

<Grid x:Name="LayoutRoot"> 
    <!-- All other stuff here ... --> 

    <my:LoadingControl IsLoading="{Binding IsLoading}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> 
</Grid> 

Y para probarlo tuve un ViewModel con una propiedad IsLoading configurada como DataContext para la ventana principal.Y en el constructor del modelo de vista me puse a IsLoading verdadera y luego iniciar un temporizador que activa o desactiva el valor de la propiedad cada 5 segundos:

public MainWindowViewModel() 
{ 
    IsLoading = true; 
    DispatcherTimer t = new DispatcherTimer(); 
    t.Interval = TimeSpan.FromSeconds(5); 
    t.Tick += (s, e) => IsLoading = !IsLoading; 
    t.Start(); 
} 
+0

Parece un ganador, aunque si no te importa publicar todo lo que sería un as. El proyecto Silverlight fallé con (ref un comentario en el OP) que hace mucho tiempo que perdí. Tal vez @Elad Katz puede confirmar también? =) – Smudge202

+0

Se ha agregado el código –

+0

Gracias Isak, esta será una referencia práctica en el futuro. Voy a otorgar generosidad una vez que me lo permita. – Smudge202

Cuestiones relacionadas