Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ControlTemplate Storyboard color animation problem

I have a problem with color animation. This is my source:

 <Window.Resources>
    <hedit:BrushToColorConverter x:Key="BrushToColorConverter" />
    <Style x:Key="MyButtonStyle" TargetType="Button">
        <Setter Property="OverridesDefaultStyle" Value="True"/>
        <Setter Property="Margin" Value="5"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <ControlTemplate.Resources>
                        <Storyboard x:Key="buttonAnimIn">
                            <!-- Problem line -->
                            <ColorAnimation Storyboard.TargetName="bntBack" Storyboard.TargetProperty="Color" To="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource BrushToColorConverter}}" />
                        </Storyboard>
                        <Storyboard x:Key="buttonAnimOut">
                            <ColorAnimation Storyboard.TargetName="bntBack" Storyboard.TargetProperty="Color" To="Blue" />
                        </Storyboard>
                        <Storyboard x:Key="buttonAnimForegroundIn">
                            <ColorAnimation Storyboard.TargetName="btnFore" Storyboard.TargetProperty="Color" To="Blue" />
                        </Storyboard>
                        <Storyboard x:Key="buttonAnimForegroundOut">
                            <ColorAnimation Storyboard.TargetName="btnFore" Storyboard.TargetProperty="Color" To="Red" />
                        </Storyboard>
                    </ControlTemplate.Resources>
                    <Border Name="border" 
                        BorderThickness="1"
                        Padding="4,2" 
                        BorderBrush="DarkGray" 
                        CornerRadius="3">
                        <Border.Background>
                            <SolidColorBrush Color="Blue" x:Name="bntBack" />
                        </Border.Background>
                        <ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}">
                            <ContentControl.Foreground>
                                <SolidColorBrush Color="Red" x:Name="btnFore" />
                            </ContentControl.Foreground>
                        </ContentControl >
                    </Border>
                    <ControlTemplate.Triggers>
                        <EventTrigger RoutedEvent="Button.MouseEnter">
                            <BeginStoryboard Storyboard="{StaticResource buttonAnimIn}" />
                            <BeginStoryboard Storyboard="{StaticResource buttonAnimForegroundIn}" />
                        </EventTrigger>
                        <EventTrigger RoutedEvent="Button.MouseLeave">
                            <BeginStoryboard Storyboard="{StaticResource buttonAnimOut}" />
                            <BeginStoryboard Storyboard="{StaticResource buttonAnimForegroundOut}" />
                        </EventTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

The problem is:

Cannot convert the value in attribute 'Style' to object of type 'System.Windows.Style'. Cannot freeze this Storyboard timeline tree for use across threads. Error at object 'System.Windows.Controls.Button' in markup file 'HLSLEditor;component/mainwindow.xaml' Line 223 Position 25.

When using fixed colors it worked, but it cannot work with the Foreground color of the parent...

How do I do an animation to the foreground or background color?

Thanks!

like image 980
Marino Šimić Avatar asked Apr 14 '11 18:04

Marino Šimić


2 Answers

You cannot freeze Bindings, you probably can get around this issue by declaring a color as a resource and then bind your Control's Background to it while using StaticResource in the animation.

e.g.

<Window.Background>
    <SolidColorBrush Color="{DynamicResource Background}"/>
</Window.Background>
<Window.Resources>
    <Color x:Key="Background">Green</Color>
</Window.Resources>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
                Duration="0:0:1"
                To="{StaticResource Background}"/>

Alternative using a resource class:

public static class MyColors
{
    public static Color MyHighlightColor = Color.FromArgb(255, 0, 88, 0);
}
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
                Duration="0:0:1"
                To="{x:Static local:MyColors.MyHighlightColor}"/>
like image 132
H.B. Avatar answered Oct 15 '22 11:10

H.B.


I think that understanding the error might give you a way of fixing the problem.

Animation requires the use of threads besides the UI thread. So storyboards have to be freezable, which means that all the animations in the storyboard must be freezable, and everything those animations use must also be freezable.

Bindings aren't freezable - pretty much by definition, as they are a mechanism whereby a dependency property can be changed. You can't use a dynamic binding in a color animation - there's the possibility that the property could change while the animation was running. The same thing happens whether you're binding to an object or you're using DynamicResource.

The thing is, this is protecting you from something that you don't really want anyway. You don't really want the colors to change while the animation is running. That's not what you're trying to accomplish. You want the color resources that the animation is using to change if the user selects a different skin.

So instead of binding storyboards to skinnable resources, add the storyboards to the dictionary of resources that get set when the skin changes (using static bindings to set the colors), and use dynamic binding in your event triggers. That should work.

like image 32
Robert Rossney Avatar answered Oct 15 '22 11:10

Robert Rossney