没有WPF的XAML-动画

没有WPF的XAML-动画,wpf,xaml,xna,animation,Wpf,Xaml,Xna,Animation,我试图在WPF之外完全使用XAML,特别是在XNA应用程序中。到目前为止,我已经设法(非常容易,我很惊讶地承认)从XAML文件在我的XNA应用程序中加载了一些数据。当我决定要设置类的一个属性的动画时,问题就开始了……什么都没有发生:( 以下是我从XAML文件加载的主要类: [ContentPropertyAttribute("Animation")] public class Test : FrameworkContentElement { public string Text { get;

我试图在WPF之外完全使用XAML,特别是在XNA应用程序中。到目前为止,我已经设法(非常容易,我很惊讶地承认)从XAML文件在我的XNA应用程序中加载了一些数据。当我决定要设置类的一个属性的动画时,问题就开始了……什么都没有发生:(

以下是我从XAML文件加载的主要类:

[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); } }
}
<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>
以下是XAML文件:

[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); } }
}
<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>

我好奇死了:)

在WPF应用程序的正常循环之外,我怀疑是否有任何方法可以驱动动画。可能有一些类你可以推动或推动他们,但它很可能是密封的

您可能会在另一个线程上构建自己的动画执行引擎,并确保更新发生在您的UI线程上,这意味着要么找到重用调度程序的方法,要么重新创建类似的东西


这是一个有趣的项目。。。我很想知道你是否成功

哇,这真是太棒了!不幸的是,这可能归结为某些内部API中正在进行的某种“更新”类型的调用。如果你不调用它,动画将不会动画。。。就像XNA游戏没有调用Update方法一样


我非常想了解更多关于你是如何做到这一点的信息,以及你的成功程度。你应该在某处写一篇博客文章:-)

尽管XAML独立于WPF,但视觉元素却不是。特别是,动画和布局是WPF的一部分,取决于WPF管道的存在——通过应用程序对象、PresentationSource(如HwndSource)、XBAP PresentationHost.exe等

因此,您可以在XAML中读取并获取测试对象的对象图,其中包含一个子情节提要对象,但该测试对象在放置到WPF上下文中之前不会连接到动画或布局引擎。XAML提供给您的只是一个哑内存对象图:是WPF而不是XAML使对象“活动”

因此,正如本所说,你可能最终需要自己“推动或推动”动画。我不知道有任何关于如何做到这一点的文档,但通过在Reflector中查看,它看起来像是关键API,其中的文档说:

值会立即更新为 反映由于 参见Kalignedtolastick,尽管 屏幕不反映这些更改 直到屏幕更新

注意第二条。通常,WPF会在可视对象值更改时处理屏幕的更新。如果您没有使用WPF,那么就由您读取更改的值并相应地重新绘制屏幕:您没有WPF布局管理器来为您处理它

最后,请注意,我还没有测试SeekAlignedToLastTick是否能在没有加载WPF管道的环境中工作。听起来应该如此,因为它不在乎是WPF还是用户代码在驱动时钟,但我不能做出任何承诺。。。虽然我承认你让我好奇


更新:我快速尝试了一下,它似乎确实有效。这是一个在Windows窗体中托管动画的演示(在本例中使用的是一个普通的ol'Windows窗体计时器,但在XNA中,我想框架将为您提供一个游戏计时器——我不知道XNA,所以没有尝试)。假设您有一个带有计时器(timer1)和标签(label1)的普通Windows窗体,并且项目引用了WPF程序集

首先,我对你们班的简化版本:

[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; }
}
现在,使用WPF代码从XAML加载其中一个婴儿并开始动画:

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;
}
test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
Storyboard.SetTarget(test.Animation, test);
test.Animation.Begin();

我已经存储了动画的开始时间,并用它来计算我们进入动画的距离。WinForms计时器有点粗糙,但这足以证明其概念;毫无疑问,XNA会有更好的产品。然后我调用Storyboard.SeekAlignedToLastTick,它会更新动画值。没有任何东西会自动显示,因为我的XAML对象没有连接到显示上,但我可以检查它的测试属性并验证它是否确实正在制作动画。实际上,我会用它来更新XAML对象所代表的任何XNA可视元素的位置或方向。

仅供参考,我现在将记录我是如何使用XNA实现这一点的。感谢itowlson提供了缺少的链接:否则我必须创建一个带有不可见窗口的空应用程序

我们用XAML定义类及其动画(请注意xmlns指令):

在XNA游戏类的初始化函数中,我们反序列化xaml文件并启动动画:

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;
}
test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
Storyboard.SetTarget(test.Animation, test);
test.Animation.Begin();
更新功能将GameTime作为输入,提供TotalGameTime字段,用于存储自应用程序启动以来经过的时间跨度:这正是故事板需要勾选的内容:

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);
}
在“绘制”方法中,我们可以使用“旋转”属性绘制一些文本,该属性现在将正确设置动画:

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);
}
protected override void Draw(游戏时间游戏时间)
{
图形设备。清晰(颜色:矢车菊蓝);
spriteBatch.Begin();
spriteBatch.DrawString(Content.Load(“font”)、test.Text、test.Position、test.Color、(float)test.Rotation、Vector2.Zero、1.0f、SpriteEffects.None、0.0f);
spriteBatch.End();
基础。抽签(游戏时间);
}

多么酷的主意!你有没有试过在普通的WPF应用程序中调试动画,看看哪些组件触发了更新?我知道这是一个老问题,但我很好奇你在这方面做了多少?我一直在玩弄在XNA内部托管XAML的想法。甚至这个显示如何添加基本动画的问题也是一个很好的开始。做得很好!我真的很震惊,事情竟如此直截了当。我原以为会有很多密封类的方式。