Question

J'ai créé une propriété de dépendance attachée pour les Storyboards, dans le but de me permettre d'appeler une méthode sur mon ViewModel lorsqu'un événement Storyboard Completed est déclenché:

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

alors j'essaie de l'utiliser en XAML, avec une syntaxe Binding:

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

Cela échoue avec l'exception suivante:

  

Exception System.Windows.Markup.XamlParseException   Message = " Impossible de convertir la valeur de l'attribut 'Style' en objet de type 'System.Windows.Style'. Impossible de geler cette arborescence de scénario de Storyboard pour une utilisation sur plusieurs threads. Erreur à l'objet 'labelHello' dans le fichier de balisage 'TestWpfApp; composant / window1.xaml'

Existe-t-il un moyen de faire en sorte que la syntaxe Binding fonctionne avec une propriété ICommand attachée pour un Storyboard?

Était-ce utile?

La solution 3

Pour résoudre ce problème, j'ai créé un ensemble de propriétés attachées, appelées Storyboard Helpers ( code source ici ). J'ai cessé d'essayer de les attacher au Storyboard lui-même, puis à tout élément de structure (arbitraire) pour appeler une ICommand sur mon ViewModel lorsque le storyboard est terminé, ainsi que la liaison à un événement particulier sur mon ViewModel pour lancer le Storyboard. . Une troisième propriété attachée spécifie le Storyboard avec lequel nous traitons:

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

Autres conseils

C’est quelque chose qui est voulu. Si vous avez un objet gelable qui est placé dans un style, le style sera gelé pour permettre un accès multithread. Mais votre liaison est essentiellement une expression, ce qui signifie qu’elle ne peut pas être gelée car la liaison de données est à thread unique.

Si vous avez besoin de le faire, placez le déclencheur en dehors du style sous un élément de cadre plutôt que dans un style. Vous pouvez le faire dans votre section Grid.Triggers. Cela craint un peu car votre style n’est plus terminé et vous devez dupliquer les déclencheurs, mais c’est un "par conception". fonctionnalité dans WPF.

La réponse complète sur les forums sociaux MSDN est ici .

Vous pouvez créer une nouvelle classe dérivée de Freezable pour lancer un story-board en tant que shim. Liez une propriété sur cet objet shim au nom du storyboard. De cette manière, vous n’aurez pas à dupliquer les déclencheurs ni à les stocker en dehors du style.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top