Hands-On Lab XNA 3D 模型浏览器

 

 

Hands-On Lab

XNA 3D 模型浏览器

 

 

Lab version:    1.0.0

Last updated:          2/29/2012

 


 

内容

概述... 3

课程... 5

任务 1 – 使用background transfer 服务... 5

任务 2 – 将 3D XNA模型嵌入到 Silverlight 应用程序中... 11

课程总结... 22

 

 


 

 

 

WindowsPhone提供了两种不同的用户界面编程模型:Silverlight和 XNA。Silverlight是最常用的应用程序开发方式,应用程序可以使用控件、显示很多数据。XNA是2D和3D游戏开发方式。当年您也可以使用Silverlight来写游戏,或者使用XNA来编写一个以数据为中心的应用程序。每个应用程序框架都有其自身的优势;选择合适的编程模型,可以使您的生产率大幅提高,并且缩短应用上市时间。

在Windows Phone 7版本中,您不得不选择一个应用程序框架来开发您的应用程序或游戏。而Windows® Phone Mango中允许您同时使用两个编程框架,Silverlight应用程序中可以嵌入XNA模块,XNA应用程序中也可以嵌入Silverlight元素。这样的话,可以保持两个应用程序框架的优势。例如,在Windows Phone Mango之前,应用程序开发者在XNA中展现非拉丁字母的文字时会比较困难。UIElementRenderer提供了一个强制方法来解决这个问题。您可以使用UIElementRenderer来展现SilverlightTextBlock的元素(或者其他可以显示字体的颜色)。通过Silverlight的高级功能和矢量图,文本将会以XNA材质的方式进行显示。

WindowsPhone Mango支持新的background transfer服务,可以独立运行您的应用程序。当您的应用程序处于隐藏状态或者用户导航到其他页面时,Transfers可以继续执行。

本次实验将会演示如何使用background transfer service来下载嵌入的XNA模型。

提示: 这次动手实验是基于Windows Phone Mango的beta版,因此RTM在API方面可能会有一些变化。

课程目标

本次实验将帮助您完成下列目标:

·        编写应用程序使用background transfer service服务

·        在Silverlight应用程序中嵌入3D XNA 模型

 

前提条件

您在开始本次动手实验前,请先确认达到下列前提条件:

·        Microsoft Visual Studio 2010 或者 Microsoft Visual C# Express2010, 和 Windows® Phone 7 Codenamed “Mango” Developer Tools,下载地址:http://go.microsoft.com/?linkid=9772716

