Pregunta

He creado una propiedad de dependencia adjunta para Storyboards, con la intención de permitirme llamar a un método en mi ViewModel cuando se activa un evento Storyboard Completed:

public static class StoryboardExtensions
{
    public static ICommand GetCompletedCommand(DependencyObject target)
    {
        return (ICommand)target.GetValue(CompletedCommandProperty);
    }

    public static void SetCompletedCommand(DependencyObject target, ICommand value)
    {
        target.SetValue(CompletedCommandProperty, value);
    }

    public static readonly DependencyProperty CompletedCommandProperty =
        DependencyProperty.RegisterAttached(
            "CompletedCommand",
            typeof(ICommand),
            typeof(StoryboardExtensions),
            new FrameworkPropertyMetadata(null, OnCompletedCommandChanged));

    static void OnCompletedCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        Storyboard storyboard = target as Storyboard;
        if (storyboard == null) throw new InvalidOperationException("This behavior can be attached to Storyboard item only.");
        storyboard.Completed += new EventHandler(OnStoryboardCompleted);
    }

    static void OnStoryboardCompleted(object sender, EventArgs e)
    {                        
        Storyboard item = ... // snip
        ICommand command = GetCompletedCommand(item);
        command.Execute(null);
    }
}

luego trato de usarlo en XAML, con una sintaxis de enlace:

<Grid>
    <Grid.Resources>
        <Storyboard x:Key="myStoryboard" my:StoryboardExtensions.CompletedCommand="{Binding AnimationCompleted}">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:5" />
        </Storyboard>

        <Style x:Key="myStyle" TargetType="{x:Type Label}">
            <Style.Triggers>
                <DataTrigger 
                 Binding="{Binding Path=QuestionState}" Value="Correct">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource myStoryboard}" />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    </Grid.Resources>
    <Label x:Name="labelHello" Grid.Row="0" Style="{StaticResource myStyle}">Hello</Label>
</Grid>

Esto falla con la siguiente excepción:

  

Se produjo System.Windows.Markup.XamlParseException   Mensaje = " No se puede convertir el valor en el atributo 'Estilo' al objeto de tipo 'System.Windows.Style'. No se puede congelar este árbol de línea de tiempo del Guión gráfico para usarlo en subprocesos Error en el objeto 'labelHello' en el archivo de marcado 'TestWpfApp; component / window1.xaml'

¿Hay alguna manera de hacer que la sintaxis de Binding funcione con una propiedad ICommand adjunta para un Storyboard?

¿Fue útil?

Solución 3

Para solucionar este problema, creé un conjunto de propiedades adjuntas, llamadas Storyboard Helpers ( código fuente aquí ). Dejé de tratar de adjuntarlos al Storyboard en sí, y ahora me adjunto a cualquier elemento del marco (arbitrario) para llamar a un ICommand en mi ViewModel cuando se completa el storyboard, así como vincularme a un evento particular en mi ViewModel para lanzar el Storyboard . Una tercera propiedad adjunta especifica el Storyboard con el que estamos tratando:

<FrameworkElement
   my:StoryboardHelpers.Storyboard="{StaticResource rightAnswerAnimation}"
   my:StoryboardHelpers.Completed="{Binding CompletedCommand}"
   my:StoryboardHelpers.BeginEvent="{Binding StartCorrectAnswer}" />

Otros consejos

Esto es algo por diseño. Si tiene un objeto congelable que se pone en un estilo, el estilo se congelará para permitir el acceso de hilos cruzados. Pero su enlace es esencialmente una expresión, lo que significa que no se puede congelar ya que el enlace de datos es de un solo subproceso.

Si necesita hacer esto, coloque el disparador fuera del estilo bajo un elemento de marco en lugar de en un estilo. Puede hacer esto en su sección Grid.Triggers. Esto apesta un poco ya que su estilo ya no está completo y tiene que duplicar los desencadenantes, pero es un `` por diseño ''. característica en WPF.

La respuesta completa en los foros sociales de MSDN es aquí .

Podría crear una nueva clase derivada de Freezable para lanzar un guión gráfico como una cuña. Enlace una propiedad en ese objeto de calce al nombre del guión gráfico. De esa manera, no tendrá que duplicar disparadores o almacenarlos fuera del estilo.

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