WPF VisualStateManager - Как анимировать свойства в шаблонном дочернем элементе - PullRequest
2 голосов
/ 13 июля 2011

У меня есть UserControl, который содержит ItemsControl с настраиваемой панелью ItemsPanel со свойством зависимости под названием «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 не указывает на объект DependencyObject в пути« (0). (1) »». Я предполагаю, что это потому, что технически он указывает на ItemsPanelTemplate?

Если я ссылаюсь на «MyCoolPanel» непосредственно в свойстве Storyboard.TargetName, я получаю ошибку об области действия имени (предположительно потому, что «MyCoolPanel» отсутствует в области имен LayoutRoot). Я не знаю, есть ли способ определить область имени в "TargetName"?

У кого-нибудь есть решение для этого? Похоже на то, что должен быть выполнимым без использования пользовательских свойств? Я имею в виду, я не против вложенных свойств, но я чувствую, что вы должны быть в состоянии сделать это непосредственно в XAML?

1 Ответ

3 голосов
/ 13 июля 2011

Хорошо, действительно, ItemsPanel - это не реальный объект, а шаблон, с помощью которого этот объект будет создан. Так что технически ваша ссылка не сработает.

У меня есть следующее о реализации:

  1. вы устанавливаете какое-либо вложенное свойство на ItemsPanel (которая в любом случае является шаблоном), но на самом ItemsControl.
  2. Вы связываете MaxColumns CoolPanel с этим прикрепленным свойством, используя RelativeSource FindAncestor.

Что ж, вы можете опустить присоединенное свойство и использовать для него Tag :-) Действительно, ItemsControl полностью под вашим контролем, поэтому нет никакого преступления в том, чтобы немного злоупотреблять 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>
...