·        如何创建 Windows® Phone 7应用程序的支持
(如果您是新的Windows® Phone 7开发者,您可以首先阅读: http://msdn.microsoft.com/en-us/gg266499).

 

实验 提纲

这个动手实验将包括一个完整的实验,包括下列的任务:

1.      编写应用程序使用background transfer service服务

2.      在Silverlight应用程序中嵌入3D XNA 模型

 

预计完成时间

完成该实验预计花费15到30分钟的时间。

 


 

 

本次课程的起始点在实验安装目录的Source\Begin文件夹中,打开里边的解决方案。

 

任务 1 – 使用 background transfer service服务

 

该应用程序从远程下载位置上,下载XNA模型。预先下载的模型将会出现在LocalModels列表中,而能够被下载的模型将出现在RemoteModels列表中。

 

本次任务将演示如何使用BackgroundTransferService类开始一个新的transfer或者管理已有的transfer。当用户点击Download按钮,应用程序开始下载并且监控其进度,当下载完成时,将该项目移动到Local Models列表中。

提示: 使用BackgroundTransferService 类和相关的API 类,需要添加Microsoft.Phone程序集的引用。该引用在Windows Phone 7应用程序工程中被默认添加。

1.       创建一个新的background transfer非常简单。您只需要创建新的 BackgroundTransferRequest 对象,并将其添加到BackgroundTransferService队列中。  BackgroundTransferRequest将信息存储在一个单独的传输队列中。

打开ModelViewer\Downloads工程文件夹下的Download.cs 文件并用下列代码替换空的Start方法:

C#

public void Start()

{

    //Create a new backgroundtransfer request

    BackgroundTransferRequest request = new BackgroundTransferRequest(requestUri,downloadUri);

    requestId =request.RequestId;

    //Add new request to the queue

    BackgroundTransferService.Add(request);

}

requestUri 变量指定文件从哪里下载,而downloadLocation变量指定本地文件的存储位置。requestId变量将在稍后使用。

当应用程序添加一个传输请求到BackgroundTransferService队列时,Windows Phone操作系统在一个后台任务中执行该请求。用户如果从应用程序中推出,传输仍然将继续。

提示: 您的传输请求也许不会被立即执行。后台传输服务使用特殊的调度程序来管理传输请求。例如,当电量不足时,为了节省电池,它也许会暂停当前活动的传输。

2.       为了在Local Models列表中添加下载完成的模型,应用程序必须监听BackgroundTransferRequestTransferStatusChanged事件。该事件会传递BackgroundTransferEventArgs对象, 其中会包含触发事件的请求的引用。通过检查请求的TransferStatus属性,你可以检测下载是否完成和响应是否正确。在这个例子中,您需要移动下载文件到本地XNA模型存储的位置。

Start方法中的请求启动之前,监听TransferStatusChanged事件:

C#

public void Start()

{

    //Create a new backgroundtransfer request

    BackgroundTransferRequest request = new BackgroundTransferRequest(requestUri,downloadUri);

    requestId =request.RequestId;

 

    //Subscribe to the events

    request.TransferStatusChanged+= request_TransferStatusChanged;

 

    //Add new requestto the queue

    BackgroundTransferService.Add(request);

}

一旦下载完成,事件处理函数将移动文件到正确位置,通知应用程序,然后将BackgroundTransferRequest对象从队列中移除。WindowsPhone 7不会从队列中自动移除完成的传输,所以开发者需要自己删除。因此应用程序不需要监视传输请求,事件处理方法会从TransferStatusChanged事件中清除掉。添加下列的方法:

C#

private void request_TransferStatusChanged(object sender, BackgroundTransferEventArgse)

{

    BackgroundTransferRequest request = e.Request;

    if(request.TransferStatus == TransferStatus.Completed)

    {

        request.TransferStatusChanged -= request_TransferStatusChanged;

 

        OnDownloadFinished(request);

    }

}

 

private void OnDownloadFinished(BackgroundTransferRequest request)

{

    //Move downloadedfile to its final location

    Storage.MoveFile(downloadPath, targetPath);

 

    //Notify listeners(UI) about download complete

    if(DownloadFinished != null)

        DownloadFinished(this, EventArgs.Empty);

 

    //Remove the requestfrom the queue

    BackgroundTransferService.Remove(request);

}

3.       同样,您可以通过BackgroundTransferRequestTransferProgressChanged事件,通过传递的BackgroundTransferEventArgs对象来监听处理过程。Download对象会向应用程序报告下载的进度,ModelMetadata会跟踪进度并更新UI上的蓝色进度条。

Start方法中添加事件处理函数:

C#

public void Start()

{

   request.TransferStatusChanged += request_TransferStatusChanged;

   request.TransferProgressChanged+= request_TransferProgressChanged;

   …

}

事件处理函数将会检查传输是否激活。如果需要,可以从BackgroundTransferEventArgs对象中的Request属性中获取进度信息。最终将触发DownloadProgress事件:

C#

private void request_TransferProgressChanged(object sender, BackgroundTransferEventArgse)

{

    BackgroundTransferRequest request = e.Request;

    //While the transferis still active

    if(request.TransferStatus== TransferStatus.Transferring)

    {

        //Notifyabout progress change

        if(DownloadProgress!= null)

            DownloadProgress(this, new DownloadProgressEventArgs(request.BytesReceived, request.TotalBytesToReceive));

    }

}

最后,但不是最重要的,当下载完成时,你必须清除不用的事件处理函数。修改request_TransferStatusChanged方法:

C#

private void request_TransferStatusChanged(object sender, BackgroundTransferEventArgse)

{

    …

    request.TransferStatusChanged -= request_TransferStatusChanged;

    request.TransferProgressChanged -=request_TransferProgressChanged;

    …

}

提示: 当应用程序休眠或关闭时,后台传输服务会继续运行。在这个过程中,服务队列继续所有的处理和状态事件,等待应用程序恢复。当你的应用程序恢复,事件将会被触发,因此你的应用程序可以收到在后台状态下的所有更新。

4.       应用程序允许用户取消进行中的下载。当下载开始时,UI会在RemoteModels列表中显示一个带“X”的按钮。当用户点击这个按钮时,ModelMetadata对象调用Abort方法,为每一个Download对象设置模块对象。

Abort 方法调用BackgroundTransferServiceFind 方法根据特别的requestId,来恢复BackgroundTransferRequest。如果发现了对应的请求,应用程序从队列中删除掉。

C#

public bool Abort()

{

    BackgroundTransferRequest request = BackgroundTransferService.Find(requestId);

 

   if (request !=null)

   {

        isAborted = true;

       BackgroundTransferService.Remove(request);

   }

 

   return request !=null;

}

提示: 后台传输服务API提供访问自己应用程序的传输请求队列。你不能访问其他应用程序的传输队列。

BackgroundTransferRequest 从队列中去掉时,BackgroundTransferService触发TransferStatusChanged事件,设置请求的TransferStatus属性为TransferStatus.Completed,就如同请求没有被取消一样。Abort方法设置isAborted标记位为true,因此TransferStatusChanged事件控制要分清这两个情况:

C#

private void request_TransferStatusChanged(object sender,BackgroundTransferEventArgs e)

{

   …

    if (isAborted)

       OnDownloadAborted();

    else

       OnDownloadFinished(request);

   …

}

OnDownloadAborted 方法删除临时下载文件,触发DownloadAborted事件通知应用程序:

C#

private void OnDownloadAborted()

{

    //Delete the temporarydownload file

    Storage.DeleteFile(downloadPath);

 

    //Notifyabout the aborted download

    if(DownloadAborted!= null)

        DownloadAborted(this, EventArgs.Empty);

}

5.       Windows Phone 7 Mango限制后台传输请求队列最多为5个。添加更多的请求将会导致应用程序抛出异常。因为Remote Models里的每一个项目也许会产生多于一个的传输请求,用户也许会尝试同时下载所有的远程模型,这样会产生过多的同时请求。

应用程序可以在DownloadManager类中实现自己的内存队列,可以解决这个问题。DownloadManagerStartDownloadProcessPendingDownloads方法演示了如何使用这个队列。

C#

public static voidStartDownload(Download download)

{

    if(BackgroundTransferService.Requests.Count()< 5)

    {

        …

        download.Start();

    }

    else

    {

        pendingDownloads.Enqueue(download);

    }

}

 

private static voidProcessPendingDownloads()

{

    if(pendingDownloads.Count > 0)

    {

        Download download = pendingDownloads.Dequeue();

        StartDownload(download);

    }

}

当活动下载数量达到限制,应用程序将请求加入到pendingDownloads队列,而不会加入到BackgroundTransferService队列中。

提示:DownloadManager 类中使用的队列是简单的实现。因为下载等待队列不能持续保留(例如,在应用程序的独立存储中),如果应用程序关闭或启动墓碑机制,他们将不会被恢复。这个实现中没有包括最佳实践,只适合本次动手实验。

 

任务 2 – 将3D XNA 模型嵌入到 Silverlight 应用程序

 

当用户选择本地模型,应用程序导航到GamePage页面,用Silverlight内容来显示XNA模型。本次任务将演示如何创建Silverlight/XNA混合应用程序。

实现整合功能的关键组件是SharedGraphicsDeviceManager类,该类让应用程序开发者使用XNA绘制的直接模式来代替Silverlight绘制的保留模式。

当您安装Windows Phone Development Tools,两个工程模板支持Silverlight/XNA混合模式的应用程序,Silverlightfor Windows Phone文件夹下的WindowsPhone 3D Graphics Application模板和XNA Game Studio 4.0文件夹下的Windows Phone Rich Graphics Application (4.0) 模板。

提示: 这些模板在标准的Windows Phone Application模板基础上增加了一些小的改进。首先在App.xaml.cs中声明SharedGraphicsDeviceManager变量;其次,App类实现IServiceProvider接口为了模拟纯粹XNA应用程序的行为。IServiceProvider.GetService方法返回存在于ApplicationLifetimeObjects集合中的对象。

1.      为了在Silverlight页面中,显示3D XNA模型。打开GamePage.xaml.cs文件,添加OnNavigatedTo方法:

C#

protected override void OnNavigatedTo(NavigationEventArgs e)

{

    // Set the sharingmode of the graphics device to turn on XNA rendering

    SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

 

   base.OnNavigatedTo(e);

}

2.      只有这一页需要XNA渲染,因此你需要在离开该页面前关闭XNA渲染。添加OnNavigatedFrom方法:

C#

protected override voidOnNavigatedFrom(NavigationEventArgs e)

{

    // Set the sharingmode of the graphics device to turn off XNA rendering

    SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

 

    base.OnNavigatedFrom(e);

}

3.       通过SharedGraphicsDeviceManager的操作打开XNA渲染模式,让操作系统使用XNA渲染取代Silverlight渲染,但是不需要实际打开XNA游戏循环。WindowsPhone Mango使用GameTimer类,用来运行XNA引擎并将一些标准的Microsoft.Xna.Framework.Game生命周期方法作为事件暴露出来,使你的应用程序可以被控制。

在绘制任何XNA内容之前,你不得不创建GameTimer类型,并启动游戏引擎。在GamePage类中,声明GameTimer的变量timer

C#

public partial class GamePage : PhoneApplicationPage

{

    GameTimer timer;

    …

}

找到GamePage构造函数,创建实际的对象,注册UpdateDraw事件。设置GameTimerUpdateInterval属性,指定触发Update事件的时间间隔,设备触发Draw事件的时间间隔与此相同。

C#

public GamePage()

{

    InitializeComponent();

 

    // Create a timer for this page

   timer = new GameTimer();

   timer.UpdateInterval = TimeSpan.FromTicks(333333);

   timer.Update += timer_Update;

   timer.Draw += timer_Draw;

}

 

private void timer_Update(object sender, GameTimerEventArgs e)

{

}

 

private void timer_Draw(object sender, GameTimerEventArgs e)

{

    SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);

}

