我有一个具有StoryBoard
类型的单个附加属性的附加行为。我想在ListView中的每个项目上设置此属性。 XAML看起来像这样:
<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>
到目前为止,一切都很好。然后,“ MyBehavior”中的代码尝试执行此操作:
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();
}
但是,对
InvalidOperationException
的调用会引发StoryBoard.SetTarget()
:“无法在对象'System.Windows.Media.Animation.Storyboard'上设置属性,因为它处于只读状态。”如果在调试器中检查Storyboard
,则可以看到其IsSealed
和IsFrozen
属性都设置为true
。相比之下,如果我直接在
MyBehavior.Animation
上设置ListView
而不需要使用Style
,则StoryBoard
会被密封,并且我可以设置目标并成功运行它。但这不是我想要的。为什么我的
StoryBoard
被密封了,我能做些什么来防止这种情况发生?更新:我可以通过在null检查之后添加以下内容来解决我的问题:
if(sb.IsSealed)
sb = sb.Clone();
但是我仍然很好奇发生了什么。显然某个地方(
Style
?Setter
?)冻结/密封了Setter.Value
中的对象。 最佳答案
我对此进行了一些研究,并认为我已经解决了大部分正在发生的事情。简短的答案是,这种行为是设计使然。 .net 4.0的MSDN Styling and Templating页明确指出“一旦应用样式,它就会被密封,无法更改”。带有Style.IsSealed的注释可以支持此操作。但这就是Style
本身。我正在处理Style
的Setter
的Value
中包含的对象。好吧,Style.Seal密封所有Setter
,而Setter.Seal密封其Value
。掌握了这些信息(头),这里发生的一切都没有特别令人震惊。但是,对于为什么所有这些密封工作都是首先进行的,仍然没有任何解释。声明here和here与线程安全有关。这似乎是合理的,但我还要进一步推测,如果所有消耗特定Style
的对象共享一个Style
对象(并且我不知道是否是这种情况),则可以对您不希望某个使用者修改Style
并意外更改其他所有人的简单原因。
所有这一切似乎都意味着无法普遍解决该问题,因此需要逐案解决。就我而言,解决方案只是克隆Storyboard
然后对该克隆进行操作。
关于c# - 由样式设置时,StoryBoard对象变为只读,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31487089/