Bobjink,
Hello, I think I understand your question, but if I've not, please let me know where I've gone wrong, and I will modify my answer as needed. From what I understand, you want to have two custom user controls that are added to a window. You then want to animate them using a story board that is contained within your window. You want this animation triggered by an event from within the window. If this is what you're wanting, I've come up with the following solution:
Storyboards can be triggered by a number of different items. If you're wanting to stay fully XAML and not wanting to do any code behind animations, you can actually have the storyboards started by a control's events. For my example, I created two controls (MyAwesomeControl and MyAwesomerControl). These two controls are very simple, in that they are both grids that take up 100% width and height of what they are given. That is, the controls will be 50 x 50 if they are contained within a control that has it's height set to 50 x 50. Within the control's grids, I put a simple label to allow them to be distinguished. I also changed the background color of each control to show clear separation of each. Here is the definition code for my controls:
MyAwesomeControl.xaml
<UserControl x:Class="MyAwesomeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="LightBlue">
<TextBlock Text="Awesome!" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</UserControl>
MyAwesomerControl.xaml
<UserControl x:Class="MyAwesomerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="LightGreen">
<TextBlock Text="Awesomer!" FontSize="22" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</UserControl>
Next, I added these to my window. So that I could clearly see them in the window, I added a column definition (one column for each control). That is shown here:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Next I added a reference to my controls (if the controls are in the same application, you only have to add the reference via a namespace declaration like this:
xmlns:me="clr-namespace:MyWpfApplication"
Next, I added the controls to my window, placing one in each column of the grid. I also gave them distinguishable names. Here are the lines of code that I added to the grid:
I then got to the fun part, Animation! I decided to start my animation whenever anyone pushed down any mouse buttons. Then I figured out what my storyboard should do, and added this to the windows triggers. Here is that code:
Now, to explain this a bit further, here is what is happening:
We are adding an EventTrigger to the Window's triggers. This trigger will be initiated by the RoutedEvent property. The event that I chose was the MouseDown event (on the Window control). To this event, I added an action. The action that I added was the BeginStoryboard action. Within this I added my Storyboard which contained my animations. The animations I chose to start were the DoubleAnimations for setting the Width and Height of my controls. The Storyboard.TargetName property sets the named control instance to act upon. The Storyboard.TargetProperty property is the dependency property of the control to act upon. The From and To properties are from where the animation is going from and to. The Duration property tells how long the animation will take from start to finish. The AutoReverse property is setting the animation to return the values to the From value when done.
This all means that when a user clicks on the window, my two controls will at the same time (over the course of 1/2 second) shrink and grow in height or width. The Awesome
control will shrink in width and the Awesomer
control will shrink in height. When these animations reach the To
value, they will reverse and got back to their From
value.
For completeness, here is my full Window file:
Window1.xmal
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:me="clr-namespace:MyWpfApplication"
Title="Window1" Height="300" Width="300">
<Window.Triggers>
<EventTrigger RoutedEvent="Window.MouseDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Awesome" Storyboard.TargetProperty="Width" From="150" To="50" Duration="0:0:0.5" AutoReverse="True"/>
<DoubleAnimation Storyboard.TargetName="Awesomer" Storyboard.TargetProperty="Height" From="300" To="50" Duration="0:0:0.5" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<me:MyAwesomeControl x:Name="Awesome" Grid.Column="0" />
<me:MyAwesomerControl x:Name="Awesomer" Grid.Column="1" />
</Grid>
</Window>
Here is my final result:
I've added the code to my Google Code project for your download. I've also zipped up the source code and it is available at the following address:
http://stackoverflow-answers-by-scott.googlecode.com/files/1784500.zip
Also, here is a very good reference to WPF animations:
http://dotnetslackers.com/articles/wpf/IntroductionToWPFAnimations.aspx
I hope this helps,
Thanks!
EDIT: Ok, got it figured out. Heres what you do... If the 'Awesomer' control has a button that needs to start a storyboard that is contained in the container (Window1 in my case) this is what you do:
Add the event to your UserControl (MyAwesomerControl) to your code-behind and add the click event for your button which raises your internal event (MyAwesomerControlClick), like so:
Partial Public Class MyAwesomerControl
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
RaiseEvent MyAwesomerControlClick(sender, e)
End Sub
Public Shared ReadOnly MyAwesomerControlClickEvent As RoutedEvent = EventManager.RegisterRoutedEvent("MyAwesomerControlClick", RoutingStrategy.Tunnel, GetType(RoutedEventHandler), GetType(MyAwesomerControl))
Public Custom Event MyAwesomerControlClick As RoutedEventHandler
AddHandler(ByVal value As RoutedEventHandler)
[AddHandler](MyAwesomerControlClickEvent, value)
End AddHandler
RemoveHandler(ByVal value As RoutedEventHandler)
[RemoveHandler](MyAwesomerControlClickEvent, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
Dim newEventArgs As RoutedEventArgs = New RoutedEventArgs(MyAwesomerControl.MyAwesomerControlClickEvent)
[RaiseEvent](newEventArgs)
End RaiseEvent
End Event
End Class
Finally, in your Window code, change your EventTrigger code to listen for your event from above, like this:
<EventTrigger SourceName="Awesomer" RoutedEvent="me:MyAwesomerControl.MyAwesomerControlClick">
Notice the EventTrigger now has a SourceName property that points to our 'Awesomer' control. The RoutedEvent changes also, in that it has a 'me:' in front of the event. This isn't required previously as we were listening for a Microsoft routed event, instead of a custom routed event.
I also updated the Google Code project for your download. I've also zipped up the source code and it is available at the following address:
http://stackoverflow-answers-by-scott.googlecode.com/files/1784500.zip
I hope this helps,
Thanks!
EDIT: I updated the code on the Google Code project for your download. I've also zipped up the source code and it is available at the following address:
http://stackoverflow-answers-by-scott.googlecode.com/files/1784500.zip
This now contains a C# project and a VB project.
Hope this helps,
Thanks!
EDIT: In order to get your inner control to send events all the way up the visual tree, you need to change the event type from Tunnel
to Bubble
. This will mean that any events that fire in children walk up the tree to any parent element that handles their event. Thus, in your scenario, you have a window which contains a storyboard with the animations. You then have a control contained within the window, which contains another control. This inner most control requires the button click to 'Bubble' up to the Window, and start the animation. This should be relativity simple.
I updated the code on the Google Code project for your download. I've also zipped up the source code and it is available at the following address:
http://stackoverflow-answers-by-scott.googlecode.com/files/1784500.zip
hope this helps,
Thanks!