2011-11-22 8 views
11

Expanderコントロール用に独自のテンプレートを作成しようとしています。コントロールが展開されると、コンテンツをゆっくりとスライドさせたいと思います。WPFで「スライドダウン」アニメーションを達成

コンテンツの望ましい高さはコンパイル時には分かりません。

私たちはダウンアニメーションのようにスライドを定義すると考えていた:

<Storyboard x:Key="ExpandContent"> 

    <DoubleAnimation 
     Storyboard.TargetName="_expanderContent" 
     Storyboard.TargetProperty="Height" 
     From="0.0" 
     To="{Binding ElementName=_expanderContent,Path=DesiredHeight}" 
     Duration="0:0:1.0" /> 
</Storyboard> 

しかし、残念ながらありません。エラーが発生する

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

アニメーションパラメータを定義するときにバインディングを使用することはできないようです。 (this questionでも議論されています)

私はこれにどのようにアプローチすることができますか? LayoutTransform.ScaleYを使用することには慎重です。歪んだ画像が作成されるからです。

これはthis questionと似ていますが、この質問にはコードビハインドの記述が含まれていますが、これは制御テンプレートでは不可能だと思います。 XAMLベースのソリューションが実現可能かどうか疑問に思っています。


私のコントロールテンプレートの現在の状態は次のとおりです。

<ControlTemplate x:Key="ExpanderControlTemplate" TargetType="{x:Type Expander}"> 
    <ControlTemplate.Resources> 
      <!-- Here are the storyboards which don't work --> 
      <Storyboard x:Key="ExpandContent"> 

       <DoubleAnimation 
        Storyboard.TargetName="_expanderContent" 
        Storyboard.TargetProperty="Height" 
        From="0.0" 
        To="{Binding ElementName=_expanderContent,Path=DesiredHeight}" 
        Duration="0:0:1.0" /> 
      </Storyboard> 
      <Storyboard x:Key="ContractContent"> 

       <DoubleAnimation 
        Storyboard.TargetName="_expanderContent" 
        Storyboard.TargetProperty="Height" 
        From="{Binding ElementName=_expanderContent,Path=DesiredHeight}" 
        To="0.0" 
        Duration="0:0:1.0" /> 

      </Storyboard> 
     </ControlTemplate.Resources> 
    <Grid Name="MainGrid" Background="White"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Name="ContentRow" Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*" /> 
     </Grid.ColumnDefinitions> 
     <Border> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*" /> 
        <ColumnDefinition Width="Auto" /> 
       </Grid.ColumnDefinitions> 
       <ContentPresenter ContentSource="Header" /> 
       <ToggleButton Template="{StaticResource ProductButtonExpand}" 
           Grid.Column="1" 
           IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" 
           /> 
       <Rectangle Grid.ColumnSpan="2" Fill="#FFDADADA" Height="1" Margin="8,0,8,2" VerticalAlignment="Bottom"/> 

      </Grid> 
     </Border> 

      <ContentPresenter Grid.Row="1" HorizontalAlignment="Stretch" Name="_expanderContent"> 

      </ContentPresenter> 

    </Grid> 
    <ControlTemplate.Triggers> 
     <Trigger Property="IsExpanded" Value="True"> 
      <Setter TargetName="_expanderContent" Property="Height" Value="{Binding ElementName=_expanderContent,Path=DesiredHeight}" /> 

       <!-- Here is where I would activate the storyboard if they did work --> 
       <Trigger.EnterActions> 
       <!--<BeginStoryboard Storyboard="{StaticResource ExpandContent}"/>--> 
      </Trigger.EnterActions> 
       <Trigger.ExitActions> 
        <!--<BeginStoryboard x:Name="ContractContent_BeginStoryboard" Storyboard="{StaticResource ContractContent}"/>--> 
       </Trigger.ExitActions> 
     </Trigger> 
      <Trigger Property="IsExpanded" Value="False"> 

       <Setter TargetName="_expanderContent" Property="Height" Value="0" /> 
      </Trigger> 
     </ControlTemplate.Triggers> 

</ControlTemplate> 
+1

なぜ「To」と「From」をDesiredHightに設定するのですか?それらを設定しないと、とにかく自動的に行われます。 – icebat

