10

I'm trying to create an animation where an icon (a xaml vector graphic on a Viewbox-wrapped Canvas) goes from having its text (TextBlock) beside it to underneath it.

I currently have the Viewbox and TextBlock in a Horizontally oriented StackPanel. I can change the orientation to vertical, but this is an instant change (not smoothly animated). I can also just set the position of the TextBlock with a TranslateTransform (which can be animated), but this is difficult to do in a reusable way (i.e. without hard-coding values).

Can anyone tell me if there is any WPF-centric way to animate the transition from horizontal to vertical orientation in a stack-panel? Or another way I haven't thought of to achieve the desired effect?

Thanks all!

Nick W.
  • 1,050
  • 2
  • 9
  • 21
  • My gut tells me you're going to have to write some code to do some translate transforms, and it's not going to be pretty. Will be interesting to see if anyone comes up with a nice way. – Ray Jan 31 '11 at 11:52
  • Are you trying to place it in a certain area relational to the ViewBox...for instance you could always place it to the left and below the ViewBox regardless of the ViewBox size or...? – Aaron McIver Jan 31 '11 at 14:53
  • It might not achieve the *desired effect*, but a smoother way of animating this change, which may be less complicated to implement, could be to fade the text out and then back in when you change the StackPanel's orientation (using a `DataTrigger`, for example, and its Start-/EndActions, though I don't know how easily you can get the timing right...) – Dan J Jan 31 '11 at 22:11

1 Answers1

5

There is a feature in Blend called FluidLayout that can do this.

In Blend

  • Create a new state group, set a transition duration and enable fluid layout.
  • Create two states one for horizontal, one for vertical.
  • You can then use a behaviour to toggle between them.

If you don't have Blend you can download the SDK which should have the required files Microsoft.Expression.Interactions and System.Windows.Interactivity. Add references to these and try the sample below.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:il="clr-namespace:Microsoft.Expression.Interactivity.Layout;assembly=Microsoft.Expression.Interactions"
    xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
    x:Class="WpfApplication4.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640" Height="480">

    <Grid x:Name="LayoutRoot">
        <VisualStateManager.CustomVisualStateManager>
            <ic:ExtendedVisualStateManager/>
        </VisualStateManager.CustomVisualStateManager>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="Orientation" ic:ExtendedVisualStateManager.UseFluidLayout="True">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="00:00:00.3000000"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Vertical"/>
                <VisualState x:Name="Horizontal">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="stack" Storyboard.TargetProperty="(StackPanel.Orientation)">
                            <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Orientation.Horizontal}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <StackPanel x:Name="stack" Margin="8,49,8,8">
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
        </StackPanel>
        <Button HorizontalAlignment="Left" Margin="8,8,0,0" VerticalAlignment="Top" Width="97" Height="25" Content="H">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ic:GoToStateAction StateName="Horizontal"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button HorizontalAlignment="Left" Margin="109,8,0,0" VerticalAlignment="Top" Width="97" Height="25" Content="V">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ic:GoToStateAction StateName="Vertical"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</Window>

You can use a similar method to handle the item transition using states to move the elements or by changing Grid.Row,RowSpan,Col. You may need some code to tie everything together. I'm looking at a more elaborate sample I'll post if I sort out the issues.

Kris
  • 7,110
  • 2
  • 24
  • 26
  • This looks like a really nice way to do it. +1 – Rob Perkins Feb 07 '11 at 05:02
  • Wound up doing this effect by just manually creating animations for elements on a Canvas. Our project team isn't using Blend, so fluidlayout wasn't an option. – Nick W. Apr 15 '11 at 03:50
  • @Nick W.: If you end up finding an answer to a question yourself, please add it as an actual answer to the question and accept it (possibly with a reference to this answer for those who can use Blend) – H.B. Apr 15 '11 at 04:03