WPF VisualStateManager - 如何为模板化子项内的属性设置动画

发布于 2024-11-19 18:51:40 字数 1493 浏览 6 评论 0原文

我有一个 UserControl,其中包含一个具有自定义 ItemsPanel 的 ItemsControl,其依赖属性名为“MaxColumns”。我想定义一个 VisualState(在 UserControl 级别),它可以为自定义面板上的“MaxColumns”属性设置动画。

本质上,XAML 看起来像:

<Grid x:Name="LayoutRoot">
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="MyCoolState">
      <VisualState x:Name="Normal" />
      <VisualState x:Name="NotNormal">
        <Storyboard>
          <Int32Animation Duration="0"
                          Storyboard.TargetName="Details"
                          Storyboard.TargetProperty="(ItemsControl.ItemsPanel).(local:CoolPanel.MaxColumns)"
                          To="4" />
        </Storyboard>
      </VisualState>
    </VisualStateGroup>
  <VisualStateManager>
  <ItemsControl x:Name="Details">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <local:CoolPanel x:Name="MyCoolPanel"
                         MaxColumns="1" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</Grid>

但是,我一辈子都无法弄清楚动画的正确语法是什么?如果我使用上面显示的语法,则会收到错误:“'ItemsPanel' 属性未指向路径 '(0).(1)' 中的 DependencyObject”。我认为这是因为它在技术上指向 ItemsPanelTemplate?

如果我直接在 Storyboard.TargetName 属性中引用“MyCoolPanel”,则会收到有关名称范围的错误(可能是因为“MyCoolPanel”不在 LayoutRoot 的名称范围内)。我不知道是否有办法限定“TargetName”中的名称范围?

有人有解决方案吗?看起来应该可以在不诉诸自定义附加属性的情况下完成?我的意思是,我并不反对附加属性,但我觉得您应该能够直接在 XAML 中执行此操作?

I have a UserControl that contains an ItemsControl with a custom ItemsPanel, with a dependency property called "MaxColumns". I'd like to define a VisualState (at the UserControl level) that can animate the "MaxColumns" property on the custom panel.

In essence, the XAML looks something like:

<Grid x:Name="LayoutRoot">
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="MyCoolState">
      <VisualState x:Name="Normal" />
      <VisualState x:Name="NotNormal">
        <Storyboard>
          <Int32Animation Duration="0"
                          Storyboard.TargetName="Details"
                          Storyboard.TargetProperty="(ItemsControl.ItemsPanel).(local:CoolPanel.MaxColumns)"
                          To="4" />
        </Storyboard>
      </VisualState>
    </VisualStateGroup>
  <VisualStateManager>
  <ItemsControl x:Name="Details">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <local:CoolPanel x:Name="MyCoolPanel"
                         MaxColumns="1" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</Grid>

However, I cannot for the life of me figure out what the right syntax is for the animation? If I use the syntax shown above, I get the error: "'ItemsPanel' property does not point to a DependencyObject in path '(0).(1)'". I'm presuming this is because it's technically pointing to a ItemsPanelTemplate?

If I refer to "MyCoolPanel" directly in the Storyboard.TargetName property, I get an error about Name scope (presumably because "MyCoolPanel" isn't in the namescope of LayoutRoot). I don't know if there is a way to qualify name scope in "TargetName"?

Does anyone have a solution for this? It seems like something that should be doable without resorting to custom attached properties? I mean, I'm not opposed to attached properties, but I feel like you ought to be able to do this directly in the XAML?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人事已非 2024-11-26 18:51:40

好吧,事实上 ItemsPanel 不是一个真实的对象,而是一个用于创建该对象的模板。所以从技术上讲,你的参考是行不通的。

我有以下关于实现的信息:

  1. 您在 ItemsPanel(无论如何都是一个模板)上设置一些附加属性,但在 ItemsControl 本身上设置一些附加属性。
  2. 您可以使用 RelativeSource FindAncestorCoolPanel 的 MaxColumns 绑定到该附加属性。

好吧,您可以省略附加属性,并使用 Tag :-) 事实上,ItemsControl 完全在您的控制之下,因此滥用 Tag 并不构成犯罪。 code>Tag 一点点。

所以代码会是这样的:

<Grid x:Name="LayoutRoot">
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="MyCoolState">
      <VisualState x:Name="Normal" />
      <VisualState x:Name="NotNormal">
        <Storyboard>
          <Int32Animation Duration="0"
                          Storyboard.TargetName="Details"
                          Storyboard.TargetProperty="Tag"
                          To="4" />
        </Storyboard>
      </VisualState>
    </VisualStateGroup>
  <VisualStateManager>
  <ItemsControl x:Name="Details" Tag="3">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <local:CoolPanel
            MaxColumns="{Binding Tag, RelativeSource={RelativeSource FindAncestor,
                                           AncestorType=ItemsControl}}" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</Grid>

Okay, indeed the ItemsPanel is not a real object but a template with which the object is going to be created. So technically your reference is not going to work.

I've got the following about implementation:

  1. you set some attached property on the ItemsPanel (which is anyway a template), but on the ItemsControl itself.
  2. You bind the CoolPanel's MaxColumns to that attached property using RelativeSource FindAncestor.

Well, you could omit the attached property, and use Tag for it :-) Indeed, the ItemsControl is totally in your control, so there is no crime in abusing the Tag a little bit.

So the code would be like this:

<Grid x:Name="LayoutRoot">
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="MyCoolState">
      <VisualState x:Name="Normal" />
      <VisualState x:Name="NotNormal">
        <Storyboard>
          <Int32Animation Duration="0"
                          Storyboard.TargetName="Details"
                          Storyboard.TargetProperty="Tag"
                          To="4" />
        </Storyboard>
      </VisualState>
    </VisualStateGroup>
  <VisualStateManager>
  <ItemsControl x:Name="Details" Tag="3">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <local:CoolPanel
            MaxColumns="{Binding Tag, RelativeSource={RelativeSource FindAncestor,
                                           AncestorType=ItemsControl}}" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</Grid>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文