ItemsControl内Label前景色动画异常:无法在硬对象实例上执行动画
问题:ItemsControl中Label前景色动画抛出异常
在使用ItemsControl并以Label作为ItemTemplate时,未添加StoryBoard程序运行正常,但为Label前景色添加动画时,抛出异常Cannot animate '(0).(1)' on a hard object instance,异常指向(Label.Foreground).(SolidColorBrush.Color)。单独在窗口中创建该Label并绑定数据时,动画可正常运行,推测问题出在ItemsControl内的操作。使用Caliburn Micro框架,但判断与此问题无关。
相关XAML代码:
<ItemsControl ItemsSource="{Binding StatusList}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Columns="{Binding StatusList.Count}" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Label Content="{Binding Text}"> <Label.Style> <Style TargetType="Label"> <Setter Property="FontSize" Value="24"></Setter> <Setter Property="FontWeight" Value="Bold"></Setter> <Setter Property="HorizontalAlignment" Value="Center"></Setter> <Setter Property="VerticalAlignment" Value="Center"></Setter> <Style.Triggers> <DataTrigger Binding="{Binding IsOnError}" Value="False"> <Setter Property="Foreground" Value="#33AA33"></Setter> </DataTrigger> <DataTrigger Binding="{Binding IsOnError}" Value="True"> <Setter Property="Foreground" Value="Red" /> <Setter Property="FontWeight" Value="Bold" /> <DataTrigger.EnterActions> <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)" RepeatBehavior="Forever" AutoReverse="True" From="Red" To="Black" Duration="0:0:0.5"> </ColorAnimation> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> </DataTrigger> </Style.Triggers> </Style> </Label.Style> </Label> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
解决方案
异常核心原因:在Style的Setter中直接使用Red这类颜色字面量时,WPF会复用冻结的SolidColorBrush实例(冻结对象不可修改,而动画需要修改对象属性,因此触发报错)。单独使用Label时,WPF创建的是非冻结实例,所以动画能正常运行。
修复步骤:
- 定义非冻结的SolidColorBrush资源,避免WPF复用冻结实例
- 修改Style中Foreground的Setter,引用自定义Brush资源
- 简化动画的TargetProperty路径(Style已指定TargetType为Label,可省略Label前缀)
修改后的代码示例:
<Window.Resources> <SolidColorBrush x:Key="ErrorForegroundBrush" Color="Red" IsFrozen="False" /> <SolidColorBrush x:Key="NormalForegroundBrush" Color="#33AA33" IsFrozen="False" /> </Window.Resources> <ItemsControl ItemsSource="{Binding StatusList}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Columns="{Binding StatusList.Count}" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Label Content="{Binding Text}"> <Label.Style> <Style TargetType="Label"> <Setter Property="FontSize" Value="24"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Style.Triggers> <DataTrigger Binding="{Binding IsOnError}" Value="False"> <Setter Property="Foreground" Value="{StaticResource NormalForegroundBrush}"/> </DataTrigger> <DataTrigger Binding="{Binding IsOnError}" Value="True"> <Setter Property="Foreground" Value="{StaticResource ErrorForegroundBrush}" /> <Setter Property="FontWeight" Value="Bold" /> <DataTrigger.EnterActions> <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetProperty="(Foreground).(SolidColorBrush.Color)" RepeatBehavior="Forever" AutoReverse="True" From="Red" To="Black" Duration="0:0:0.5"/> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> </DataTrigger> </Style.Triggers> </Style> </Label.Style> </Label> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
补充说明:
- 设置
IsFrozen="False"确保Brush实例可被动画修改 - 也可以直接在Setter中创建新Brush实例(如
<Setter Property="Foreground"><Setter.Value><SolidColorBrush Color="Red"/></Setter.Value></Setter>),但使用资源更便于复用维护
内容的提问来源于stack exchange,提问作者Quino
相关产品推荐
相关产品推荐

