2009-10-31 14 views
13

xamlのどこかで(例えば、リソースとして)アニメーションを定義して、それを複数回再利用する方法はありますか?私は、データトリガーに基づいて同じ種類のアニメーションを独立して開始する必要がある、異なるデータ型の間に独立したブラシをたくさん持っています。アニメーションがStoryboard.TargetNameとStoryboard.TargetPropertyを定義しなければならないようだからです。これは、再利用性の目的をはるかに凌駕します。私はどういうわけか「このアニメーションをリソースとして使うが、今回は別の要素に適用する」と宣言したいと思うだろう。再利用可能なリソースとしてアニメーションとトリガを定義しますか?

私にとってこれは基本的で重要で不可欠な要求であると思われます。私はそれがまっすぐ進むことで功を奏してくれることを驚かせています。私はここに何かを逃していますか

トリガーにも同じことが適用されます。色アニメーションを使用して、すべて同じタイプの状態を表す多くの異なるビジュアル要素があるとします。例えば。ビジュアルツリーの唯一の違いは、目的のアニメーションの動作が同じであることです。ビジュアルツリーのどこかに要素があります。タイプcolorのプロパティ同じアニメーションやデータトリガーセットを何度も何度も再定義するのがいかに面倒なのか想像するのは難しくありません。すべての開発者はこれを嫌う。私は必死に、後ろにC#コードを必要としない簡単な解決策を模索しています。これは(活性化、アクティブ、非アクティブ、エラーのように、あることをすべての基本的な状態のためにこれを繰り返す)リク

がリソースにアニメーションを定義します:私は今のところ出ている何

はこれです

<ColorAnimationUsingKeyFrames x:Key="deactivatingColorAnimation" 
        Storyboard.TargetProperty="Material.(MaterialGroup.Children)[0].Brush.(SolidColorBrush.Color)"      
        FillBehavior="HoldEnd" RepeatBehavior="Forever" AutoReverse="True"> 
     <ColorAnimationUsingKeyFrames.KeyFrames> 
     <LinearColorKeyFrame KeyTime="00:00:00" Value="Gray"/> 
     <LinearColorKeyFrame KeyTime="00:00:0.25" Value="Gray"/> 
     <LinearColorKeyFrame KeyTime="00:00:0.5" Value="Gray" /> 
     <LinearColorKeyFrame KeyTime="00:00:0.75" Value="Gray" /> 
    </ColorAnimationUsingKeyFrames.KeyFrames> 
</ColorAnimationUsingKeyFrames> 

トリガでストーリーボードで使用すること(必ず、各状態Xの各differnt stateviusalのための時間のこの無数を繰り返してストーリーボードの新しい名前を思い付く):

<DataTrigger Binding="{Binding SubstrateHolder.State}" Value="Deactivating"> 
     <DataTrigger.EnterActions> 
      <BeginStoryboard x:Name="someStateVisualDeactivatingStoryboard"> 
       <Storyboard Storyboard.TargetName="someStateVisual"> 
        <StaticResource ResourceKey="deactivatingColorAnimation" /> 
       </Storyboard> 
      </BeginStoryboard> 
     </DataTrigger.EnterActions> 
     <DataTrigger.ExitActions> 
      <RemoveStoryboard BeginStoryboardName="someStateVisualDeactivatingStoryboard" /> 
     </DataTrigger.ExitActions> 
</DataTrigger> 

膨大な量の膨大なXAMLを、膨大な数のDataTriggerすべてに対して繰り返しコピーして貼り付けなければならないことを簡単に想像することができます。

このトリガをすべて一度定義し、それをさまざまな状態のビジュアルに適用することはクールです。これはWPFでどのように解決されますか?すべてのヒント?

答えて

1

この一般的なプロンプトに対して、優れたXAMLの解決策はありません。私は、与えられた要素のアニメーションの振る舞いをすべて定義する独自の添付プロパティを作成しました。このような何か:

<DataTemplate> 
    <!-- ... --> 
    <Rectangle Fill="Gray"> 
    <v:AnimationHelper.Animations> 
     <v:StandardColorStateAnimation TargetColorProperty="(Rectangle.Fill).(SolidColorBrush.Color)" TraggetSateProperty={Binding State} /> 
    </v:AnimationHelper.Animations> 
    </Rectangle> 
<DataTemplate> 

残り(アニメーションなどを作成)を分離コードで行われます。

