Simon
Simon

Reputation: 1312

WPF Binding (Storyboard)

I want to make a kind of custom ListView in WPF. It consists of a Header and a stack panel which contains all entries. I want to be able to minimize the ListView, so I added a little Triangle before the header that triggers an Storyboard. This should minimize/maximize the Listview. Anything works well except that I don't have a static height. So in my Storyboard I can't set a Keyframe with a specific static Value. I tried a Binding with a custom converter that adds to the height of the stack panel the height of the header. But it seems like it always returns "0".

My current code:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:GenericWPF="clr-namespace:GenericWPF"
    mc:Ignorable="d"
    x:Class="Vertretungsplan.UserElements.VertretungsPlan"
    x:Name="UserControl" Width="824" SizeChanged="VertretungsPlan_OnSizeChanged" Height="40">
    <UserControl.Resources>
        <GenericWPF:AddValueConverter x:Key="AddConverter"/>

        <Style x:Key="HeaderTextBlockLinkStyle" TargetType="{x:Type TextBlock}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Foreground" Value="#FF3C66C1"/>
                </Trigger>
            </Style.Triggers>
            <Setter Property="TextWrapping" Value="NoWrap"/>
            <Setter Property="TextTrimming" Value="None"/>
        </Style>
        <Storyboard x:Key="Maximize">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="UserControl">
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="900"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="NotExpandedTriangle">
                <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="ExpandedTriangle">
                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.995"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="NotExpandedTriangle">
                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:0.7" Value="{x:Static Visibility.Hidden}"/>
            </ObjectAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ExpandedTriangle">
                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="{x:Static Visibility.Visible}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="{x:Static Visibility.Visible}"/>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="Minimize">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="UserControl">
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="40"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ExpandedTriangle">
                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:0.7" Value="{x:Static Visibility.Visible}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="{x:Static Visibility.Hidden}"/>
            </ObjectAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="ExpandedTriangle">
                <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="NotExpandedTriangle">
                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="NotExpandedTriangle">
                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="{x:Static Visibility.Visible}"/>
                <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="{x:Static Visibility.Visible}"/>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>
    <UserControl.Triggers>
        <EventTrigger RoutedEvent="UIElement.MouseDown" SourceName="NotExpandedTriangle">
            <BeginStoryboard x:Name="Maximize_BeginStoryboard" Storyboard="{StaticResource Maximize}"/>
        </EventTrigger>
        <EventTrigger RoutedEvent="UIElement.MouseDown" SourceName="ExpandedTriangle">
            <BeginStoryboard x:Name="Minimize_BeginStoryboard" Storyboard="{StaticResource Minimize}"/>
        </EventTrigger>
    </UserControl.Triggers>

    <Grid x:Name="LayoutRoot" Height="Auto">
        <TextBlock x:Name="Header" TextWrapping="Wrap" VerticalAlignment="Top" Margin="60,10,10,0" TextAlignment="Center" FontSize="20" FontWeight="Bold" MouseDown="Header_MouseDown" Style="{DynamicResource HeaderTextBlockLinkStyle}" Cursor="Hand"><Run Text="XX.XX.XXXX XXXXXXX, Woche X"/></TextBlock>
        <StackPanel x:Name="RowStackPanel" Margin="0,41.6,0,0" MinHeight="100"/>
        <Path x:Name="NotExpandedTriangle" Data="M0,0 L26,26 0,26 z" Fill="Black" HorizontalAlignment="Left" Height="20" Margin="10,12.5,0,0" Stretch="Fill" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="0" VerticalAlignment="Top" Width="20" RenderTransformOrigin="0.5,0.5" >
            <Path.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="-134.855"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Path.RenderTransform>
        </Path>
        <Path x:Name="ExpandedTriangle" Data="M0,0 L26,26 0,26 z" Fill="Black" HorizontalAlignment="Left" Height="20" Margin="10,12.5,0,0" Stretch="Fill" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="0" VerticalAlignment="Top" Width="20" RenderTransformOrigin="0.5,0.5" Opacity="0" Visibility="Hidden" >
            <Path.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="-44.898"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Path.RenderTransform>
        </Path>
    </Grid>

</UserControl>

Please help me out how I can get a dynamic Value for the Keyframe that represents the total Heigth of the stackPanel + the Header + Spacing. Thanks!

Upvotes: 0

Views: 702

Answers (1)

Gavin Lanata
Gavin Lanata

Reputation: 366

It's possible to set the value of that key frame from code.

At a point you feel is best, possibly via the SizeChanged event, search for the storyboard in the resources. I have code that looks something like the following...

maximizeStoryboard = (Storyboard)FindResource("Maximize");

After you have that you can grab the timeline collection from its Children. And the first child in your case will be

<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="UserControl">
    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="900"/>
</DoubleAnimationUsingKeyFrames>

Once you have that, you can gain access to the key frames via the DoubleAnimationUsingKeyFrames property KeyFrames. Which again is a collection. As you only have one EasingDoubleKeyFrame, grab a hold of that one frame and from that you can set its value via its Value property.

Hope this helps.

Upvotes: 1

Related Questions