4.      为了启动和关闭XNA引擎,在OnNavigatedTo方法中调用GameTimerStart方法,在OnNavigatedFrom方法中调用Stop方法。

C#

protected override void OnNavigatedTo(NavigationEventArgse)

{

    // Set the sharingmode of the graphics device to turn on XNA rendering

    SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

 

    // Start the game timer

   timer.Start();

 

    base.OnNavigatedTo(e);

}

 

protected override void OnNavigatedFrom(NavigationEventArgse)

{

    // Stop the game timer

   timer.Stop();

 

    // Set thesharing mode of the graphics device to turn off XNA rendering

    SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

 

    base.OnNavigatedFrom(e);

}

5.       现在XNA绘制的引擎已经开始运行了,在实际绘制内容之前,您需要一个最终的对象。 SpriteBatch类负责绘制多个基于可视化元素的精灵。在接下来的几步中,您将使用SpriteBatch实例来绘制背景图片和Silverlight内容。但是,首先您需要初始化它。

声明 SpriteBatch 变量叫做spriteBatch:

C#

public partial class GamePage : PhoneApplicationPage

{

    GameTimer timer;

    SpriteBatch spriteBatch;

    …

}

6.      在 OnNavigatedTo方法中实现该对象:

C#

protected override void OnNavigatedTo(NavigationEventArgse)

