Magnus Johansson
Magnus Johansson

Reputation: 28325

How can I target multiple UIElements with VisualStateManager?

If I do something like this to change the opacity of an Ellipse:

<VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="VisualStateGroup">
    <VisualStateGroup.Transitions>
      <VisualTransition GeneratedDuration="0:0:1">
        <VisualTransition.GeneratedEasingFunction>
          <CircleEase EasingMode="EaseIn"/>
        </VisualTransition.GeneratedEasingFunction>
      </VisualTransition>
    </VisualStateGroup.Transitions>
    <VisualState x:Name="Lit"/>
    <VisualState x:Name="Unlit">
      <Storyboard>
        <DoubleAnimation Duration="0" To="0.225" 
                         Storyboard.TargetProperty="(UIElement.Opacity)" 
                         Storyboard.TargetName="ellipse"  d:IsOptimized="True"/>
      </Storyboard>
    </VisualState>
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<Ellipse x:Name="ellipse" Width="100" Height="100" Fill="Azure"/>


VisualStateManager.GoToState(this, "Unlit", true);

It works just fine.

But let's say I have a handful of Ellipses and want to apply the same StoryBoard to them, how do I do that?

<Ellipse x:Name="ellipse1" Width="100" Height="100" Fill="Azure"/>
<Ellipse x:Name="ellipse2" Width="100" Height="100" Fill="Azure"/>
<Ellipse x:Name="ellipse3" Width="100" Height="100" Fill="Azure"/>

One way would be to define multiple DoubleAnimations to the same StoryBoard:

  <Storyboard>
    <DoubleAnimation Duration="0" To="0.225" 
                     Storyboard.TargetProperty="(UIElement.Opacity)" 
                     Storyboard.TargetName="ellipse1"
                       d:IsOptimized="True"/>
    <DoubleAnimation Duration="0" To="0.225" 
                     Storyboard.TargetProperty="(UIElement.Opacity)" 
                     Storyboard.TargetName="ellipse2"
                       d:IsOptimized="True"/>
  </Storyboard>

But this is somewhat cumbersome when I have a dynamic number of ellipses.
Is there any more elegant way?

Upvotes: 2

Views: 547

Answers (1)

Nicholas W
Nicholas W

Reputation: 2241

I'm not sure about elegant, but one way could be to animate an intermediate property, and bind the real target properties to that:

<Grid x:Name="animationTarget" Visibility="Collapsed" />
<Ellipse x:Name="ellipse1" Width="100" Height="100" Fill="Azure" 
    Opacity={Binding Opacity, ElementName=animationTarget}/>
<Ellipse x:Name="ellipse2" Width="100" Height="100" Fill="Azure" 
    Opacity={Binding Opacity, ElementName=animationTarget}/>

and

<Storyboard>
    <DoubleAnimation Duration="0" To="0.225" 
                     Storyboard.TargetProperty="(UIElement.Opacity)" 
                     Storyboard.TargetName="animationTarget" />
</Storyboard>

(If using an invisible extra element as an intermediate binding target doesn't seem nice it could instead be on some attached property on whatever container your ellipses are in)

Upvotes: 2

Related Questions