StoryBoard对象被样式设置后变为只读

本文关键字:只读 设置 对象 样式 StoryBoard | 更新日期: 2023-09-27 18:03:23

我有一个附加行为,它有一个类型为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();
}

但是在调用StoryBoard.SetTarget()时抛出了InvalidOperationException:"不能在对象上设置属性"System.Windows.Media.Animation。"因为它处于只读状态"如果我在调试器中检查Storyboard,我可以看到它的IsSealedIsFrozen属性都设置为true

相反,如果我直接在ListView上设置MyBehavior.Animation,这样我就不需要使用Style,那么StoryBoard到达时是未密封的,我就能够设置目标并成功运行它。但那不是我想要的地方。

为什么我的StoryBoard被密封,我能做些什么来防止这种情况吗?

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

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

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

StoryBoard对象被样式设置后变为只读

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

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

我对此做了一些研究,我想我已经弄清楚了发生的大部分事情。简单地说,这种行为是设计出来的。.net 4.0的MSDN样式和模板页面直截了当地说:"一旦样式被应用,它就被密封,不能被更改。"有风格的评论。我把它封起来了。但这就是Style本身;我正在处理一个包含在StyleSetterValue中的对象。嗯,风格。印章印章所有的Setter s,和Setter。Seal密封其Value。有了这些信息,这里发生的一切都不是特别令人震惊。但目前还没有解释为什么要首先进行所有这些密封。这里和这里都有人声称它与线程安全有关。这似乎是合理的,但我进一步推测,如果所有使用特定Style的对象共享单个Style对象(我不知道情况是否如此),密封可能是因为您不希望一个消费者修改Style并意外地改变其他所有人。

所有这些似乎都意味着这个问题没有通用的解决方案,它需要逐个解决。在我的例子中,解决方案只是克隆Storyboard,然后对该克隆进行操作。