title: In WPF, How to create a storyboard with a `Completed` event handler which recognize the button that triggered the storyboard?
body: <p>I want to build a navigation system for my application. The guiding principle that I followed was to carry out everything about animation in XAML so that I could maintain a complete separation between logic and design. Here is how I have tried to build it.</p>
  
  <p>I want to create a <code>Frame</code>, which will be a container of <code>Page</code>s. The navigation system contains buttons, and clicking one of the buttons changes the <code>Content</code> of The <code>Frame</code> to another <code>Page</code>:</p>
  
  <pre><code>FrameName.Content = new PageName();
  </code></pre>
  
  <p>Visually, I want the navigation to be animated: the <code>Frame</code> is faded out, then the <code>Page</code> changes, and finally, the <code>Frame</code> fades back in.</p>
  
  <p>The first step was to create a fade-out animation for the <code>Frame</code> when the user presses the buttons. I duplicated the following code for each button:</p>
  
  <pre><code>&lt;Button x:Name="&lt;!-- Button name --&gt;"&gt;
      &lt;Button.Triggers&gt;
          &lt;EventTrigger RoutedEvent="Button.PreviewMouseDown"&gt;
              &lt;BeginStoryboard&gt;
                  &lt;Storyboard&gt;
                      &lt;DoubleAnimation
                          Storyboard.TargetName="FrameName"
                          Storyboard.TargetProperty="Opacity"
                          To="0" Duration="0:0:0.25" /&gt;
                  &lt;/Storyboard&gt;
              &lt;/BeginStoryboard&gt;
          &lt;/EventTrigger&gt;
      &lt;/Button.Triggers&gt;
      &lt;!-- Button content --&gt;
  &lt;/Button&gt;
  </code></pre>
  
  <p>Then, when the animation ends, I want to call an event handler which replaces the <code>Content</code> of the <code>Frame</code> to the new page. So, I added  a <code>Completed</code> event to the <code>Double Animation</code>:</p>
  
  <pre><code>&lt;DoubleAnimation
      Storyboard.TargetName="FrameName"
      Storyboard.TargetProperty="Opacity"
      To="0" Duration="0:0:0.25"
      Completed="ButtonName_Completed" /&gt;
  </code></pre>
  
  <p>The event handler looks like this:</p>
  
  <pre><code>private void ButtonName_Completed(object sender, EventArgs e)
  {
      FrameName.Content = new PageName();
  }
  </code></pre>
  
  <p>The next step will be to fade in the <code>Frame</code> when its content changes. Unfortunately, I realized that there was no built-in routed event for that. After searching and asking here in stackoverflow, I received the following code, which I do not completely understand, but ultimately works. It creates a custom routed event for changes in the <code>Frame</code>'s content:</p>
  
  <pre><code>public class MyFrame : Frame
  {
      public static readonly RoutedEvent ContentChangedEvent = EventManager.RegisterRoutedEvent("ContentChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyFrame));
  
      public event RoutedEventHandler ContentChanged
      {
          add { AddHandler(ContentChangedEvent, value); }
          remove { RemoveHandler(ContentChangedEvent, value); }
      }
  
      protected override void OnContentChanged(object oldContent, object newContent)
      {
          base.OnContentChanged(oldContent, newContent);
          RaiseEvent(new RoutedEventArgs(ContentChangedEvent, this));
      }
  }
  </code></pre>
  
  <p>The frame is called <code>MyFrame</code> and it actually inherits from <code>Frame</code> and implements a routed event <code>ContentChangedEvent</code>. The XAML for <code>MyFrame</code>:</p>
  
  <pre><code>&lt;local:MyFrame x:Name="FrameName" NavigationUIVisibility="Hidden"&gt;
      &lt;local:MyFrame.Triggers&gt;
          &lt;EventTrigger RoutedEvent="local:MyFrame.ContentChanged"&gt;
              &lt;BeginStoryboard&gt;
                  &lt;Storyboard&gt;
                      &lt;DoubleAnimation
                          Storyboard.TargetName="FrameName"
                          Storyboard.TargetProperty="Opacity"
                          To="1"
                          Duration="0:0:1" /&gt;
                  &lt;/Storyboard&gt;
              &lt;/BeginStoryboard&gt;
          &lt;/EventTrigger&gt;
      &lt;/local:MyFrame.Triggers&gt;
  &lt;/local:MyFrame&gt;
  </code></pre>
  
  <p>So far everything is working fine. My problem is this: I have to write the fade out animation for each button separately since each implements a different event handler when the animation ends, and because it's the same animation every time, the code is unbearably repetitive.</p>
  
  <p>The solution I have tried is to create one event handler for all the buttons to refer to, and in it, I decide, based on the pressed button, which page should be present in the <code>Frame</code>. In this way, I can write the storyboard once, and then begin the animation from the <code>Buttons</code>'s triggers. Later on, I would also like to create a template for the <code>Button</code>s, containing all the relevant triggers so the code will be very short and elegant, I think.</p>
  
  <p>For that, I need to find out which <code>Button</code> the user pressed,  inside the shared event handler (for the <code>Completed</code> event). The problem is that the <code>sender</code> is of type <code>AnimationClock</code> (because the <code>sender</code> is a <code>Storyboard</code>, I think....) and not <code>Button</code>. I can not think of a way to find out which button the user pressed.</p>
  
  <p>I did try to find out by checking which <code>Control</code> is in focus, but it is not very elegant. While it works, it has an annoying bug. When the user clicks the button, and during the animation presses <kbd>tab</kbd>, the focus changes and the application stops (I think because the focus changes from the <code>Button</code> to a control of a different type):</p>
  
  <pre><code>/* Every button begins a storyboard, and when it ends, this method is called */
  private void DoubleAnimation_Completed(object sender, EventArgs e)
  {
      // How to find out which control fired the animation?
      // Tried `Button btn = sender as Button;`
      // But `sender` is of type`AnimationClock`, not `Button`
  
      Button btn = FocusManager.GetFocusedElement(this) as Button;
  }
  </code></pre>
  
  <p>In summary, is there a way to find out which button the user pressed through the shared <code>Completed</code> event handler? If not, is there a better way to build this navigation? Maybe I should write this navigation system in a completely different way?</p>
  
  <p>Thank you very much.</p>
  
  <p><strong>EDIT</strong>
  Could anyone please suggest an accurate title to this question because It's a bit hard to me to summarize... Thanks...</p>