控件模板故事板颜色动画问题

5

我在颜色动画方面遇到了问题。这是我的源代码:

 <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>

问题是:
无法将属性“Style”中的值转换为类型为“System.Windows.Style”的对象。无法冻结此Storyboard时间线树以在跨线程使用。标记文件'HLSLEditor;component/mainwindow.xaml'中的对象'System.Windows.Controls.Button'出现错误,行223位置25。
当使用固定颜色时它可以工作,但是不能与父元素的前景色一起工作...
如何对前景色或背景色进行动画处理?
谢谢!

顺便说一下,故事板的目的是将动画分组,因此您通常只会有一个“InStoryboard”和“OutStoryboard”,每个故事板都包含两个动画。 - H.B.
3个回答

6
您无法冻结绑定,您可以通过将颜色声明为资源并在动画中使用StaticResource将控件的背景绑定到它来解决此问题。
例如:
<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}"/>

使用资源类的替代方案:

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}"/>

感谢H.B.的建议,但问题在于我的所有颜色都在资源文件中,我们的应用程序中有皮肤功能。有没有一种方法可以解决这个问题,而不需要在XAML文件中声明静态颜色? - Marino Šimić
什么类型的资源文件?如果它将颜色声明为静态公共字段,您可以使用{x:Static namespace:Class.Field}而不是使用静态资源。 (x:Static Reference) - H.B.
为了澄清:动态资源文件:主控件的背景和前景颜色通过DynamicResource绑定进行绑定。控件模板中的所有内部元素都绑定到包含它们的控件颜色...当我需要更改皮肤时,我更改资源字典,这就是我需要DynamicResource的原因。 - Marino Šimić
很遗憾,这可能是不可能的,至少我想不到任何方法来做到这一点,抱歉... - H.B.

2

我认为理解错误可能会让你找到解决问题的方法。

动画除了UI线程之外还需要使用线程。因此,故事板必须是可冻结的,这意味着故事板中的所有动画都必须是可冻结的,并且这些动画使用的所有内容也必须是可冻结的。

绑定不是可冻结的 - 几乎可以通过定义来说明,因为它们是一种依赖属性可以被更改的机制。在颜色动画中不能使用动态绑定 - 可能在动画运行时属性会发生变化。无论您绑定到对象还是使用DynamicResource,都会发生相同的情况。

问题是,这保护您免受您实际上不想要的东西的影响。您实际上不希望在动画运行时更改颜色。这不是您想要完成的任务。如果用户选择了不同的皮肤,您希望动画使用的颜色资源发生更改。

因此,不要将故事板绑定到可换肤资源,而是将故事板添加到在更改皮肤时设置的资源字典中(使用静态绑定设置颜色),并在事件触发器中使用动态绑定。那应该可以起作用。


谢谢您的观点,不幸的是,在一些研究之后,我也得出了同样的结论,现在得到了您的确认。看来只有放弃XAML,改用.cs文件才是唯一的解决方案 :/ - Marino Šimić
我认为我的建议只涉及移动XAML,而不是用代码替换它。我对你的应用了解得不够,无法确定。 - Robert Rossney

1
当我遇到这个问题时,我通过修改我的样式来绕过它,使样式包含两个相同的元素,一个用于“正常”状态,另一个用于“按下”状态。默认情况下,“按下”元素的Opacity设置为0,而另一个元素的Opacity为1。我的动画将透明度从0改变为1,反之亦然。
这种方法避免了实际动画化Color属性,但产生了相同的效果,同时保持了所有内容在XAML中。由于颜色是在样式定义中设置而不是在动画中设置,因此可以根据需要进行绑定。这可能并不适用于所有情况,但对于我比较简单的样式来说,这是一种非常快速实现所需效果的方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接