0

I want to create an animated control which can fade in and out, triggered by a bool value. For this purpose I made a custom control 'FadeHeaderControl':

public class FadeHeaderControl : ContentControl
{
    public static readonly DependencyProperty IsAnimatedProperty = DependencyProperty.Register(
            "IsAnimated", typeof (bool), typeof (FadeHeaderControl), new FrameworkPropertyMetadata(default(bool)));

    public bool IsAnimated
    {
         get { return (bool) GetValue(IsAnimatedProperty); }
         set { SetValue(IsAnimatedProperty, value); }
    }

    static FadeHeaderControl()
    {
         DefaultStyleKeyProperty.OverrideMetadata(typeof(FadeHeaderControl), new FrameworkPropertyMetadata(typeof(FadeHeaderControl)));
    }
}

When the IsAnimated Dependency Property gets set to true (via Binding) the header should slide in (user notification that something has changed)

My MainWindow.xaml is here:

<Window.DataContext>
    <wpfApplication1:MainWindowViewModel/>
</Window.DataContext>
<StackPanel>
    <wpfApplication1:FadeHeaderControl x:Name="Myrect" VerticalAlignment="Top" IsAnimated="{Binding AnimationStarts}">
        <Grid Background="Chartreuse" Width="Auto">
            <Button Margin="10" HorizontalAlignment="Right">Button</Button>
        </Grid>
    </wpfApplication1:FadeHeaderControl> 

    <Button Margin ="50"  Command="{Binding TriggerAnimationCommand}">Change visibility</Button>
</StackPanel>

and the viewmodel:

public class MainWindowViewModel : ViewModelBase
{
    private bool _animationStarts;

    public bool AnimationStarts
    {
        get { return _animationStarts; }
        set
        {
            _animationStarts = value;
            RaisePropertyChanged(() => AnimationStarts);
        }
    }

    public ICommand TriggerAnimationCommand
    {
        get { return new RelayCommand(TriggerAnimation); }
    }

    private void TriggerAnimation()
    {
        AnimationStarts = !AnimationStarts;
    }
}

the problem comes now in the Style for FadeHeaderControl:

<ResourceDictionary>    
    <Storyboard x:Key="HeaderFadeInAnimation">
        <DoubleAnimation
            Storyboard.TargetProperty="Height" 
            From="0" 
            To="{Binding RelativeSource={RelativeSource AncestorType={x:Type wpfApplication1:FadeHeaderControl}}, Path=ActualHeight}" 
            Duration="0:0:0.5" 
            BeginTime="0:0:0" 
            />
    </Storyboard>

    <Storyboard x:Key="HeaderFadeOutAnimation">
        <DoubleAnimation
            Storyboard.TargetProperty="Height" 
            From="{Binding RelativeSource={RelativeSource AncestorType={x:Type wpfApplication1:FadeHeaderControl}}, Path=ActualHeight}" 
            To="0" 
            Duration="0:0:0.5" 
            BeginTime="0:0:0" 
            />
    </Storyboard>

    <Style TargetType="{x:Type wpfApplication1:FadeHeaderControl}" x:Shared="False">
        <Setter Property="IsAnimated" Value="False"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type wpfApplication1:FadeHeaderControl}">
                    <ContentPresenter x:Name="ContentPresenter" ContentSource="Content"></ContentPresenter>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsAnimated" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard Storyboard="{StaticResource HeaderFadeInAnimation}"/>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <BeginStoryboard Storyboard="{StaticResource HeaderFadeOutAnimation}"/>
                            </Trigger.ExitActions>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

How can I bind the 'To' or 'From' values of the double animation to the actual height of the FadeHeaderControl inside this style - or is this not possible because of the storyboard architecture. If I set the values to static numbers everything works like expected.

Should I replace the Trigger with an EventTrigger and create a RoutedEvent in my FadeHeaderControl?

Regards, and thanks for your help.

ProgrammingDude
  • 597
  • 1
  • 5
  • 25
patdhlk
  • 139
  • 3
  • 11
  • If you place only one element `From` or `To` the animation will start from actual `Height` of element. – bars222 Dec 17 '15 at 12:32
  • ok, this would be possible at the FadeOutAnimation, that it starts at actual height and animates back to 0 but not for FadeInAnimation. Because the double animation needs to know the end value to calculate the animation. Correct me if i am wrong – patdhlk Dec 17 '15 at 13:10
  • If the `Height` property of `Control` is set to 0 as default (I think it should be set for this control), you can write for `FadeInAnimation` To ="100" for example, and for `FadeOutAnimation` To ="0". Or you can use binding for end value, start value is not needed. Maybe I missing something, but it should work. – bars222 Dec 17 '15 at 13:17
  • if i doesn't use bindings, the animation works perfect. Using bindings fails in a xaml parse exception at application startup. InnerException: Cannot freeze this Storyboard timeline tree for use across threads. – patdhlk Dec 17 '15 at 13:29
  • Yes, you're right. Here http://stackoverflow.com/questions/2186933/wpf-animation-binding-to-the-to-attribute-of-storyboard-animation there are some info about it. – bars222 Dec 17 '15 at 13:44
  • I found that question but don't like the converter magic here and hoped to find a nicer approach – patdhlk Dec 17 '15 at 14:01

0 Answers0