rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

[Unity] Dynamically changing Animation Values with Bindings

08 Oct 2014, 01:14

Hey all, hopefully this is something simple that I have just overlooked. I'm trying to animate the ViewBox property of an ImageBrush through an animation. The catch is that I need to specify the value to animate to at runtime so I figured this would be a perfect time to take a stab at adding properties to the user control and use bindings for this.

Below is the code I current have set up and I am calling AnimateToView with a new Rect(50, 20, 348, 236) so the image being displayed should zoom in. However, nothing happens. when I update the animation storyboard to just use a hard coded value of To="50, 20, 348, 236" it works as expected. So I'm not sure what it is that I am missing. Any thoughts?
<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	xmlns:noesis="clr-namespace:NoesisGUIExtensions" xmlns:five="clr-namespace:FiveGui"
	mc:Ignorable="d" x:Class="FiveGui.UIImageViewer" x:Name="_UIImageViewerControl" d:DesignWidth="1920" d:DesignHeight="1080">
    <UserControl.Resources>
		<ResourceDictionary>
            <Storyboard x:Key="NextFrame">
                <RectAnimation To="{Binding Frame}" Duration="0:0:1" Storyboard.TargetName="_Image" Storyboard.TargetProperty="Viewbox"/>
            </Storyboard>
        </ResourceDictionary>
	</UserControl.Resources>

	<Grid x:Name="LayoutRoot">
	    <Rectangle>
	    	<Rectangle.Fill>
	    		<ImageBrush x:Name="_Image" ImageSource="../GUIResources/DefaultImage.png" Viewbox="0,0,448,276" ViewboxUnits="Absolute"/>
	    	</Rectangle.Fill>
        </Rectangle>
	</Grid>
</UserControl>
using Noesis;

namespace FiveGui
{
    [Noesis.Extended]
    [Noesis.UserControlSource("Assets/GUI/GUIControls/UIImageViewer.xaml")]
    public class UIImageViewer : Noesis.UserControl
    {
        public static DependencyProperty FrameProperty = DependencyProperty.Register("Frame", typeof(Rect), typeof(UIImageViewer), new PropertyMetadata(null));

        public Rect Frame
        {
            get { return GetValue<Rect>(FrameProperty); }
            set { SetValue<Rect>(FrameProperty, value); }
        }

        private Storyboard _nextFrame;

        public void OnPostInit()
        {
            _nextFrame = FindStringResource<Storyboard>("NextFrame");
            Frame = new Rect(0, 0, 448, 276);
        }

        private void AnimateToView(Rect rect)
        {
			Frame = rect;
			_nextFrame.Begin(this);
        }
    }
}
 
User avatar
sfernandez
Site Admin
Posts: 3184
Joined: 22 Dec 2011, 19:20

Re: [Unity] Dynamically changing Animation Values with Bindi

08 Oct 2014, 12:11

Hi,

The Binding you are using in the RectAnimation expects a DataContext to search for the Frame property. You have to set it when your UserControl is initialized:
    public class UIImageViewer : Noesis.UserControl
    {
        // ...

        public void OnPostInit()
        {
            SetDataContext(this);

            _nextFrame = FindStringResource<Storyboard>("NextFrame");
            Frame = new Rect(0, 0, 448, 276);
        }

        // ...
    }
 
rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Re: [Unity] Dynamically changing Animation Values with Bindi

08 Oct 2014, 17:04

Added that in and still got nothing.
 
User avatar
sfernandez
Site Admin
Posts: 3184
Joined: 22 Dec 2011, 19:20

Re: [Unity] Dynamically changing Animation Values with Bindi

08 Oct 2014, 18:18

I tried the attached scene in 1.1.11 version and worked correctly.
Maybe you have a more complex scenario, could you please attach your complete scene here (or send it to me privately)?
Attachments
AnimationBinding.unitypackage
(516.04 KiB) Downloaded 361 times
 
rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Re: [Unity] Dynamically changing Animation Values with Bindi

08 Oct 2014, 22:30

Using the Image viewer by itself directly in the Noesis GUIPanel, the Frame property works as expected and shown in your text example. However, as soon as I add the user control to another xaml file, the Frame property stops working.

Example:
<Page
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
	xmlns:noesis="clr-namespace:NoesisGUIExtensions" xmlns:five="clr-namespace:FiveGui" 
	mc:Ignorable="d" x:Name="_PageRoot" d:DesignWidth="1440" d:DesignHeight="810" RenderTransformOrigin="0.5,0.5">
	<Viewbox x:Name="_ControllerRoot" Stretch="UniformToFill" HorizontalAlignment="Center" VerticalAlignment="Center">
		<Grid x:Name="_ContentRoot" Width="1920" Height="1080">
            <five:UIImageViewerx:Name="_ImageViewer"/>
		</Grid>
	</Viewbox>
