I have an attached behavior that has a single attached property of type StoryBoard
. I want to set this property on every item in a ListView. The XAML looks something like this:
<Grid>
<Grid.Resources>
<Storyboard x:Key="TheAnimation" x:Shared="False">
<DoubleAnimation From="0.0" To="1.0" Duration="0:0:0.20"
Storyboard.TargetProperty="Opacity" />
</Storyboard>
</Grid.Resources>
<ListView>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="local:MyBehavior.Animation"
Value="{StaticResource TheAnimation}" />
</Style>
</ListView.Resources>
</ListView>
</Grid>
So far so good. Then the code in 'MyBehavior' tries to do this:
private static void AnimationChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var listViewItem = d as ListViewItem;
if (d == null)
return;
var sb = e.NewValue as Storyboard;
if (sb == null)
return;
Storyboard.SetTarget(sb, listViewItem);
sb.Begin();
}
But an InvalidOperationException
is thrown on the call to StoryBoard.SetTarget()
: "Cannot set a property on object 'System.Windows.Media.Animation.Storyboard' because it is in a read-only state." If I inspect the Storyboard
in the debugger, I can see that both its IsSealed
and IsFrozen
properties are set to true
.
By contrast, if I set MyBehavior.Animation
directly on the ListView
so that I don't need to use a Style
, the StoryBoard
arrives unsealed and I am able to set the target and run it successfully. But that's not where I want it.
Why is my StoryBoard
being sealed, and is there anything I can do to prevent this?
Update: I can solve my problem by adding this right after the null check:
if(sb.IsSealed)
sb = sb.Clone();
But I'm still curious what's going on. Apparently something somewhere (Style
? Setter
?) is freezing/sealing the object in Setter.Value
.