{

    // Set the sharingmode of the graphics device to turn on XNA rendering

    SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

 

    //Initialize SpriteBatch

   spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

 

    // Start the gametimer

    timer.Start();

 

    base.OnNavigatedTo(e);

}

7.      下一步来绘制位于ModelViewerLibraryContent工程的背景图片background.jpg。 为了绘制图片,通过ContentManager进行加载,然后通过spriteBatch进行绘制。

GamePage类中,声明  Texture2D 类型的变量叫做background ,来加载背景图片。这是一个简单的材质,用来在XNA绘制引擎里进行绘制。

C#

public partial class GamePage : PhoneApplicationPage

{

    …

    SpriteBatch spriteBatch;

    Texture2D background;

    …

}

8.      ModelViewerLibraryContent工程中包含预编译的资源,当ModelViewer工程编译时,并将其嵌入到Silverlight程序集里。应用程序需要ContentManager在运行时加载这些资源。

根据XNA的需求,在App类中实现IServiceProvider接口。现在你可以使用它在OnNavigatedTo方法中来创建ContentManager。使用ContentManager将预编译的背景图片,加载为材质,并且设置到background变量中去。

C#

protectedoverride void OnNavigatedTo(NavigationEventArgse)

{

    …

    //Initialize SpriteBatch

    spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

 

    App app = (App)Application.Current;

   ContentManager appContentManager = new ContentManager(app,"Content");

 

   background = appContentManager.Load<Texture2D>("background");

 

    // Startthe game timer

    timer.Start();

 

    base.OnNavigatedTo(e);

}

