14

I have a storyboard which targets an element, and binds one of its own properties to a property on another element:

<Storyboard>
  <DoubleAnimation 
            Storyboard.TargetProperty="RenderTransform.X" 
            From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" 
            To="0" 
            Duration="0:0:5"/>
 </Storyboard>

This storyboard works when the storyboard is stored in the resources of the window which holds the storyboard target. The 'From' value is correctly bound to the ActualWidth of the host Window instance.

However, I need to store the storyboard in my application level resources. From here, the storyboard does not seem to be able to target the window to determine the 'From' property. This is understandable as from inside <Application.Resources>, the binding won't be able to find an 'ancestor' of type Window.

I guess I need to be able to bind the 'From' value, relative to the target of the animation, rather than relative to the storyboard's DoubleAnimation.

Is this possible, and if so, how?

Here is the sample MainWindow.xaml:

<Window.Resources>
    <!--This works : Storyboard correctly sets 'From' property to 'ActualWidth' of window-->
    <Storyboard x:Key="localStoryBoard">
        <DoubleAnimation 
            Storyboard.TargetProperty="RenderTransform.X" 
            From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" 
            To="0" 
            Duration="0:0:5"/>
    </Storyboard>
</Window.Resources>
<StackPanel>

    <Button
        RenderTransformOrigin="0,1"
        HorizontalAlignment="Left"
        Content="Click me">

        <Button.RenderTransform>
            <TranslateTransform/>
        </Button.RenderTransform>
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <EventTrigger.Actions>
                    <BeginStoryboard Storyboard="{StaticResource centralStoryBoard}"/>
                </EventTrigger.Actions>
            </EventTrigger> 
        </Button.Triggers>
    </Button>
</StackPanel>

And here is an example app.xaml:

<Application x:Class="WpfApplication3.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <!--Storyboard doesn't work at all-->
        <Storyboard x:Key="centralStoryBoard">
            <DoubleAnimation 
                Storyboard.TargetProperty="RenderTransform.X" 
                From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" 
                To="0" 
                Duration="0:0:5"/>
        </Storyboard>
    </Application.Resources>
</Application>

This won't work, as the eventtrigger refers to the app.xaml version. If you change it to the local resource version, you can see it works.

Noel Kennedy
  • 12,128
  • 3
  • 40
  • 57
  • This is an excellent question. Information on problems like this is pretty hard to come by so hopefully someone can answer it. I noticed that it works in a merged ResourceDictionary as well if that's any help – Fredrik Hedblad Dec 18 '10 at 02:02

1 Answers1

0

The example doesn't work because when you put your storyboard to resources it has no Window ancestor. What actually RelativeSource do is search element tree backwards waiting for the node with AncestorType appear and then binds it.

When put in the Window.Resources there's actual Window back in the tree and it binds it correctly. When put to the application resources there's no Window back in the tree because it's not connected to the Window whatsoever.

If you really want to put your storyboard to the application resources you should consider giving up the idea with binding. Instead, you can check out this answer with code for a clipper, I think this is what you need - https://stackoverflow.com/a/59376318/11178539.

Lauriero
  • 14
  • 4