tags:

views:

3901

answers:

4

I have created a very simple test app to try and solve this problem described to me by a co-worker. He was able to trigger it in C#, but I believe he needed the solution to be more generic and wanted it to be done strictly in the XAML. The problem was: How do you trigger the Storyboard inside of a UserControl to begin in response to an event on a control in the containing Window (the parent doesn't have to be a Window, it can be a Page or another UserControl...I use a Window for simplicity). So, my best example is that you have a Window with a Button and an instance of your UserControl. You want the Click event of the Button to trigger a Storyboard inside of the UserControl to begin.

Inside of the UserControl itself, the Storyboard is declared as a Resource with the key of MyStoryboard. I created a Button with an EventTrigger to show that I could trigger the Storyboard by referencing it with a Binding expression. Here is the complete XAML for my UserControl:

<UserControl x:Class="UserControlStoryboard.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<UserControl.Resources>
    <Storyboard x:Key="MyStoryboard">
        <ColorAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(Grid.Background).Color" From="CadetBlue" To="White" Duration="0:0:2" />
    </Storyboard>
</UserControl.Resources>
<Grid Background="CadetBlue" x:Name="grid">
    <Button Content="Press Me" Height="50">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <BeginStoryboard.Storyboard>
                        <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" Path="Resources[MyStoryboard]" />
                    </BeginStoryboard.Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>            
</Grid>

I was hoping that since I was able to tell a Storyboard to begin by referencing it with a Binding expression that I should be able to do the exact same thing from a Window that contains this UserControl as a child element. But I can't seem to figure out how to get a reference to the Storyboard inside of the parent Window. Is this impossible to accomplish in XAML only?

The parent window in my test project has nothing but a button and an instance of this UserControl. If it's even possible, which element would let me add an EventTrigger where the source of the event is the Button and the trigger action tells the UserControl's Storyboard to begin?

Thanks.

A: 

Hi Rich,

You can access the storyboard by using the StaticResource. You need only assign the resource to the Storyboard on the BeginStroyboard.

<BeginStoryboard Storyboard="{StaticResource MyStoryboard}">
</BeginStoryboard>

I changed the code to the following and when you press the button, it will start the storyboard for you. Hope this helps.

    <UserControl.Resources>
    <Storyboard x:Key="MyStoryboard">
        <ColorAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(Grid.Background).Color" From="CadetBlue" To="White" Duration="0:0:2" />
    </Storyboard>
</UserControl.Resources>
<Grid Background="CadetBlue" x:Name="grid">
    <Button Content="Press Me" Height="50">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard Storyboard="{StaticResource MyStoryboard}">
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>
</Grid>
NR
A: 

NR,

Thanks for your response, but that's not what I needed. I know that I could have simplified my code by using the StaticResource expression, but that's not going to work in the consumer (parent) of this UserControl that way. If the parent Window has the expression {StaticResource MyStoryboard}, it is going to traverse UP the logical tree looking for an element by that name. What I need to know is how to drill DOWN the tree into an instance of a UserControl FROM the consumer (containing parent) of the UserControl.

So, my question would be much better stated as follows:

How do I use binding expressions in WPF to drill down into an instance of a UserControl (if it's even possible).

Thanks again.

Rich
A: 

There probably isn't a good way to do it with pure Xaml.

You can:

  • Make a dependency property on your UserControl that takes a Button, then you can bind to it.
  • Make some kind of crazy converter that traverses your visual tree looking for something in particular.

Both require some C#, so I don't know if any of the above is what you are looking for.

Jonathan.Peppers
+1  A: 

I think the idea of responding to external events within UserControl is not a very safe one. Within UserControl, you'd want to react only to events that are born within the control.

Can you flip the situation around and do the following: ?

  • Expose the UC property that needs to be animated as a dependency property (background in this case)
  • Create both EventTrigger and Storyboard on the parent window
Sergey Aldoukhov