Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetCurrentState on a Storyboard defined and started in XAML

I've searched all over and can't seem to find an answer on this one. My app lives in the world of loose XAML so has to rely on XamlReaders and tree walking to find elements. I have a component that handles the rendering of these XAML pages. That renderer needs to know the state of storyboards that could be running on the loaded XAML. So what I'd like to do in my renderer is something like this: -

var resources = _currentScreenFrameworkElement.Resources;
foreach (var item in resources.Values)
{
    if (item is Storyboard)
    {
        try
        {
            var storyboard = item as Storyboard;
            **if (storyboard.GetCurrentState() == ClockState.Active)**

All well and good. However the problem is when I try an dcheck the CurrentState it throws an exception: -

"Cannot perform action because the specified Storyboard was not applied to this object for interactive control."

Looking around I see it's because I need to make the storyboard controllable. So my question is how do I do this in XAML? I don't start the storyboard in code so can't pass true into the overloaded BeginStoryboard.

like image 991
Slippy Avatar asked Jun 14 '12 08:06

Slippy


1 Answers

I just ran into this same problem so i figured i'd share my findings.

You get that error when your storyboard is not marked as Controllable. Storyboards are marked as Controllable when the Begin method is called.

If you're doing it from code behind then you just use an overload that has this IsControllable boolean argument (list of Begin overloads).

If you've used the BeginAnimation element in Xaml then you'll need to do 2 things.

  1. assign a Name to the BeginAnimation element. The documentation for this property states: "If the Name of BeginStoryboard is unspecified, the Storyboard cannot be interactively affected after it is begun"
  2. When you're trying to interact with your storyboard in codebehind you must pass in the reference to the object that your BeginStoryboard was declared in.

Here's an example showing you step 1 (name the beginstoryboard)

<Button Name="btn1" Content="bla">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard 
             Name="bnt1_beginStoryboard" 
             Storyboard={StaticResource someSharedStoryboard}"/>
    </EventTrigger>
  </Button.Triggers>
</Button>

and here's an example for step 2. Since you've named your beginStoryboard you can use that as a local variable in your class.. or you can just reference the actual storyboard directly. The main point is that you must pass in the owner of the beginStoryboard (which is the button in this case)

//The main point here is that we're passing in btn1
bnt1_beginStoryboard.Storyboard.Stop(btn1);
bnt1_beginStoryboard.Storyboard.SkipToFill(btn1);
bnt1_beginStoryboard.Storyboard.Resume(btn1);

Here's a list of all the "action" methods on a storyboard that require you to pass in the owning framework element: Control a Storyboard After It Starts

like image 171
Bill Tarbell Avatar answered Oct 31 '22 20:10

Bill Tarbell