9.      最后,在timer_Draw事件处理函数中使用SpriteBatch对象绘制图片。

C#

private void timer_Draw(object sender, GameTimerEventArgs e)

{

    …

    spriteBatch.Begin();

   spriteBatch.Draw(background, Vector2.Zero,Color.White);

   spriteBatch.End();

}

运行程序确认 XNA可以正常显示背景图片。

10.   绘制3D模型比绘制背景图片略微苦难一些。首先需要替代预编译资源,需要从独立存储中加载3D模型资源。首先要声明嵌入3D模型和其元数据的成员变量:

C#

public partial class GamePage : PhoneApplicationPage

{

    …

    XnaModelWrapper model;

   ModelMetadatamodelMetadata;

    …

}

11.  使用content manager来加载模型,就像加载背景图片一样。因为这些模型通过查询字符串,被传递到GamePage页面,而不是预编译的,你不得不使用Model\CustomContentManager.cs位于的自定义内容管理器,从独立存储中加载模型。在OnNavigatedTo方法中加载模型和元数据:

C#

protected override void OnNavigatedTo(NavigationEventArgse)

{

    …

    background = appContentManager.Load<Texture2D>("background");

 

    //Get query string parameter andinitialize local metadata variable

   IDictionary<string, string>data = NavigationContext.QueryString;

   modelMetadata = app.ModelsStore[data["ID"]];

 

   //Initialize the model

   model = new XnaModelWrapper();

   model.Lights = new bool[] { true, true, true };

   ContentManager contentManager = modelMetadata.IsContent? appContentManager : new CustomContentManager();

   model.Load(contentManager,modelMetadata.Assets[0]);

 

    // Startthe game timer

    timer.Start();

 

    base.OnNavigatedTo(e);

}

提示: 下面的代码中包含XNA和3D模型,这些超出了本次实验的范围。为了学习更多关于XNA的知识,可以参考XNA的文档。

12.    SpriteBatch只能绘制Texture2D对象,因此你不能使用它来绘制3D模型。为了绘制模型,调用XnaModelWrapper类的Draw方法。编辑GamePage类中timer_Draw事件处理函数来绘制模型:

C#

private void timer_Draw(object sender, GameTimerEventArgs e)

{

    spriteBatch.Begin();

    spriteBatch.Draw(background, Vector2.Zero, Color.White);

    spriteBatch.End();

 

   // Set render states.

    SharedGraphicsDeviceManager.Current.GraphicsDevice.DepthStencilState= DepthStencilState.Default;

    SharedGraphicsDeviceManager.Current.GraphicsDevice.BlendState= BlendState.Opaque;

    SharedGraphicsDeviceManager.Current.GraphicsDevice.RasterizerState= RasterizerState.CullCounterClockwise;

    SharedGraphicsDeviceManager.Current.GraphicsDevice.SamplerStates[0]= SamplerState.LinearWrap;

 

   // Draw the model

   model.Draw();

}

