3

Storyboard Completedイベントが発生したときに、ViewModelのメソッドを呼び出せるようにするために、Storyboardsに添付された依存関係プロパティを作成しました。

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

次に、バインディング構文を使用して、XAMLで使用しようとします。

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

これは、次の例外で失敗します。

System.Windows.Markup.XamlParseExceptionが発生しましたMessage="属性'Style'の値をタイプ'System.Windows.Style'のオブジェクトに変換できません。スレッド間で使用するためにこのストーリーボードタイムラインツリーをフリーズできません。オブジェクト'labelHello'でエラーが発生しましたマークアップファイル'TestWpfApp;component / window1.xaml'

ストーリーボードに添付されたICommandプロパティを使用してBinding構文を機能させる方法はありますか?

4

3 に答える 3

1

これは設計上のものです。スタイルに入れられるフリーズ可能なオブジェクトがある場合、クロススレッド アクセスを許可するためにスタイルがフリーズされます。ただし、バインドは本質的に式であり、データ バインディングはシングル スレッドであるため、凍結することはできません。

これを行う必要がある場合は、スタイル内ではなく、フレームワーク要素の下のスタイルの外にトリガーを配置します。これは Grid.Triggers セクションで行うことができます。スタイルが完全ではなく、トリガーを複製する必要があるため、これは少し面倒ですが、これは WPF の「設計による」機能です。

MSDN ソーシャル フォーラムでの完全な回答はこちらです。

于 2009-09-18T12:43:22.253 に答える
0

この問題を回避するために、ストーリーボード ヘルパー (ソース コードはこちら) と呼ばれる一連の添付プロパティを作成しました。それらをストーリーボード自体にアタッチすることをあきらめ、ストーリーボードが完了したときに ViewModel で ICommand を呼び出すために任意の (任意の) フレームワーク要素にアタッチし、ViewModel の特定のイベントにバインドしてストーリーボードを起動します。 . 3 番目の添付プロパティは、扱うストーリーボードを指定します。

<FrameworkElement
   my:StoryboardHelpers.Storyboard="{StaticResource rightAnswerAnimation}"
   my:StoryboardHelpers.Completed="{Binding CompletedCommand}"
   my:StoryboardHelpers.BeginEvent="{Binding StartCorrectAnswer}" />
于 2009-10-06T14:51:22.723 に答える