2010-03-05 39 views
7

我想在WPF外部完全使用XAML,特別是在XNA應用程序中。到目前爲止,我已經管理(很容易,我驚訝地承認)從XAML文件加載我的XNA應用程序中的一些數據。這些問題開始的時候,我決定,我想我的動畫類的屬性之一......什麼也沒有發生:(XAML沒有WPF - 動畫

這裏是主類我從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); } } 
} 

這裏XAML文件:

<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> 

這裏是加載和啓動動畫(未遂):

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

我是臨死好奇:)

+0

真是個好主意!您是否嘗試過在普通WPF應用程序中調試動畫以查看哪些組件觸發更新? – 2010-03-05 14:51:44

+0

我知道這是一個老問題,但我很好奇你有多遠?我一直在玩弄自己在XNA內部託管XAML的想法。即使這個問題顯示如何添加基本的動畫是一個很好的開始。 – 2012-05-05 05:48:28

回答

4

僅供參考,現在我將記錄如何使用XNA進行此項工作。感謝itowlson提供缺少的鏈接:否則,我必須創建一個空的應用程序與一個不可見的窗口...

我們定義的類及其在XAML動畫(注意的xmlns指令):

<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> 

的「代碼隱藏」級測試如下:

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

在初始化函數的XNA遊戲類,我們反序列化我們的xaml文件並啓動動畫:

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

該更新功能需要輸入一個GameTime,它提供存儲,因爲該應用程序推出經過的時間量的時間跨度的TotalGameTime場:這正是一個Storyboard需要打勾:

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

在draw方法我們可以使用Rotation屬性繪製一些文本,該屬性現在可以正確生成動畫:

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

在WPF應用程序的正常循環之外,我懷疑是否有任何方法來驅動動畫。可能有一些課程可以推動或驅動它們,但它可能是密封的。

您可能會最終創建自己的動畫執行引擎,運行在另一個線程上,並確保更新發生在您的UI線程上,這意味着要麼找到重用Dispatcher或重新創建類似的方法。

This MSDN article may provide some useful information in this endeavor

這是一個有趣的項目。我很好奇,如果你成功的來信!

0

哇,這真是太棒了!不幸的是,它可能會歸結爲某些內部API中正在進行的某種「更新」類型的調用。如果你不叫它,動畫就不會動畫......就像XNA遊戲沒有調用Update方法一樣。

我非常想知道更多關於你如何做這件事的信息以及你找到的成功程度。你應該在某處寫一篇博客帖子/文章:-)

6

雖然XAML獨立於WPF,但視覺元素卻不是。特別是,動畫和佈局是WPF的部分,並依賴於WPF管道存在 - 通過應用對象,PresentationSource諸如HwndSource,所述XBAP PresentationHost.exe等

這樣你就可以讀入您的XAML並獲取包含子Storyboard對象的Test對象的對象圖,但該Test對象不會連接到動畫或佈局引擎,直到將其放置在WPF上下文中。 XAML帶給你的所有內容都是一個愚蠢的內存對象圖:它是WPF,而不是XAML,它使對象「活着」。按照Ben的說法,你可能最終需要自己「推動或製作」動畫。我不知道如何做到這一點的任何文檔,但在反射閒逛,看起來關鍵API是Storyboard.SeekAlignedToLastTick,它的文檔說:

值立即更新到 反映由於 SeekAlignedToLastTick的變化,即使 屏幕沒有反映這些變化 直到屏幕更新。

請注意,第二條款。通常,WPF會在可視對象值發生更改時處理屏幕更新。如果你不使用WPF,那麼你需要閱讀已更改的值並相應地重新繪製屏幕:你沒有WPF佈局管理器來爲你處理它。

最後,請注意我還沒有測試SeekAlignedToLastTick是否可以在沒有加載WPF管道的環境中工作。它聽起來喜歡它應該,因爲它不關心是否WPF或用戶代碼是驅動時鐘,但我不能作出任何承諾......雖然我承認你讓我好奇!


更新:我考慮了一個快速去,和它似乎工作。這是一個在Windows窗體中託管動畫的演示(在這種情況下,使用普通的Windows窗體計時器,但在XNA中,我猜框架會爲您提供一個遊戲計時器 - 沒有嘗試,因爲我不知道XNA)。假設你有一個帶定時器(timer1)和標籤(label1)的vanilla 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; 
} 

注意,我不得不將故事板的目標設置爲我剛剛加載的XAML對象。這不會自動發生。我試圖在XAML中使用Storyboard.TargetName來做到這一點,但這似乎並不奏效 - 你可能會有更多的運氣。

最後幾行只是爲計時器回調設置:

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

    label1.Text = _f.Test.ToString(); 
} 

我已經存儲了動畫的開始時間,並使用了多遠的動畫,我們來計算。 WinForms定時器有點粗糙,但這足以證明概念;毫無疑問XNA會有更好的東西。然後我調用Storyboard.SeekAlignedToLastTick,它更新動畫值。沒有任何內容會自動顯示,因爲我的XAML對象沒有連接起來顯示,但我可以檢查它的Test屬性並驗證它確實是動畫。實際上,我會用它來更新XAML對象所代表的任何XNA可視元素的位置或方向。

+0

做得很好!我真的很震驚,這是直截了當的。我預計會有很多密封課程。 – 2010-03-07 14:29:57