13.   您也会更新模型的属性,在3D空间中正确的显示。当GameTimer触发Draw事件时,模型会被绘制;当触发Update事件时,执行应用程序的逻辑,并计算模型位置。

timer_Update事件处理函数中更新模型:

C#

private void timer_Update(object sender, GameTimerEventArgs e)

{

    float yaw = MathHelper.Pi + MathHelper.PiOver2; //rotation around the y-axis

   float pitch = 0; // rotation around the x-axis

    floatfieldOfView = MathHelper.ToRadians(45f) /modelMetadata.FieldOfViewDivisor; // zoom

 

   model.Rotation = modelMetadata.World * Matrix.CreateFromYawPitchRoll(yaw,pitch, 0);

    model.Projection = Matrix.CreatePerspectiveFieldOfView(fieldOfView,modelMetadata.AspectRatio, modelMetadata.NearPlaneDistance,modelMetadata.FarPlaneDistance);

   model.View = modelMetadata.ViewMatrix;

   model.IsTextureEnabled = true;

   model.IsPerPixelLightingEnabled = true;

}

14.   因为要在Update事件处理函数中进行的计算在不同调用中不会发生变化,每一帧看起来都是相同的,并且绘制模型会出现在3D空间相同的位置上。为了响应手势识别使XNA绘制能够缩放、旋转3D模型,首先需要在GamePage构造函数里激活手势识别的句柄:

C#

public GamePage()

{

    InitializeComponent();

 

    …

    //Initialize gestures support -Pinch for Zoom and horizontal drag for rotate

    TouchPanel.EnabledGestures= GestureType.FreeDrag | GestureType.Pinch | GestureType.PinchComplete;

}

声明声明下列的变量,在timer_Update事件处理函数中,我们会使用这些变量来旋转和缩放这些模型:

C#

public partial class GamePage : PhoneApplicationPage

{

    …

   floatxRotation = 0.0f;

   floatyRotation = 0.0f;

   float? prevLength;

   floatcameraFOV = 45; // Initial camera FOV (servesas a zoom level)

    …

}

15.  在OnNavigatedTo方法中根据初始化xRotationyRotation变量:

C#

protected override void OnNavigatedTo(NavigationEventArgse)

{

    …

    modelMetadata = app.ModelsStore[data["ID"]];

    xRotation = modelMetadata.DefaultXRotation;

   yRotation = modelMetadata.DefaultYRotation;

    …

}

16.  添加HandleInput方法读取用户输入到xRotation, yRotation, cameraFOVprevLength变量中:

C#

private void HandleInput()

{

    while(TouchPanel.IsGestureAvailable)

    {

        GestureSamplegestureSample = TouchPanel.ReadGesture();

        switch(gestureSample.GestureType)

        {

            caseGestureType.FreeDrag:

            xRotation += gestureSample.Delta.X;

            yRotation -= gestureSample.Delta.Y;

            break;

 

            caseGestureType.Pinch:

                float gestureValue = 0;

                float minFOV = 80;

                float maxFOV = 20;

                float gestureLengthToZoomScale = 10;

 

                Vector2 gestureDiff = gestureSample.Position - gestureSample.Position2;

                gestureValue = gestureDiff.Length()/ gestureLengthToZoomScale;

 

            if(null != prevLength) // Skipthe first pinch event

                cameraFOV -= gestureValue- prevLength.Value;

 

                cameraFOV = MathHelper.Clamp(cameraFOV, maxFOV, minFOV);

 

                prevLength = gestureValue;

                break;

 

                case GestureType.PinchComplete:

                prevLength = null;

                break;

 

            default:

                break;

        }

    }

}

17.   编辑timer_Update方法来获取用户输入,并更新3D模型:

C#

private void timer_Update(object sender, GameTimerEventArgs e)

