1

我有一个附加的行为,它有一个 type 的附加属性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在调试器中检查 ,我可以看到它IsSealedIsFrozen属性都设置为true.

相比之下,如果我MyBehavior.Animation直接设置在 上,ListView这样我就不需要使用 a StyleStoryBoard到达时未密封,我可以设置目标并成功运行它。但这不是我想要的。

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

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

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

但我仍然很好奇发生了什么。显然某处(Style??Setter)正在冻结/密封对象Setter.Value

4

2 回答 2

2

我已经对此进行了一些研究,并认为我已经弄清楚了大部分情况。简短的回答是,这种行为是设计使然。.net 4.0的 MSDN样式和模板页面直截了当地说:“一旦应用了样式,它就会被密封并且无法更改。” 带有Style.IsSealed的评论支持这一点。但这就是它Style本身;我正在处理包含在Style'sSetter中的对象Value。好吧,Style.Seal密封了它的所有Setters,而Setter.Seal密封了它的 s Value。有了这些信息(头脑),这里发生的一切都不是特别令人震惊的。但是仍然没有解释为什么首先要完成所有这些密封。在这里它与线程安全有关。这似乎是合理的,但我会进一步推测,如果所有消耗特定对象的对象Style共享一个Style对象(我不知道是否是这种情况),那么密封可能会出于您不这样做的简单原因而完成不希望一个消费者修改Style并意外地改变其他所有人。

这一切似乎意味着这个问题没有通用的解决方案,需要根据具体情况来解决。就我而言,解决方案只是克隆Storyboard然后对该克隆进行操作。

于 2015-07-18T15:57:34.153 回答
1

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

如果您仍想走资源路线,则可以将资源视为{DynamicResource...}代替,{StaticResource...}这可能允许您修改已用于其他对象的对象。正如我所说,我不是 WPF 方面的专家,我承认在 和 之间的区别上仍然有点DynamicResource模糊StaticResource,但我有一个模糊的回忆,它解决了这种情况。:)

于 2015-07-18T04:49:32.113 回答