XAML without WPF - animation

I am trying to use XAML completely outside of WPF, in particular inside an XNA application. So far I have managed (quite easily, I am surprised to admit) to load some data inside the XNA application from the XAML file. The problems begin when I decided that I want to revive one of the properties of my class ... Nothing happens: (

Here is the main class that I am loading from the XAML file:

[ContentPropertyAttribute("Animation")] public class Test : FrameworkContentElement { public string Text { get; set; } public Vector2 Position { get; set; } public Color Color { get; set; } public Storyboard Animation { get; set; } public static DependencyProperty RotationProperty = DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0)); public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } } } 

Here is the XAML file:

 <l:Test xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA" xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework" xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore" Text="Testo" Position="55,60" Color="0,255,255,255"> <a1:Storyboard> <a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation" From="0" To="360" Duration="00:00:10.0"/> </a1:Storyboard> </l:Test> 

And here is the loading and loading animation (attempt):

 Test test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test; test.Animation.Begin(test); 

I'm dying of curiosity :)

+7
animation wpf xna xaml
source share
4 answers

For reference only, I will now document how I was able to do this work with XNA. Thanks to itowlson for providing the missing link: otherwise I had to create an empty application with an invisible window ...

We define a class with its animation in XAML (note the xmlns directives):

 <l:Test xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA" xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework" xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore" Text="Testo" Position="55,60" Color="0,255,255,255"> <a1:Storyboard> <a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation" From="0" To="6.28" Duration="00:00:2.0" RepeatBehavior="Forever"/> </a1:Storyboard> </l:Test> 

The code-behind class test is as follows:

 [ContentPropertyAttribute("Animation")] public class Test : DependencyObject { public string Text { get; set; } public Vector2 Position { get; set; } public Color Color { get; set; } public Storyboard Animation { get; set; } public static DependencyProperty RotationProperty = DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0)); public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } } } 

In the Initialize function of the XNA Game class, we deserialize our xaml file and start the animation:

 test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test; Storyboard.SetTarget(test.Animation, test); test.Animation.Begin(); 

The Update function takes as an input the GameTime, which offers the TotalGameTime field, which stores the TimeSpan of the time that has passed since the application was launched: this should be noted:

 protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); test.Animation.SeekAlignedToLastTick(gameTime.TotalGameTime); base.Update(gameTime); } 

In the drawing method, we can simply draw the text using the Rotation property, which will now be correctly animated:

 protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.DrawString(Content.Load<SpriteFont>("font"), test.Text, test.Position, test.Color, (float)test.Rotation, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f); spriteBatch.End(); base.Draw(gameTime); } 
+4
source share

Although XAML is not dependent on WPF, visual elements are not. In particular, animation and layout are part of WPF and depend on the presence of the WPF system — through an Application, PresentationSource object such as HwndSource, XBAP PresentationHost.exe, etc.

So you can read in your XAML and get a graphical object of the Test object with a child Storyboard object, but this test object is not connected to the animation or layout mechanisms until it is placed in the WPF context. All that XAML receives is a dumb graphic object in memory: it is WPF, not XAML, which makes the objects “live”.

Since, as Ben says, you will probably have to “push or push” the animation. I don't know any documentation on how to do this, but because it works in Reflector, it looks like the Storyboard.SeekAlignedToLastTick API key the docs are talking about:

The values ​​updated immediately reflect the changes caused by SeekAlignedToLastTick, although the screen does not reflect these changes until the screen refreshes.

Please note that the second sentence. Typically, WPF handles updating the screen as the values ​​of visual objects change. If you are not using WPF, you need to read the changed values ​​and redraw the screen accordingly: you do not have a WPF layout manager to process it.

Finally, note that I have not tested whether SeekAlignedToLastTick will work in an environment without loading WPF plumbing. It seems like it should be, because it doesn’t matter if it is WPF or the user code that controls the clock, but I can’t make any promises ... although I admit I'm curious!


UPDATE: I did it quickly and it seems to work. Here is a demonstration of hosting animations in Windows Forms (in this case using a simple Windows Forms timer, but in XNA I assume that the structure will provide you with a game timer - I haven’t tried because I don’t know XNA). Suppose you have a vanilla Windows form with a timer (timer1) and a label (label1), and the project references WPF assemblies.

Firstly, my simplified version of your class:

 [ContentProperty("Animation")] public class Fie : DependencyObject { public double Test { get { return (double)GetValue(TestProperty); } set { SetValue(TestProperty, value); } } public static readonly DependencyProperty TestProperty = DependencyProperty.Register("Test", typeof(double), typeof(Fie), new FrameworkPropertyMetadata(0.0)); public Storyboard Animation { get; set; } } 

Now, the WPF code to load one of these babies from XAML and start the animation:

 private Fie _f; private DateTime _startTime; public Form1() { InitializeComponent(); string xaml = @"<local:Fie xmlns:local=""clr-namespace:AnimationsOutsideWpf;assembly=AnimationsOutsideWpf"" xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" > <Storyboard> <DoubleAnimation Storyboard.TargetProperty=""Test"" From=""0"" To=""360"" Duration=""00:00:10.0""/> </Storyboard> </local:Fie>"; _f = (Fie)XamlReader.Load(XmlReader.Create(new StringReader(xaml))); Storyboard.SetTarget(_f.Animation, _f); _f.Animation.Begin(); _startTime = DateTime.Now; timer1.Enabled = true; } 

Please note that I needed to set the storyboard target as the XAML object I just downloaded. This does not happen automatically. I tried to do this using Storyboard.TargetName in XAML, but that didn't seem to work - you might have more luck.

The final lines are just a setting for a timer callback:

 private void timer1_Tick(object sender, EventArgs e) { TimeSpan sinceStart = DateTime.Now - _startTime; _f.Animation.SeekAlignedToLastTick(sinceStart); label1.Text = _f.Test.ToString(); } 

I saved the start time of the animation and used this to calculate how far we are in the animation. WinForms timers are a little rude, but that's enough to prove the concept; no doubt XNA will have something better. Then I call Storyboard.SeekAlignedToLastTick, which updates the animated values. Nothing is displayed automatically because my XAML object is not connected for display, but I can check its Test property and make sure it really animates. In fact, I would use this to update the position or orientation of any XNA visual element represented by an XAML object.

+6
source share

Outside of the normal WPF application loop, I doubt there is a way to control the animation. There may be some class that you can click on or push it on, but it is probably sealed.

You will probably create your own animation engine running in another thread, and make sure that updates happen in your user interface thread, which means either looking for a way to reuse the Dispatcher or recreating something like that.

This MSDN article may provide some useful information in this endeavor.

This is an interesting project ... I would be interested to hear if you succeed!

0
source share

Wow, this is pretty amazing! Unfortunately, most likely, this will lead to some type of “upgrade” that runs in some internal API. And if you do not name it, the animation will not animate ... as if the Update method was not called in the XNA game.

I would really like to know more about how you do this and what level of success you will find. You must write an article / blog article :-)

0
source share

All Articles