文章目錄
- 調用MessageBox
- 調用Software Input Panel
- 寫到最後
作者:馬寧
相信未來一段的業餘時間,我都要和XNA為伍了。本來想向3D開發的縱深發展,但是遇到了一個實際的問題,就是如何在XNA下顯示MessageBox和Software Input Panel。乾脆先寫出來吧,省得大家遇到這問題時抓狂。
按照為數不多的公開文檔描述,XNA和Silverlight for Windows Phone應該是基於同一個.NET Compact Framework的CLR。但是,XNA並沒有提供任何使用者控制項、MessageBox和軟鍵盤等,也不能直接調用Silverlight for Windows Phone的類庫。這樣勢必為XNA製造了很多人為的障礙。但調用MessageBox和Software Input Panel的後門,XNA還是給我們留下了,這就是Microsoft.Xna.Framework.GamerServices命名空間下的Guide類,類描述如下:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.gamerservices.guide.aspx
該類不但可以調用MessageBox和軟鍵盤,還能夠調用Marketplace、XBox Live等表單。不過,值得注意的是,Guide類提供的方法都是非同步呼叫,而非同步調用,這也好理解,遊戲的處理過程是以時間驅動的,所以任何操作不應該阻塞住遊戲主線程。
Guide類調用MessageBox和軟鍵盤的描述在這裡:
http://msdn.microsoft.com/en-us/library/ff827869.aspx
http://msdn.microsoft.com/en-us/library/ff827868.aspx
但MSDN文檔還是有一些瑕疵,按上面提供的方法會產生Exception,所以我在下面給出修改後可以啟動並執行方法。運行環境基於VS 2010 + Windows Phone 7 SDK RTW版。
調用MessageBox
建立Windows Phone 7中XNA 4.0的工程,然後,我們在Update方法裡添加對於MessageBox的調用。當然,大家請不要認為把MessageBox加到Update裡正確的,這樣會造成MessageBox不斷彈出。我只是為了簡化代碼,才這麼做的。
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // TODO: Add your update logic here List<string> MBOPTIONS = new List<string>(); MBOPTIONS.Add("OK"); MBOPTIONS.Add("CANCEL"); if (!Guide.IsVisible) Guide.BeginShowMessageBox("test", "hello, XNA", MBOPTIONS, 0, MessageBoxIcon.Alert, new AsyncCallback(RespCallback), null); base.Update(gameTime); }
由於Microsoft.Xna.Framework.GamerServices是預設添加的組件,所以,我們可以直接使用Guide類。首先建立一個string類型的List,用於儲存MessageBox中按鈕的Text;然後通過List<string>的Add方法將需要顯示的Button Text添加進去。
接下來是Guide.IsVisible方法,由於MessageBox、SIP軟鍵盤等公用一個繪製表面,必須保證沒有其他UI顯示時,才能夠顯示指定組件,如果不添加這句Guide.IsVisible的判斷,將觸發下面的異常。
接下來就是調用的主體Guide.BeginShowMessageBox了,這是一個非同步方法呼叫,調用後立刻返回。參數比較好理解,下面是函數的聲明:
public static IAsyncResult BeginShowMessageBox ( string title, string text, IEnumerable<string> buttons, int focusButton, MessageBoxIcon icon, AsyncCallback callback, Object state)
第一個參數是標題,第二個參數是對話方塊內容,第三個是button上文字的列表,也表示有幾個Button出現,第四個是焦點在第幾個Button上,第五個是表徵圖,我們設定為null,第六個是結束時調用的Callback函數對象,最後一個是使用者自訂狀態物件,可以傳遞自訂資訊。其他參數都容易理解,AsyncCallback對象需要一個Callback函數RespCallback,我們實現如下:
private static void RespCallback(IAsyncResult asynchronousResult) { int? b = Guide.EndShowMessageBox(asynchronousResult); if (b > 0) Debug.WriteLine("Cancel"); else Debug.WriteLine("OK"); }
Callback函數中最重要的工作是調用Guide.EndShowMessageBox函數,來關閉MessageBox。EndShowMessageBox需要傳入一個IAsyncResult對象,來自Callback函數的參數。傳回值是一個可為空白的int,如果為空白則表示沒有傳回值,如果不為空白,傳回值是Button的Index值,返回0表示點擊了第一個按鈕OK,返回1則表示點擊了第二個按鈕Cancel,以此類推。
顯示MessageBox的效果如下:
調用Software Input Panel
接下來是調用SIP軟鍵盤的代碼,仍舊放到Update方法裡,Callback函數也一併給出。
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); if (!Guide.IsVisible) Guide.BeginShowKeyboardInput(PlayerIndex.One, "Here's your Keyboard", "Type something...", "abc", new AsyncCallback(GetTypedChars), null); base.Update(gameTime); } private static void GetTypedChars(IAsyncResult asynchronousResult) { string output = Guide.EndShowKeyboardInput(asynchronousResult); Debug.WriteLine(output); }
前邊都解釋過了,直接來看Guide.BeginShowKeyboardInput,第一個參數要傳PlayerIndex進去,這個是針對Xbox的,在Windows和Windows Phone 7上只支援一個使用者,所以直接傳PlayerIndex.One就好了。接下來的三個參數是標題、描述和預設字元,然後是非同步呼叫方法和自訂狀態。還有最後一個選擇性參數,表示是否用Password方式顯示字元。
public static IAsyncResult BeginShowKeyboardInput ( PlayerIndex player, string title, string description, string defaultText, AsyncCallback callback, Object state, bool usePasswordMode)
在非同步呼叫方法中,Guide.EndShowKeyboardInput會返回一個字串,該字串為使用者輸入的字串。為什麼顯示的是字串呢,這和SIP的顯示方式有關。在調用SIP函數後,會首先彈出第一個對話方塊,詢問使用者是否輸入字元,如果使用者點Cancel則關閉SIP,如果點OK則進入第二個介面,使用者才能夠使用SIP軟鍵盤進行輸入。
下面就是SIP顯示的狀態:
寫到最後
今天的主角Guide類,還有很多有趣的函數調用,有興趣的朋友按照這個方法調用就可以了。這次的代碼量不多,所以就不給出單獨Sample Code的下載了。再有就是,虛心接受批評,將文章裡代碼的格式弄好了。
我最近還是很勤快的,Windows Phone 7的開發都寫了三篇了,這是之前文章的連結:
馬寧的Windows Phone 7開發教程(1)——Windows Phone開發工具初體驗
馬寧的Windows Phone 7開發教程(2)——Windows Phone XNA 4.0 3D遊戲開發