</Page>
Should I submit a bug for this, or am I doing something wrong?
 
User avatar
sfernandez
Site Admin
Posts: 3184
Joined: 22 Dec 2011, 19:20

Re: [Unity] Dynamically changing Animation Values with Bindi

09 Oct 2014, 01:17

Ok, I was able to reproduce the error. We will fix it in a future release.

Meanwhile I found a workaround. Instead of defining the storyboard in the UserControl.Resources, do it in the inner Grid panel:
<UserControl
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   xmlns:noesis="clr-namespace:NoesisGUIExtensions" xmlns:five="clr-namespace:FiveGui"
   mc:Ignorable="d" x:Class="FiveGui.UIImageViewer" x:Name="_UIImageViewerControl" d:DesignWidth="1920" d:DesignHeight="1080">
   <Grid x:Name="LayoutRoot">
      <Grid.Resources>
         <Storyboard x:Key="NextFrame">
            <RectAnimation To="{Binding Frame}" Duration="0:0:1" Storyboard.TargetName="_Image" Storyboard.TargetProperty="Viewbox"/>
          </Storyboard>
       </Grid.Resources>
       <Rectangle>
          <Rectangle.Fill>
             <ImageBrush x:Name="_Image" ImageSource="../GUIResources/DefaultImage.png" Viewbox="0,0,448,276" ViewboxUnits="Absolute"/>
          </Rectangle.Fill>
        </Rectangle>
   </Grid>
</UserControl>
And set the DataContext in that Grid:
    public class UIImageViewer : Noesis.UserControl
    {
        // ...

        public void OnPostInit()
        {
            var layout = FindName<Grid>("LayoutRoot");
            layout.SetDataContext(this);
            
            _nextFrame = layout.FindStringResource<Storyboard>("NextFrame");
            Frame = new Noesis.Rect(0, 0, 640, 480);
        }

        // ...
    }
This should work ;)
 
rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Re: [Unity] Dynamically changing Animation Values with Bindi

10 Oct 2014, 17:51

Found another fun issue related to all this. Apparently once a property is animated, it can no longer be changed directly via Set, in the case of this code, after animating the ImageBox's Viewbox property I can no longer set that property directly using SetViewbox. No error is thrown, no indication as to what is wrong. I've tried calling Stop and Remove on the Storyboard with no luck. Know of any workarounds? So far the only one I've been able to think of is just having a "Reset" storyboard with a 0 duration that resets the values back to what I want them to be.

Also I'm not sure if this is a bug with just ImageBrushes or animating any property in general. Haven't tested all cases yet.
 
User avatar
sfernandez
Site Admin
Posts: 3184
Joined: 22 Dec 2011, 19:20

Re: [Unity] Dynamically changing Animation Values with Bindi

10 Oct 2014, 18:23

DependencyProperty follows a value precedence scheme to determine how to obtain the effective value of the property. As you can see in the previous link, an animated value has precedence over a local value (when you do a SetValue).

So when a property is animated, and you want to set a new value in code, you need to clear the property first:
rectangle.ClearAnimation(Shape.StrokeThicknessProperty);
rectangle.SetStrokeThickness(2.0f);
I have to check again the behavior of WPF, but I think it should be done the same way.
Anyway I'm seeing we have a different API compared to WPF, we will change it to make code compatible between WPF and Noesis.
 
rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Re: [Unity] Dynamically changing Animation Values with Bindi

10 Oct 2014, 18:26

I'm trying to set the value after the animation has been complete, not during the animation. I would have thought that once an animation has been complete the precedence would have been cleared automatically.

Thanks for the info, I'll give this a shot.

Edit: Thanks again for the Binding work around. Works great, simplifies my code a lot as I can use the same binding in several areas instead of needing direct references to all of those pieces.
 
User avatar
sfernandez
Site Admin
Posts: 3184
Joined: 22 Dec 2011, 19:20

Re: [Unity] Dynamically changing Animation Values with Bindi

13 Oct 2014, 14:17

I'm trying to set the value after the animation has been complete, not during the animation. I would have thought that once an animation has been complete the precedence would have been cleared automatically.

Thanks for the info, I'll give this a shot.
The animation value is just another value source, in fact the animation value is not modifying the local value (that remains the same during all the animation duration). You can specify how your storyboard behaves when the animation completes by setting the FillBehavior property:
  • <Storyboard x:Key="anim"> or <Storyboard x:Key="anim" FillBehavior="HoldEnd"> is the default behavior, that will maintain the last animated value after animation ends.
  • <Storyboard x:Key="anim" FillBehavior="Stop"> will remove last animated value after animation ends, so the local (or any other value with less precedence) will be recovered.
Edit: Thanks again for the Binding work around. Works great, simplifies my code a lot as I can use the same binding in several areas instead of needing direct references to all of those pieces.
You're welcome :)

Who is online

Users browsing this forum: No registered users and 8 guests