views:

99

answers:

2

Consider the following simple WPF form, we will try to animate border1's Height:

alt text

This is the XAML for border1:

<Border Margin="3" BorderBrush="Black" BorderThickness="1" Name="border1">
    <Border.Style>
        <Style>
            <Setter Property="Control.Height" Value="50" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding X}" Value="1">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="100" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding X}" Value="2">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="200" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding X}" Value="3">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="300" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
    <TextBlock Text="{Binding X}" />
</Border>

X is a normal DependencyProperty and buttons do their work without problem and TextBlock's content inside border1 shows the changed value.

Now the problem is Height can be only Increased! For example by pressing 1, Height increases to 100, pressing 3 increases it to 300 but pressing 2 does not change the height.

If I set the initial border1's height to, for example, 400, all buttons can decrease it to 100, 200 or 300 but after this stage no animation can decrease border's height.

Am I missing some obvious point regarding WPF animation?

+2  A: 

Update

Part of the issue is the storyboard in the DataTrigger is not being stopped, so (the last DataTrigger defined) is always holding the Height's 'animated' value.

Adding a StopStoryboard in the exit action fixes part of it. You can now switch between all three heights again... but the animation always starts from the Height's base value (which is clearly not what you want). You want it to start from where it was last set at.

The following MSDN article explains the second issue pretty well: http://msdn.microsoft.com/en-us/library/aa970493.aspx

Good Solution-

EventTriggers on your three buttons seem to work better and doesn't have the problems that the DataTrigger encounters (plus you don't even need the dependency property 'X' anymore!)

<Border Margin="3" BorderBrush="Black" BorderThickness="1" Name="border1"> 
    <Border.Style> 
        <Style> 
            <Setter Property="Control.Height" Value="50" /> 
        </Style> 
    </Border.Style> 
    <TextBlock Text="{Binding X}" /> 
</Border> 

and

<StackPanel Orientation="Horizontal">
    <Button Content="1" Width="50">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="border1" Storyboard.TargetProperty="Height" To="100"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>
    <Button Content="2" Width="50">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="border1" Storyboard.TargetProperty="Height" To="200"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>
    <Button Content="3" Width="50">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="border1" Storyboard.TargetProperty="Height" To="300"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>
</StackPanel>
Scott
+1  A: 

There must be a simpler way to do this, but I cannot recall if there is at the moment.

Otherwise this will work. You can set the ExitAction of your triggers to set back to the default value. Do this by using a DoubleAnimation with no To value.

i.e.,

<DataTrigger Binding="{Binding X}" Value="1">
    <DataTrigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetProperty="Height" Duration="0:0:0.2" To="100" />
            </Storyboard>
        </BeginStoryboard>
    </DataTrigger.EnterActions>
    <DataTrigger.ExitActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetProperty="Height" Duration="0:0:0.2" />
            </Storyboard>
        </BeginStoryboard>
    </DataTrigger.ExitActions>
</DataTrigger>
Jeff M