9

次のコードを検討してください。

<UserControl x:Class="MyApp.MyControl"
             ...
         xmlns:local="clr-namespace:MyApp"
         DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">

    <UserControl.Template>
        <ControlTemplate>
            <ControlTemplate.Resources>
                <Storyboard x:Key="MyStory">
                    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
                        <SplineColorKeyFrame KeyTime="0:0:1" Value="Red"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </ControlTemplate.Resources>

            <Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
                ...
            </Border>

            <ControlTemplate.Triggers>
                <Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource MyStory}"/>
                    </Trigger.EnterActions>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

上記のコードは問題なく動作します。ここで、のキーフレーム値をこのユーザー コントロールのMyStoryDP (という名前) に次のようにバインドします。SpecialColor

<Storyboard x:Key="MyStory">
    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
        <SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
    </ColorAnimationUsingKeyFrames>
</Storyboard>

これはエラーになります:

複数のスレッドで使用するために、このストーリーボード タイムライン ツリーをフリーズすることはできません。

コードビハインドを使用してこれを行うことができます。しかし、どうすれば XAML だけでそれを行うことができますか?


コード ビハインド支援ソリューション:

►<em>ステップ 1:MyStoryストーリーボードをbrdBaseリソースに配置する。

<UserControl.Template>
    <ControlTemplate>
        <Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
            <Border.Resources>
                <Storyboard x:Key="MyStory">
                    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
                        <SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </Border.Resources>
            ...
        </Border>

        <ControlTemplate.Triggers>
            <Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard Storyboard="{StaticResource MyStory}"/>
                </Trigger.EnterActions>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
</UserControl.Template>

エラー: 「MyStory」という名前のリソースが見つかりません。リソース名は大文字と小文字が区別されます。

►<em>ステップ 2:プロパティを削除Triggerし、 from コードビハインドを開始します。IsMouseOverMyStory

<UserControl.Template>
    <ControlTemplate>
        <Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black" MouseEnter="brdBase_MouseEnter">
            <Border.Resources>
                <Storyboard x:Key="MyStory">
                    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
                        <SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </Border.Resources>
        </Border>
    </ControlTemplate>
</UserControl.Template>

C# コード ビハインド:

private void brdBase_MouseEnter(object sender, MouseEventArgs e)
{
   Border grdRoot = (Border)this.Template.FindName("brdBase", this);
   Storyboard story = grdRoot.Resources["MyStory"] as Storyboard;

   story.Begin(this, this.Template);
}

►<em>ステップ 3: ソリューションは既に完了していますが、最初は機能しません。幸いなことに、この問題には回避策があります。を に入れるだけで十分ControlTemplateですStyle

( 以外のTrigger型が必要で、要素を でEventTriggerラップする必要があります。)UserControlControlTemplate


アップデート:

使用するというアイデアはObjectDataProvider失敗しました。

  1. ObjectDataProviderリソースを使用してストーリーボードを提供することはできません!!! エラーレポートは次のとおりです。
    • XamlParseException:プロパティ 'System.Windows.Media.Animation.BeginStoryboard.Storyboard' を設定すると、例外がスローされました。
    • InnerException: 'System.Windows.Data.ObjectDataProvider' は、プロパティ 'Storyboard' の有効な値ではありません。
  2. AssociatedControl DPは常に null です。

コードは次のとおりです。

<UserControl.Template>
    <ControlTemplate>
        <ControlTemplate.Resources>
            <local:StoryboardFinder x:Key="StoryboardFinder1" AssociatedControl="{Binding ElementName=brdBase}"/>
            <ObjectDataProvider x:Key="dataProvider" ObjectInstance="{StaticResource StoryboardFinder1}" MethodName="Finder">
                <ObjectDataProvider.MethodParameters>
                    <sys:String>MyStory</sys:String>
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
        </ControlTemplate.Resources>

        <Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
            <Border.Resources>
                <Storyboard x:Key="MyStory">
                    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
                        <SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </Border.Resources>
            ...
        </Border>

        <ControlTemplate.Triggers>
            <Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard Storyboard="{StaticResource dataProvider}"/>
                </Trigger.EnterActions>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
</UserControl.Template>

StoryboardFinder クラス:

public class StoryboardFinder : DependencyObject
{
    #region ________________________________________  AssociatedControl

    public Control AssociatedControl
    {
        get { return (Control)GetValue(AssociatedControlProperty); }
        set { SetValue(AssociatedControlProperty, value); }
    }

    public static readonly DependencyProperty AssociatedControlProperty =
        DependencyProperty.Register("AssociatedControl",
                                    typeof(Control),
                                    typeof(StoryboardFinder),
                                    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None));

    #endregion

    public Storyboard Finder(string resourceName)
    {
        //
        // Associated control is always null :(
        //
        return new Storyboard();
    }
}
4

2 に答える 2

3

クロススレッドで効率的に作業するには、ストーリーボードを固定する必要があるため、実際には "To" にも From にもバインドできません。

解決策1)ハックなしの最も簡単な解決策 (コード ビハインドを含む): MouseOver イベント ハンドラー & をイベント ハンドラーに追加し、必要なアニメーションを見つけ、「To」プロパティを直接設定して、バインドを使用せず、「フリーズ」を実行できるようにします。 . このようにして、何もハードコードしません:)。

解決策 2) XAML のみをサポートするクールなハックがあります (もちろんコンバーター マジックは少しあります) が、私はお勧めしません。それにもかかわらず、それはクールです:) WPFアニメーション:ストーリーボードアニメーションの「To」属性へのバインディング ジェイソンによる回答を参照してください。

他にもいくつか試してみることができます:

解決策 3) Dependency プロパティを使用せずに、INotifyProperthChanged を実装します。このようにして、「To」をバインドできます。これは理論的には機能するはずですが、試していないことに注意してください。

Solution4)バインディングに Mode=OneTime を適用します。多分それは動作しますか?

解決策 5)正しいスレッドで依存関係プロパティを評価し、「To」プロパティを設定する、独自の添付動作を記述します。それは素晴らしい解決策になると思います。

ここにも良い複製があります:WPFアニメーション「このストーリーボードのタイムラインツリーをスレッド間で使用するためにフリーズできません」

于 2013-04-06T08:58:09.717 に答える