当Style设置时,StoryBoard对象变为只读

时间:2015-07-18 02:11:24

标签: c# wpf storyboard attached-properties attachedbehaviors

我有一个附加行为,它具有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>

到目前为止一切顺利。那么&#39; MyBehavior&#39;中的代码试图这样做:

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():&#34;无法在对象&#39; System.Windows.Media.Animation.Storyboard&#39;上设置属性。因为它处于只读状态。&#34;如果我检查调试器中的Storyboard,我可以看到其IsSealedIsFrozen属性都设置为true

相比之下,如果我直接在MyBehavior.Animation上设置ListView,以便我不需要使用Style,那么StoryBoard就会启封,而{I}我能够设置目标并成功运行它。但那不是我想要的地方。

为什么我的StoryBoard被封存了,我能做些什么来防止这种情况发生?

更新:我可以通过在空检查后添加此项来解决我的问题:

if(sb.IsSealed)
   sb = sb.Clone();

但我仍然很好奇发生了什么。显然某个地方(StyleSetter?)冻结/密封Setter.Value中的对象。

2 个答案:

答案 0 :(得分:1)

我远不是WPF的专家,所以我无法解释为什么这是微软做出的选择的细节。但据我了解,主要问题是声明为资源的对象可能与多个其他对象共享。因此,您无法修改它。

如果你仍然想要进入资源路径,那么可能你可以将资源视为{DynamicResource...}而不是{StaticResource...},这可能会让你修改已被用于其他对象的对象。正如我所说的,我不是WPF的专家,我承认DynamicResourceStaticResource之间的差异仍然有点混乱,但我有一个模糊的回忆,它解决了这种情况。 :)

答案 1 :(得分:1)

我已经对此做了一些研究,并认为我已经解决了大部分正在发生的事情。简短的回答是这种行为是设计的。 .net 4.0的MSDN Styling and Templating页面表示,“一旦应用了某个样式,它就会被密封并且无法更改。”有Style.IsSealed的评论支持这一点。但那是Style本身;我正在处理Style的{​​{1}} Setter中包含的对象。好吧,Style.SealValue封为所有Setter,而Setter.Seal封印其Value。掌握了这些信息(头部),这里发生的一切都不是特别令人震惊。但是,仍然没有解释为什么所有这些密封首先要完成。声称herehere与线程安全相关。这似乎是合理的,但我会进一步推测,如果所有使用特定Style的对象共享一个Style对象(并且我不知道是否是这种情况),那么密封可能这样做的原因很简单,你不希望一个消费者修改Style并意外地改变其他人。

这一切似乎意味着问题没有一般解决方案,需要逐案解决。就我而言,解决方案只是克隆Storyboard,然后对该克隆进行操作。