答えて

5

あなたは幸運であるInteractionsFluidLayoutBlend 4 SDK)で使用できる場合には、それはそれらの空想アニメーションもののために非常に便利です。

まず0にコンテンツCPの高さを設定します。

<ContentPresenter Grid.Row="1" 
    HorizontalAlignment="Stretch" 
    x:Name="_expanderContent" 
    Height="0"/> 

これをアニメーション化するには、Heightだけで展開された状態(非離散アニメーションがあなたをできないだろう表しVisualStateNaNにアニメーションする必要がありますNaN)を使用します。

xmlns:is="http://schemas.microsoft.com/expression/2010/interactions" 
<Grid x:Name="MainGrid" Background="White"> 
    <VisualStateManager.CustomVisualStateManager> 
     <is:ExtendedVisualStateManager/> 
    </VisualStateManager.CustomVisualStateManager> 
    <VisualStateManager.VisualStateGroups> 
     <VisualStateGroup x:Name="ExpansionStates" is:ExtendedVisualStateManager.UseFluidLayout="True"> 
      <VisualStateGroup.Transitions> 
       <VisualTransition GeneratedDuration="0:0:1"/> 
      </VisualStateGroup.Transitions> 
      <VisualState x:Name="Expanded"> 
       <Storyboard> 
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" 
                Storyboard.TargetName="_expanderContent"> 
         <DiscreteDoubleKeyFrame KeyTime="0" Value="NaN"/> 
        </DoubleAnimationUsingKeyFrames> 
       </Storyboard> 
      </VisualState> 
      <VisualState x:Name="Collapsed"/> 
     </VisualStateGroup> 
    </VisualStateManager.VisualStateGroups> 
    <!-- ... ---> 

それがすべて必要なはずですが、流体レイアウトはそこからあなたのための移行を作成します。


あなたはコードビハインドソリューション罰金だろうしている場合、あなたも、このような辞書でコードビハインドを使用することができます。

<!-- TestDictionary.xaml --> 
<ResourceDictionary x:Class="Test.TestDictionary" 
        ...> 
//TestDictionary.xaml.cs 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 

namespace Test 
{ 
    partial class TestDictionary : ResourceDictionary 
    { 
     //Handlers and such here 
    } 
} 
+0

この解決策はうまくいきません。 NaNは依然として不満を抱いています。 –

+0

@ChrisBordeman:まあ、私はこれが書面の時に働いたと確信しています... –

4

これは古いの一種でありますこれは今日の問題ですが、私は解決策を投稿する価値があると思います。

グリッド行の高さプロパティをアニメーション化する必要がありました下に移動します)、行が以前と同じ位置に再びスライドするように動的バインディングが必要でした。

私はこの答えは(無意味XAMLを戦った後で)非常に有用であることが判明: http://go4answers.webhost4life.com/Question/found-solution-work-protected-override-190845.aspx

は時々、コードビハインドで物事を行うだけで簡単です:

 Storyboard sb = new Storyboard(); 

     var animation = new GridLengthAnimation 
     { 
       Duration = new Duration(500.Milliseconds()), 
       From = this.myGridRow.Height, 
       To = new GridLength(IsGridRowVisible ? GridRowPreviousHeight : 0, GridUnitType.Pixel) 
     }; 

     // Set the target of the animation 
     Storyboard.SetTarget(animation, this.myGridRow); 
     Storyboard.SetTargetProperty(animation, new PropertyPath("Height")); 

     // Kick the animation off 
     sb.Children.Add(animation); 
     sb.Begin(); 

GridLengthAnimationクラスを見つけることができますここでは: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/da47a4b8-4d39-4d6e-a570-7dbe51a842e4/

+1

ありがとうございました!最後に、パラメータ化されたアニメーションを作成しました。確かにXAMLでは不可能と思われます。 –

+0

これは助けてくれてうれしいです。 WPFのどの項目がXAMLで処理するのが面倒であるかを知るにはしばらく時間がかかります; –

+2

素敵な作業です!同じことをするために必要なすべてのXAMLトリッキーよりずっと簡単です。すべてのMVVMの「コードなし」の狂気には、これがすべてのUI専用コードです。これを乗り越えてください。 –