{

    HandleInput();

 

    float yaw = MathHelper.Pi + MathHelper.PiOver2+ xRotation / 100; // rotation around the y-axis

   float pitch = yRotation / 100; // rotation around the x-axis

    floatfieldOfView = MathHelper.ToRadians(cameraFOV)/ modelMetadata.FieldOfViewDivisor; // zoom

    …

}

18.   在同一时间只有一个Readerer能够在屏幕上进行绘制。所以如果在你的应用程序中使用3D模型和其他XNA功能,那么XNA Renderer不会触发正规的Silverlight页面生命周期时间。Silverlight内容只是存在,但不会显示出来,因为XNA不会绘制它们。

XNA框架中使用一个新的对象来解决这个问题:UIElementRendererUIElementRenderer将Silverlight内容作为2D材质在XNA中显示,并且触发Silverlight事件。例如,当我们的用户触摸由UIElementRenderer生成的Silverlight按钮图片时,UIElementRenderer将会把输入信息传递给真实(不可见)的Silverlight按钮。

为了显示模型的名称和描述,使用UIElementRenderer来绘制Silverlight控件树。开始声明uiRenderer变量:

C#

public partial class GamePage : PhoneApplicationPage

{

    …

    UIElementRenderer uiRenderer;

    …

}

19.  为了展现整个控件树,当控件树改变时,你需要更新uiRenderer变量。在GamePageLayoutUpdated事件中添加处理函数:

C#

public GamePage()

{

    …

    this.LayoutUpdated += GamePage_LayoutUpdated;

}

 

private void GamePage_LayoutUpdated(object sender, EventArgs e)

{

    if(uiRenderer == null || LayoutRoot.ActualWidth > 0 && LayoutRoot.ActualHeight> 0)

        uiRenderer = newUIElementRenderer(LayoutRoot, (int)LayoutRoot.ActualWidth, (int)LayoutRoot.ActualHeight);

}

20.   XNA renderer只能在应用程序触发Draw事件之后,更新绘制。调用uiRendererRender方法来更新Silverlight UI,并在材质中进行重华。使用spriteBatch将材质绘制到屏幕上。

C#

private void timer_Draw(object sender, GameTimerEventArgs e)

{

    …

    // Update the Silverlight UI

   uiRenderer.Render();

 

   // Draw the sprite

   spriteBatch.Begin();

   spriteBatch.Draw(uiRenderer.Texture, Vector2.Zero,Color.White);

   spriteBatch.End();

}

21.  最后,设置页面的DataContext,并添加GamePanel XAML可以绑定的所依赖的属性:

C#

public GamePage()

{

    …

    this.DataContext = this;

}

 

public string ModelName

{

    get { return (string)GetValue(ModelNameProperty);}

   set { SetValue(ModelNameProperty, value); }

}

 

// Using aDependencyProperty as the backing store for ModelName.  This enables animation, styling, binding,etc...

public static readonlyDependencyProperty ModelNameProperty =

   DependencyProperty.Register("ModelName", typeof(string), typeof(GamePage), null);

 

public string ModelDesc

{

   get { return(string)GetValue(ModelDescProperty); }

   set { SetValue(ModelDescProperty, value); }

}

 

// Using aDependencyProperty as the backing store for ModelDesc.  This enables animation, styling, binding,etc...

public static readonlyDependencyProperty ModelDescProperty =

   DependencyProperty.Register("ModelDesc", typeof(string), typeof(GamePage), null);

22.  在OnNavigatedTo方法中,更新依赖属性值:

C#

protected override void OnNavigatedTo(NavigationEventArgse)

{

    …

    modelMetadata = app.ModelsStore[data["ID"]];

    ModelName = modelMetadata.Name;

   ModelDesc = modelMetadata.Description;

    …

}

23.  我们完成了本次动手实验。

 


 

 

 

本次实验中,您学习了如何使用两个Windows Phone Mango的新功能。您浏览了BackgroundTransferService,解释了如何在您的应用程序总集成一个下载管理器,使其能够不依赖于您的应用程序而独立运行。你也看到了如何将XNA内容嵌入到一个Silverlight页面中,创建一个Silverlight/XNA混合应用程序,来演示如何在同一个页面中显示两个完全不同的。程序框架。

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值