Phil
Phil

Reputation: 42991

Storyboard not found in name scope of style

The problem I'm having is that if I base a style on a second style that contains a storyboard, then there is an exception in the Trigger.ExitAction.

So:

In the end what I'm trying to achieve re-use a style containing triggers and storyboards in several other styles.

Here's some simple code that demonstrates the problem:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Grid.Resources>
        <Style x:Key="rectStyle" TargetType="{x:Type Rectangle}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard x:Name="MouseOverStoryboard">
                            <Storyboard>
                                <ColorAnimation To="PaleGoldenrod" 
                                   Storyboard.TargetProperty="(Fill).(Color)" 
                                   Duration="0:0:1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <StopStoryboard BeginStoryboardName="MouseOverStoryboard"/>
                    </Trigger.ExitActions>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="rectStyle2" TargetType="{x:Type Rectangle}" 
               BasedOn="{StaticResource rectStyle}"/>
    </Grid.Resources>

    <Rectangle Grid.Row="0" Width="100" Height="100" Fill="Red" 
               Style="{StaticResource rectStyle}" />
    <Rectangle Grid.Row="1" Width="100" Height="100" Fill="Blue" 
               Style="{StaticResource rectStyle2}" />
</Grid>

Upvotes: 5

Views: 3241

Answers (2)

Joachim Bickel
Joachim Bickel

Reputation: 21

Just stumbled upon this due to having the same problem. There is another solution, albeit a somewhat clunky one.

Animations on Properties get overwritten when applying another animation, so you can use another BeginStoryboard in the ExitActions of the Trigger to overwrite the previous one, and use a FillBehavior of Stop to automatically remove that.

Unfortunately, the combination of Duration=0, FillBehavior=Stop, and no target value doesn't work, so you need to set a very short duration for that animation.

In your example:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Grid.Resources>
        <Style x:Key="rectStyle" TargetType="{x:Type Rectangle}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation To="PaleGoldenrod" 
                                   Storyboard.TargetProperty="(Fill).(Color)" 
                                   Duration="0:0:1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard FillBehavior="Stop">
                                <ColorAnimation 
                                   Storyboard.TargetProperty="(Fill).(Color)" 
                                   Duration="0:0:0.0000001"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.ExitActions>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="rectStyle2" TargetType="{x:Type Rectangle}" 
               BasedOn="{StaticResource rectStyle}"/>
    </Grid.Resources>

    <Rectangle Grid.Row="0" Width="100" Height="100" Fill="Red" 
               Style="{StaticResource rectStyle}" />
    <Rectangle Grid.Row="1" Width="100" Height="100" Fill="Blue" 
               Style="{StaticResource rectStyle2}" />
</Grid>

Upvotes: 2

erodewald
erodewald

Reputation: 1825

Your best bet is to steer clear of derived styles if you want to include StopStoryboard. There are actually 2 instances of the style and the scope is wrong for the derived style. I believe this is by design. You could abstract that storyboard out to an outer scope in the resources and duplicate the triggers in both styles, referencing the Storyboard by StaticResource. It may not solve your problem since you may have a specific requirement for derived styles, but I don't think you have a choice unfortunately.

Because you cannot inherit from a base style at all if you want to use StopStoryboard you'd have to do something like this:

<Grid>
<Grid.RowDefinitions>
  <RowDefinition/>
  <RowDefinition/>
</Grid.RowDefinitions>
<Grid.Resources>
  <Storyboard x:Key="mouseOver">
    <ColorAnimation
      AutoReverse="True"
      Duration="0:0:1"
      RepeatBehavior="Forever"
      Storyboard.TargetProperty="(Fill).(Color)"
      To="PaleGoldenrod"/>
  </Storyboard>
  <Style x:Key="rectStyle" TargetType="{x:Type Rectangle}">
    <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">
        <Trigger.EnterActions>
          <BeginStoryboard x:Name="MouseOverStoryboard" Storyboard="{StaticResource mouseOver}"/>
        </Trigger.EnterActions>
        <Trigger.ExitActions>
          <StopStoryboard BeginStoryboardName="MouseOverStoryboard"/>
        </Trigger.ExitActions>
      </Trigger>
    </Style.Triggers>
  </Style>
  <Style x:Key="rectStyle2" TargetType="{x:Type Rectangle}">
    <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">
        <Trigger.EnterActions>
          <BeginStoryboard x:Name="MouseOverStoryboard1" Storyboard="{StaticResource mouseOver}"/>
        </Trigger.EnterActions>
        <Trigger.ExitActions>
          <StopStoryboard BeginStoryboardName="MouseOverStoryboard1"/>
        </Trigger.ExitActions>
      </Trigger>
    </Style.Triggers>
  </Style>
</Grid.Resources>
<Rectangle
  Width="100"
  Height="100"
  Grid.Row="0"
  Fill="Red"
  Style="{StaticResource rectStyle}"/>
<Rectangle
  Width="100"
  Height="100"
  Grid.Row="1"
  Fill="Blue"
  Style="{StaticResource rectStyle2}"/>

Upvotes: 9

Related Questions