+0

私は、これについての提案を思いつくためにさまざまなことを試したことを知っています。コードで何かをしなければ、それはできませんでした。これは私があなたが得ると思うほど良い解決策です。 WPF拡張性のためのHurray、右? :) –

+0

これにはSilverlightの動作APIを使用することをお勧めします。同意しますか?それは標準の.net 3.5フレームワークと互換性がありますか? – bitbonk

+0

いいえ、互換性がありません。正直なところ、WPFアーキテクチャを非常に「自然な」方法で活用する優れたソリューションが見つかったと思います。 –

3

あなたはこれを試すことができますか?

  • すべての現在のコントロールテンプレートを不可視のルート要素で囲みます。 BorderまたはStackPanelで、その境界ボックスはコントロール全体をカバーします。
  • トリガーとアニメーションをすべて含む、この不可視のボックスのスタイルまたはコントロールテンプレートを作成します。
  • アニメーションに不可視のボックスの任意の色プロパティをアニメートさせます。
  • すべての異なるコントロールのビジュアルツリーで、アニメーション化するプロパティを不可視のルート要素のColorプロパティにバインドします。
0

私は、この問題がこの投稿時には少し死んでいたことを認識していますが、コードをあまり必要としないソリューションが見つかりました。

長方形とアニメーションと状態トリガを含むUserControl with custom properties(図8を下にスクロールしてください)を作成できます。このユーザーコントロールは、変更時に色の変更を引き起こすステータスなどのパブリックプロパティを定義します。

必要なコードビハインドは、コードで変数を作成することだけです。

ユーザーコントロールは、XAMLストーリーボードまたはデータトリガーを書き換えることなく何度も何度も再利用できます。私はStoryboard.Targetのサブセットに限定されているものと仮定し、 -

0

私は考えることができる、この目標を達成するための最も「XAML方法は、」リソース辞書からアニメーションと設定し、必要なプロパティを引き上げる専用MarkupExtensionを作成することですStoryboard.TargetNameおよびStoryboard.TargetProperty。いくつかのコードビハインドが必要ですが、これは1回限りの作業であり、さらにMarkupExtensionXAMLと一緒に使用するように設計されています。ここでは最も簡単なバージョンがあります:

[MarkupExtensionReturnType(typeof(Timeline))] 
public class AnimationResourceExtension : StaticResourceExtension 
{ 
    //This property is for convienience so that we 
    //don't have to remember to set x:Shared="False" 
    //on all animation resources, but have an option 
    //to avoid redundant cloning if it is 
    public bool IsShared { get; set; } = true; 

    public DependencyObject Target { get; set; } 

    public string TargetName { get; set; } 

    public PropertyPath TargetProperty { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (base.ProvideValue(serviceProvider) is Timeline animation) 
     { 
      //If the animation is shared we shall clone it 
      //Checking if it is frozen is optional and we can 
      //either clone it or throw an exception 
      //(or simply proceed knowing one will be thrown anyway) 
      if (IsShared || animation.IsFrozen) 
       animation = animation.Clone(); 
      Storyboard.SetTarget(animation, Target); 
      Storyboard.SetTargetName(animation, TargetName); 
      Storyboard.SetTargetProperty(animation, TargetProperty); 
      return animation; 
     } 
     else 
      throw new XamlException("The referenced resource is not an animation"); 
    } 
} 

使い方は非常に簡単です:それは、この解決策になることができますような単純なビーイング

<FrameworkElement.Resources> 
    <DoubleAnimation x:Key="MyAnimation" From="0" To="1" Duration="0:0:1" /> 
</FrameworkElement.Resources> 
(...) 
<Storyboard> 
    <utils:AnimationResource ResourceKey="MyAnimation" TargetName="SomeElement" TargetProperty="Opacity" /> 
</Storyboard> 

は限界がある - それは、前述の特性のためでもないBindingDynamicResourceの拡張機能をサポートしていません。しかしこれは達成可能ですが、いくらか余分な努力が必要です。 Bindingのサポートは、かなり簡単です - XamlSetMarkupExtensionAttribute (およびいくつかの定型コードを使用)の適切な使用の質問。 DynamicResourceのサポートはやや厄介で、XamlSetMarkupExtensionAttributeの使用に加えて、IServiceProviderを適切なIProvideValueTargetの実装に戻すように折り返す必要がありますが、それでも可能です。

関連する問題