0

すぐに使用できるXAML専用ソリューションがあります。on CodeProject

スタイル:

<local:MultiplyConverter x:Key="MultiplyConverter" /> 
    <Style TargetType="Expander" x:Key="VerticalSlidingEmptyExpander"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type Expander}"> 
        <ScrollViewer x:Name="ExpanderContentScrollView" 
        HorizontalScrollBarVisibility="Hidden" 
        VerticalScrollBarVisibility="Hidden" 
        HorizontalContentAlignment="Stretch" 
        VerticalContentAlignment="Top" 
        > 
         <ScrollViewer.Tag> 
          <system:Double>0.0</system:Double> 
         </ScrollViewer.Tag> 
         <ScrollViewer.Height> 
          <MultiBinding Converter="{StaticResource MultiplyConverter}"> 
           <Binding Path="ActualHeight" ElementName="ExpanderContent"/> 
           <Binding Path="Tag" RelativeSource="{RelativeSource Self}" /> 
          </MultiBinding> 
         </ScrollViewer.Height> 
         <ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/> 
        </ScrollViewer> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsExpanded" Value="True"> 
          <Trigger.EnterActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation 
         Storyboard.TargetName="ExpanderContentScrollView" 
         Storyboard.TargetProperty="Tag" 
         To="1" 
         Duration="0:0:0.2"/> 
            </Storyboard> 
           </BeginStoryboard> 
          </Trigger.EnterActions> 
          <Trigger.ExitActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation 
         Storyboard.TargetName="ExpanderContentScrollView" 
         Storyboard.TargetProperty="Tag" 
         To="0" 
         Duration="0:0:0.2"/> 
            </Storyboard> 
           </BeginStoryboard> 
          </Trigger.ExitActions> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
    <Style TargetType="Expander" x:Key="HorizontalSlidingEmptyExpander"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type Expander}"> 
        <ScrollViewer x:Name="ExpanderContentScrollView" 
        HorizontalScrollBarVisibility="Hidden" 
        VerticalScrollBarVisibility="Hidden" 
        HorizontalContentAlignment="Left" 
        VerticalContentAlignment="Stretch" 
        > 
         <ScrollViewer.Tag> 
          <system:Double>0.0</system:Double> 
         </ScrollViewer.Tag> 
         <ScrollViewer.Width> 
          <MultiBinding Converter="{StaticResource MultiplyConverter}"> 
           <Binding Path="ActualWidth" ElementName="ExpanderContent"/> 
           <Binding Path="Tag" RelativeSource="{RelativeSource Self}" /> 
          </MultiBinding> 
         </ScrollViewer.Width> 
         <ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/> 
        </ScrollViewer> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsExpanded" Value="True"> 
          <Trigger.EnterActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation 
         Storyboard.TargetName="ExpanderContentScrollView" 
         Storyboard.TargetProperty="Tag" 
         To="1" 
         Duration="0:0:0.2"/> 
            </Storyboard> 
           </BeginStoryboard> 
          </Trigger.EnterActions> 
          <Trigger.ExitActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation 
         Storyboard.TargetName="ExpanderContentScrollView" 
         Storyboard.TargetProperty="Tag" 
         To="0" 
         Duration="0:0:0.2"/> 
            </Storyboard> 
           </BeginStoryboard> 
          </Trigger.ExitActions> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

MultiplyConverter:

public class MultiplyConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, 
      object parameter, CultureInfo culture) 
    { 
     double result = 1.0; 
     for (int i = 0; i < values.Length; i++) 
     { 
      if (values[i] is double) 
       result *= (double)values[i]; 
     } 

     return result; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, 
      object parameter, CultureInfo culture) 
    { 
     throw new Exception("Not implemented"); 
    } 
} 

私は水平方向と垂直方向のバージョンを持っているスタイルを複製してトグルボタンを省略していますが、簡単にオリジナルのポストからそれを得ることができます。

+0

このソリューションの問題を使用すると、ボタンを切り替えることなく、ヘッダーをまったく使用しない – igorGIS

関連する問題