MonoTouch:用.NET開發iOS應用
隨著MonoTouch框架(Novell的Mono Project的一部分)的出現,這一切都將改變。Mono Project是微軟.NET平臺的開源實現。其允許你在幾乎任何平臺上運行.NET應用程序,包括Apple、FreeBSD、Linux、Unix等 等。MonoTouch是Mono Project的新組成部分,讓你能夠用C#和.NET平臺編寫可以運行在iPhone上的應用程序。
本篇文章的目的,就是提供MonoTouch平臺的一個完整介紹,讓大家知道到那里獲取必要的工具,MonoTouch有什么樣的限制,以及如何構建一個簡單的應用程序。
背景和限制
對于打算為iPhone開發應用的.NET開發人員而言,MonoTouch的出現無疑是一件好事。然而,在決定創建應用程序之前,有一些限制和背景知識需要先了解清楚。
它如何工作?
在創建MonoTouch應用程序的時候,大部分非UI方面的.NET 3.5功能依舊可用,或者一些還處于計劃之中(如.NET 4.0的功能)也囊括其中。這讓你可以使用很多業已熟悉的.NET Framework技術來編寫應用程序,包括Windows Communication Framework (WCF)、Workflow Foundation (WF)等等。也包括幾乎所有的基類庫(Base Class Library,BCL),涵蓋諸如垃圾收集(Garbage Collection)、線程、數學函數、System.Net、加密等。對于可用的標準.NET程序集列表,見http://monotouch.net/Documentation/Assemblies。MonoTouch是一種基礎.NET函數庫的特別定制版本,這也類似Silverlight和Moonlight的實現方式。
這意味著,你能夠使用MonoTouch的核心程序集來編譯標準的.NET 3.5代碼成相應的函數庫,并在你的應用程序中使用它們。因此,如果你有一個用于其它應用程序的特別函數庫,其包含著一些用于工程問題的高級數學函數,那 么只需簡單地把這些代碼庫加入到你的MonoTouch解決方案中,并引用它。在你構建解決方案的時候,編譯器就利用MonoTouch核心函數庫對其進行編譯,接著就能在iPhone應用程序中使用它了。
MonoTouch也包括一些原生iPhone API的包裝函數庫,如訪問位置(Location,GPS)、加速計、地址簿等的函數。MonoTouch也提供相應的功能,讓你能夠調用那些尚未進行包裝的原生Objective-C函數庫,所以你可以直接和現存的Objective-C代碼進行互操作。
我如何創建用戶界面(UI),我能使用Silverlight嗎?
MonoTouch應用程序的UI需要使用蘋果的Interface Builder(界面創建器,IB)應用程序來創建,IB連同iPhone SDK一起提供。Interface Builder使用Cocoa Touch(蘋果用于iPhone的UI框架)控件對象,這些控件對象在iPhone上原生提供的。這意味著,你能在應用程序中使用所有的標準 iPhone控件,如選擇器(Pickers)、滑動條(Sliders)、按鈕等等。
你也能通過代碼來創建界面,即實例化Cocoa Touch對象后,把它們添加到應用程序的視圖(Views)中(關于視圖,后面會詳細講述)。
然而,你不能利用傳統的.NET技術,如Silverlight、WPF、WinForms等來創建MonoTouch界面。
Cocoa Touch使用一種融合了MVC(Model View Controller)模式思想的結構,我們將在后面一篇文章中介紹。
我如何分發我的應用?
MonoTouch應用程序的分發完全和傳統iPhone應用程序的分發一樣,既可以通過蘋果App Store,也可以通過企業部署。
App Store是一個在線資源庫,讓用戶可以付費購買(如果不是免費的話)和下載應用程序??梢詮膇Tunes中訪問,或直接通過iPhone本身來訪問。為 了得到通過App Store分發應用的許可,你必須向蘋果注冊,并支付每年99美元的年費。
企業部署方式就是為公司開發內部應用程序,并分發給員工等人員使用,無需把應用在App Store中列出。
什么是許可模型?
不像Mono那樣,MonoTouch不是開源的,且是一個收費產品。這意味著,如果你打算開發一些實際的應用,就必須購買軟件許可。
專業版($399)——單個的個人開發人員許可,讓你可以開發應用程序,并通過蘋果App Store來分發它們。
企業版($999)——單個的企業開發人員許可,讓你可以開發應用程序,并通過蘋果App Store來分發它們,或者進行企業部署。
企業版,5人($3999)——和企業版一樣,只是提供了5個坐席的授權。
以上所有選項都包括了一年的免費升級權益。
還有一個評估版本,你只能把應用部署到模擬器中。出于介紹的目的,我們只需要評估版本就行。
MonoTouch有哪些限制?
沒有即時(JIT)編譯
根據蘋果的iPhone政策,任何應用程序都不能包含需要JIT編譯的代碼。但是稍等,.NET確實能正確工作,是不?對,不過MonoTouch是通過把應用程序編譯為原生的iPhone程序集來跳過這個限制的。但是,這也帶來了幾個限制。
- 泛型——泛型是由JIT編譯器在運行時進行實例化的,然而,Mono具備一種提前(Ahead of Time ,AOT)編譯的模式,可以為類似List這樣的泛型集合生成方法和屬性。而泛型的其他用法,例如泛型虛方法、泛型類型上的 P/Invokes和Dictionary上的值類型,就不被支持(雖然存在Dictionary的代替方法)。
- 動態代碼生成——因為動態代碼生成依賴于JIT編譯器,所以對任何動態語言編譯的過程也不能支持。包括System.Reflection.Emit、 Remoting和動態語言運行時(DLR)。
C#是唯一的語言
另外,目前用于編寫MonoTouch應用程序的唯一可用語言是C#。Visual Basic.NET有望在MonoTouch未來的發布中支持,不過此時此刻我們別無選擇。
更多信息
相關限制的完整列表和更多的信息,包括一些代替方法,可用參見http://monotouch.net/Documentation/Limitations。#p#
入門
要進入為iPhone創建MonoTouch應用程序的大門,我們需要下面幾樣東西:
- 一個使用Intel CPU的Mac電腦,其要安裝MacOSX 10.5或10.6 (Leopard或Snow Leopard)
- 蘋果的iPhone SDK 3.0或更高版本
- Mono的當前版本
- MonoTouch SDK
- 一個IDE工具,如MonoDevelop或XCode,或一個文本編輯器程序
安裝著Leopard或Snow Leopard的Mac
這是最重要也是最容易忽視的需求。盡管,理論上你能在任何平臺上開發大部分應用程序,然而iPhone Simulator和Interface Builder只能在Leopard和Snow Leopard上運行。另外,編譯器本身用到了一些特定于Intel Mac機器的底層功能,所以購買這樣一臺電腦是絕對必須的。
蘋果的iOS SDK
iOS SDK可通過http://developer.apple.com/iphone/來免費下載,不過必須在蘋果網站上注冊,才能訪問這個地址。
在安裝了iPhone SDK后,要確保你能正常啟動iPhone Simulator。要啟動它,只需打開Spotlight,鍵入iPhone Simulator。
Mono
一旦你測試iPhone Simulator正常,那么就要安裝Mono for OSX的最新版。Mono可以從http://mono-project.com/Downloads下載。記住要點擊“Intel”版本的鏈接,不要點CSDK版本。同樣,安裝MonoTouch SDK之前也需要安裝Mono的。Mono的安裝包是磁盤鏡像的形式,掛接鏡像,雙擊安裝包,根據安裝向導完成安裝過程。
MonoTouch SDK
接下來,下載和安裝最新的MonoTouch SDK。你既可以在MonoTouch商店(http://monotouch.net/Store)購買,購買后會收到一個下載鏈接,也可以從http://monotouch.net/DownloadTrial下載評估版。如果購買了MonoTouch,你就能把應用程序部署到一臺正確配置了的iPhone上,不過也可像我這樣,僅僅在模擬器中運行。所以,目前 而言試用/評估版就足夠了。
文本編輯器或集成開發環境(IDE)
如果你打算創建MonoTouch應用程序,所需的所有東西就是前面提及的,和一個文本編輯器。你能創建所有代碼文件,并用命令行(終端窗口)來手動編 譯。這種方式雖然可行,但是實際操作起來可能會非常痛苦,所以我們還是需要使用一個IDE來開發我們的應用程序。
你可以編輯/hack一下XCode(隨iPhone SDK一起安裝)來利用MonoTouch的函數庫和編譯器,也可以使用MonoTouch版的MonoDevelop,其已經為MonoTouch應用 程序做好所有配置了。我們理所當然要用MonoDevelop,所以訪問這里http://monodevelop.com/Download/Mac_MonoTouch來 下載它。要安裝MonoDevelop,只用把下載文件拖到應用程序目錄中就行。
如果你已經正確安裝Mono,那么MonoDevelop應該可以正常啟動。#p#
Hello World應用程序
現在,一切已經準備妥當,讓我們開始來嘗試開發點東西了。
MonoDevelop
首先,啟動MonoDevelop。你應該會看到和下圖類似的界面【譯者注:如果OSX的首選語言是中文的話,MonoDevelop的菜單和工具欄的文字顯示不正常,所以最好把English拖到語言選項的第一位】:

作為一個標準的IDE,看上去還是蠻熟悉的。它非常類似Visual Studio、SharpDevelop、Visual C# Express等等。
我們創建一個新解決方案,來包含iPhone項目。這里的解決方案和Visual Studio中的概念一樣,實際上你可以在MonoDevelop中打開Visual Studio創建的解決方案。在MonoDevelop中的一個不同點就是,你能夠在一個MonoDevelop實例中打開多個解決方案,正如下面的截圖所示:

這完全是由于在OSX中,你不能啟動MonoDevelop的多個實例(事實上,任何程序都不行),且沒有任何變通方法。所以,如果你需要在解決方案間切 換(例如,你希望另外打開一個包含示例代碼的解決方案),你就能簡單地一次性打開多個。
那么,說了上面這么多,讓我們現在來創建一個解決方案吧。在菜單中,點File:New:Solution:

我們要創建一個如下面截圖所示的“iPhone MonoTouch Project”。選中它,并命名為Example_HelloWorld_1。

這里再次和Visual Studio中創建新解決方案的對話框很類似。點擊Forward ,顯示下一屏,直接點擊OK,因為我們不需要這些功能:
你現在應該可以看到如下所示的解決方案視圖了(注意,我展開了解決方案中的節點,以便顯示出所有文件和引用程序集):
我們來過一遍這些東西:
- References ——這個文件夾包含MonoTouch應用程序需要的基本引用。MonoTouch程序集包括特定于iPhone的任何東西,也包括了所有Cocoa Touch控件的包裝器,以及類似位置、數據等核心iPhone接口。以System.開頭的程序集是.NET的基類庫和運行時,其被裁減過以便能運行在 iPhone上。
- Main.cs ——這和控制臺應用程序、WPF應用程序等是一致的。在這里調用的是static void main() ,其是作為應用程序的入口點。過一下我們會仔細研究一下這個文件。
- MainWindow.xib和MainWindow.xib.designer.cs ——這個和Winforms Window或WPF Window類似。xib文件實際上要在Interface Builder中進行編輯,而designer.cs文件包含這個窗體的屬性。
讓我們來仔細研究一下Main.cs文件中的代碼:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using MonoTouch.Foundation;
- using MonoTouch.UIKit;
- namespace Example_HelloWorld_1
- {
- public class Application
- {
- static void Main (string[] args)
- {
- UIApplication.Main (args);
- }
- }
- // The name AppDelegate is referenced in the MainWindow.xib file.
- public partial class AppDelegate : UIApplicationDelegate
- {
- // This method is invoked when the application has loaded its UI and its ready to run
- public override bool FinishedLaunching (UIApplication app, NSDictionary options)
- {
- // If you have defined a view, add it here:
- // window.AddSubview (navigationController.View);
- window.MakeKeyAndVisible ();
- return true;
- }
- // This method is required in iPhoneOS 3.0
- public override void OnActivated (UIApplication application)
- {
- }
- }
- }
其中有兩個有趣的地方。它包含一個Application類和一個AppDelegate類。從這里開始,和傳統的.NET GUI開發就有所不同了。
iPhone應用程序的工作方式是,應用程序類(繼承于UIApplication)包含了所有窗口、視圖、控件和資源等等;同時應用程序委托類中(繼承于UIApplicationDelegate)處理來自iPhone OS的回調,實際上會包括應用程序運行周期(Lifecycle)的事件(例如應用程序啟動和應用程序終止)和大量的運行時事件(例如低內存報警)。
通過在應用程序委托類處理這些事件,你就能夠響應它們。比如,在應用程序關閉的時候,WillTerminate()方法將被調用,這樣就有機會去保存任何用戶數據、應用程序狀態等。
在Application類中,具有一個Main() 方法。調用UIApplication.Main,Objective-C運行時將查找MainWindow.xib文件(它包含了 UIApplicationDelegate類的名稱),實例化Application類(為單實例)后,就接著調用AppDelegate類中運行周期事件。
你不必把主窗體的名稱命名為“MainWindow.xib” (即所謂的主界面文件)。你可以任意命名它,只需告知編譯系統去查找哪個文件就行。如果你希望它去查找不同的文件,在項目文件上右鍵打開項目選項,點擊 Options ,接著在Build : iPhone Application : Main Interface File中即可設置主窗體對應的文件。在應用程序啟動的時候,Objective-C運行時將會嘗試去加載那個文件,并根據這個文件內的設置來查找應用程序委托類。
另外,你也可以任意命名你的應用程序委托類。默認情況下,它的名稱為“AppDelegate”。要改變它,在Interface Builder中打開主界面文件,修改Application Delegate的名稱。 |
一會我們會回到Main.cs文件上來,不過首先來深入研究下應用程序的實際GUI。
Interface Builder
目前為止,已經讀到了我們的iPhone應用程序的部分代碼,可以深入研究一下如何構建它的界面了。蘋果的應用程序設計工具包稱之為 Interface Builder。Interface Builder可以和開發環境松耦合。它可以編輯那些定義應用程序GUI的.xib文件。NIB和XIB的比較:Nib文件包含了窗口、控件等的XML表示,類似于WPF/Silverlight中的XAML模型。
不管是在XCode中編寫Objective-C,或在MonoDevelop中編寫C#,Interface Builder的用法都是完全一樣的。能這樣,完全是因為MonoDevelop能夠監測Nib文件的變更,并添加/刪除對應于Nib文件的適當代碼到 designer.cs文件中。
你當然可以不打開Interface Builder,純粹通過編程來創建整個GUI,有些開發人員確實也是這樣做的。很多事情在Interface Builder也無法完成,就此而言,你還是需要編程來完成某些事情。Interface Builder隱藏了一些復雜的部分,在入門的時候,很容易使用Interface Builder來熟悉iPhone應用程序GUI的一些概念。
那么,說了這么多,讓我們來著手創建界面了。在MainWindow.xib文件上雙擊。Interface Builder將啟動,并能看到如下圖所示的東西:
讓我們逐一研究一下這些窗口。從左到右,分別是:Document Window(文檔窗口)、Design Surface Window(設計界面窗口)、Library Window(控件庫窗口)和Inspector Window(檢查器窗口)。
首先讓我們來看Document Window:
這個窗口顯示了在.xib文件中的所有對象。這是默認的視圖,你會發現它雖然樣子漂亮,但沒有太大用處,因為你的對象實際上是層級排列的,而圖標視圖只能同時顯示一級。在我們添加控件到界面上的時候,它不會顯示在這個視圖中。所以,我們需要通過點擊View Mode工具條上中間的圖標來改變列表視圖。改變后,應該會顯示如下的樣子:
下一個窗口是設計界面。也就是,我們實際拖拽Cocoa Touch控件來設計我們界面的地方:
當然,由于我們尚未添加任何控件到上面,所以現在還是一片空白。
下一個窗口是Library。Library包含了所有能在設計界面上使用的Cocoa Touch控件。如果你運行Leopard【譯者注:原文這里為Snow Leopard,實際是錯誤的?!浚敲茨愕目丶齑翱谌缦滤荆?/p>
如果你運行Snow Leopard【譯者注:原文這里未Leopard,實際是錯誤的?!浚鼞撌沁@個樣子:
注意它們兩者還是非常類似的。在Snow Leopard里,有一個名為“Classes”的標簽頁,我們后面會講到這個東西,不過這也是唯一的不同點。
這是Library的默認視圖,不過我喜歡稍微不同的樣子,以便我能一下看到更多的控件。為了改變Library窗口中的視圖,右鍵點擊控件視圖,可以選擇不同的顯示風格。你也可以點擊窗口左下角的Gear(齒輪)按鈕。下圖是Leopard中的“icons and labels”風格:
而在Snow Leopard中是:
最后一個窗口是Inspector Window:
Inspector具有四種不同的視圖,可以通過窗口頂部的標簽欄來選擇。這些視圖分別是Attribute Inspector、Connections Inspector、Size Inspector和Identity Inspector。Inspector大致和Visual Studio中的Property Explorer類似。它向你顯示當前選中的Cocoa Touch對象的所有屬性。也可以用它來設置可視化屬性、布局等等。在創建Outlets和Actions時也用得著它,這個主題后面會談到。在下面的圖片中,我們在Document窗口中選擇了Window對象,所以我們可以查看這個對象的相關屬性。
現在,我們對Interface Builder窗口已經大致瀏覽了一遍,接下來讓我們實際地創建一些東西。我們要創建如下這樣的界面:
首先,拖一個“Round Rect Button(圓角矩形按鈕)”(UIButton)到窗口上。接著,在按鈕上雙擊來設置文本。在這個過程中你會注意到,你會獲得少許的指導。這些指導是基于蘋果的人機交互向導(Human Interface Guidelines)的,來輔助你在視圖上以適合的間距等來定位控件。
在窗口上添加了按鈕后,拖入一個“Label(標簽)”(UILabel)控件。改變它的尺寸以便接近窗口的寬度。接著雙擊這個label控件,刪除文本以使應用程序啟動的時候,標簽的內容是空白的。
如果你正確地完成了所有步驟,那么你的Document Window將顯示如下的樣子(點擊“Window”旁邊的箭頭就會看到它包含的子控件):
我們現在創建了第一個窗口界面。不過,不像傳統的.NET GUI開發,你還不能編程訪問這些控件。假如這是一個WPF應用程序,你一拖動控件到設計界面上,你就能通過this.ControlName這樣的形式來訪問它。如果你馬上去查看MainWindow.designer.cs文件,除了“window”屬性外,你看不到任何其他代碼。為了讓這些對象能被代碼訪問,我們必須通過Outlets把它們關聯上。你在Interface Builder中創建一個Outlet(對象關聯口)的時候,MonoDevelop將在這個類的designer.cs文件中添加一個匹配的屬性,讓你可以編程訪問這些控件。
Outlets(對象關聯口)
我們來為之前添加的標簽和按鈕控件添加outlets,以便能在代碼中訪問它們。這點在Leopard和Snow Leopard上也有所區別,所以大家要嚴格遵循這里提到的正確指示。
【SNOW LEOPARD指示開始】
確保Library Window是打開的。點擊頂部的“Classes”標簽。點擊第一個下拉列表框,這個就是所謂的“Library”,滾動到最后選擇“Other Classes”。就會顯示在你的項目中存在的自定義類。從上面列表中選擇AppDelegate,接著選擇下面的“Outlets”標簽:
點擊“+”按鈕兩次來創建兩個新的Outlet。
【SNOW LEOPARD指示結束】
【LEOPARD指示開始】
首先,保證在Document Window中App Delegate是被選中的。如果App Delegate未被選中,那么在創建Outlets的時候,它們的屬性不會被創建,或者會在錯誤的地方創建。
接下來,來看Identity Inspector。Identity Inspector是Inspector窗口的最后一個標簽頁?,F在,在Identity Inspector中定位到“Class Outlets”部分。在Class Outlets上,點擊“+”按鈕兩次來創建兩個新的Outlet。
【LEOPARD指示結束】
每個outlet都具有一個名稱和一個類型。名稱代表了控件屬性的名字,這個類似于ASP.NET的ID,或WPF中的Name。類型是 Outlet的實際類型,比如UIButton、UILabel、UITextView等等。為了命名它們,在它們的名稱上雙擊,鍵入相應的名稱。對于我們之前添加的outlet來說,我們修改為“btnClickMe”和“lblResult”。
目前,它們兩者的類型都是“id”。如果你不改變類型,就能把它們掛接到任何東西上,因為id就意味著動態類型,本質上就是.NET世界中的 “object”。id類型雖然好,不過我們打算把它們改為實際的類型。過一會我們會看到這樣做會有什么不同?,F在,雙擊btnClickMe的類型,鍵入“UIButton”。你的Class Outlets 窗口應該顯示如下這個樣子:
如果在里面沒有window的outlet,意味著你沒有在App Delegate創建outlet。如果這樣的話,刪除Outlets,保證在Document Window中選中App Delegate,重新創建outlets。
現在我們已經創建了這些outlets了,就需要實際地把它們關聯到我們的控件上。首先,在Inspector窗口上點擊第二個標簽頁,來選中 Connections Inspector。在Outlets部分,應該可以看到我們之前創建的兩個Outlets了。然而,你不能把它掛接到任何東西上。注意,“window”這個outlet已經掛接到“Window”對象上了。
為了掛接我們的Outlets,我們要從“Outlets”中的outlet圓點上,拖動到我們想要掛接的控件上。在這樣做的時候,我們將會看到如下所示的效果:
對兩個Outlet都進行這樣處理。你也可以從Connections Inspector拖到Document Window上。如果控件相互重疊的情況下,這樣就很有用。下面的截圖就描述了這種方式:
在我們這樣做的時候,你可能會注意到一些有趣的事情。因為設置lblResult的類型為UILabel,所以在我們把它的 Outlet拖到Window的時候,它只允許我們掛接到那些類型一致的控件上,在這個例子中就是UILabel。另外一方面,btnClickMe能被拖到任何東西上,因為它具有動態的ID類型。這就是我們要設置強類型outlet的一個原因,以便降低它掛接到錯誤控件上的可能性。當然,這不是必須的,不過這樣做是一個良好的習慣。
好的,現在我們創建好了界面了,outlets也掛接好了,讓我們回到MonoDevelop把一起串在一起。
回到MonoDevelop
如果你打開MainWindow.designer.cs,在其中會到兩個屬性:
- [MonoTouch.Foundation.Connect("btnClickMe")]
- private MonoTouch.UIKit.UIButton btnClickMe {
- get {
- return ((MonoTouch.UIKit.UIButton)(this.GetNativeField("btnClickMe")));
- }
- set {
- this.SetNativeField("btnClickMe", value);
- }
- }
- [MonoTouch.Foundation.Connect("lblResult")]
- private MonoTouch.UIKit.UILabel lblResult {
- get {
- return ((MonoTouch.UIKit.UILabel)(this.GetNativeField("lblResult")));
- }
- set {
- this.SetNativeField("lblResult", value);
- }
- }
有了這兩個屬性,就可以讓我們通過代碼來訪問標簽和按鈕了。在這里要注意一件有趣的事情——就算我們聲明btnClickMe的類型為 id,而自動創建出來的屬性也是強類型的UIButton。這是因為MonoDevelop足夠智能,可以查看outlet背后實際的類型,以便創建適合類型的屬性。這對于我們很有用,因為意味著我們在每次使用它的時候,都無需把btnClickMe屬性轉換為UIButton類型。
現在回到Main.cs文件,查看AppDelegate。我們來看一下FinishedLaunching方法。
- // This method is invoked when the application has loaded its UI and its ready to run
- public override bool FinishedLaunching (UIApplication app, NSDictionary options)
- {
- // If you have defined a view, add it here:
- // window.AddSubview (navigationController.View);
- window.MakeKeyAndVisible ();
- return true;
- }
正如注釋所建議的,這個方法在Application實例化后且已經準備好運行之時,由Objective-C運行時來調用。第一句(window.AddSubview)被注釋掉了,我們會在談論Model View Controller(MVC)模式的時候來研究它的真正作用。
下一句window.MakeKeyAndVisible,設置MainWindow為主窗口并讓其顯示出來。在 iPhone開發中,真正有意思的事情是你永遠有且有一個窗口在顯示。如果想在iPhone應用程序中顯示不同的界面,你要創建新的視圖,并用視圖控制器把其“推”到前端。然而,你不調用這個方法,iPhone OS就不會發送事件到你的窗口上。MakeKey這個部分是真正起作用的,而AndVisible部分實際上留有傳統OS X Cocoa框架的痕跡。
我們來添加一些新代碼到這個文件中。在我們創建Outlets的時候,我們是在AppDelegate中創建它們的。那意味著它們會出現在 AppDelegate類中,所以可以在這里來訪問它們。和傳統的.NET GUI編程有一點不同的是,通常會有一個MainWindow.cs文件,在那里面來處理所有窗口相關的代碼。而在這里,我們遵循Objective-C 的模式,就把代碼放在AppDelegate中。
我們來把AppDelegate類改為如下這樣子:
- // The name AppDelegate is referenced in the MainWindow.xib file.
- public partial class AppDelegate : UIApplicationDelegate
- {
- //---- number of times we've clicked
- protected int _numberOfClicks;
- // This method is invoked when the application has loaded its UI and its ready to run
- public override bool FinishedLaunching (UIApplication app, NSDictionary options)
- {
- // If you have defined a view, add it here:
- // window.AddSubview (navigationController.View);
- window.MakeKeyAndVisible ();
- //---- wire up our event handler
- this.btnClickMe.TouchDown += BtnClickMeTouchDown;
- return true;
- }
- protected void BtnClickMeTouchDown (object sender, EventArgs e)
- {
- //---- increment our counter
- this._numberOfClicks++;
- //---- update our label
- this.lblResult.Text = "Hello World, [" + this._numberOfClicks.ToString () + "] times";
- }
- // This method is required in iPhoneOS 3.0
- public override void OnActivated (UIApplication application)
- {
- }
- }
第一件事情,我們添加了一個變量來跟蹤點擊次數, _numberOfClicks。接著,我們添加這行代碼:this.btnClickMe.TouchDown += BtnClickMeTouchDown;
這就把btnClickMe的TouchDown事件(類似于OnClick)掛接到處理程序BtnClickMeTouchDown上
接著,在BtnClickMeTouchDown中,我們簡單地用按鈕被點擊多少次的數量值來更新標簽的顯示內容。
好了,我們已經完成了所有編程,讓我們來構建和運行一下。首先來構建。在菜單中,選擇Build : Build All。如果目前為止你都正確的按部就班的話,它應該能構建成功。下一步,就是在iPhone模擬器上運行它。在工具欄上,確保 debug|iPhoneSimulator被選中,如圖:
接著,在菜單中選擇Run : Run。在MonoTouch的評估版中,你只能在模擬器中運行,如果你打算在iPhone中運行,你會得到一個錯誤。
如果一切正常,模擬器會顯示出來(實際上,它有可能隱藏在MonoDevelop窗口的背后,所以你需要切換過去),那么你就能看到如下所示的效果:
點擊按鈕將會產生下圖的結果:
恭喜你!你已經創建并跑起你的第一個iPhone應用程序了。
Actions(動作)
在我們剛剛創建的應用程序中,我們有一些Outlets,在代碼中可以藉由屬性來訪問控件。就像在其他.NET GUI模型中,我們能把事件處理程序掛接到它們之上,來對事件作出響應。不過MonoTouch提供了另外一種響應用戶輸入的方式。這稱之為 Actions。Actions類似于WPF的Commands,用這種方式,多個控件可以調用同一個方法,然后依據調用者是誰來決定如何去處理。讓我們來稍微仔細地研究一下。確保你已經在MonoDevelop打開了Example_HelloWorld_1應用程序了。
雙擊MainWindow.xib文件來在Interface Builder中打開它?,F在在標簽控件下面添加兩個按鈕,類似下圖:
再次,我們要針對Leopard和Snow Leopard作出不同的說明,你要確定按照正確的部分進行操作。
【SNOW LEOPARD指示開始】
在Library窗口中,確保選中“Classes”標簽頁,并再次在頂部的下拉列表框中選擇“Other Classes”。接著,在上面選擇AppDelegate,在下面選擇“Actions”標簽頁。創建一個名為ActionButtonClick的 Action。你的Library窗口應該看起來如下所示:
【SNOW LEOPARD指示結束】
【LEOPARD指示開始】
在窗口管理器中,確保選中App Delegate 。接著在Identity Inspector窗口中,在“Class Actions”里面創建一個名為ActionButtonClick的Action。你的Identity Inspector應該看起來如下所示:
【LEOPARD指示結束】
我們剛剛在App Delegate上創建好了一個名為ActionButtonClick的通用動作?,F在,要做的就是把它關聯到按鈕的 TouchDown事件上,以便在按鈕被點擊的時候,這個Action能被調用。
首先,選擇一個動作按鈕,接著轉到Connections Inspector,把Touch Down拖動Document窗口中的App Delegate。如下圖所示:
注意,在我們拖到App Delegate的時候,會顯示出一個可用Actions的列表。選擇ActionButtonClick,現在按鈕上的TouchDown事件就關聯到這個動作上了:
為兩個動作按鈕都進行同樣的操作。如果我們在Connections Inspector中查看App Delegate,會這樣顯示:
通過點擊“Multiple”旁邊的箭頭,可展開和ActionButtonClick相關的控件。保存好.xib文件后,回到 MonoDevelop中。
如果我們看一下MainWindow.designer.cs,會發現多了一行新代碼:
- [MonoTouch.Foundation.Export("ActionButtonClick")]
- partial void ActionButtonClick (MonoTouch.UIKit.UIButton sender);
這是我們的Action的分部聲明。注意它用MonoTouch.Foundation.Export特性標記進行了裝飾。這使 Objective-C運行時可以找到關聯到我們Action上的適當方法。編譯器實際上會忽略沒有任何實現的分部方法(正如我們在這里所見的這個),那么這個分部方法的聲明實際上是為了在實現它的時候可以獲得代碼完成的功能。如果我們回到Main.cs,會看到它的真正作用。在AppDelegate類中,只要鍵入“partial”就會自動地得到ActionButtonClick的自動完成代碼:
我們把如下代碼寫在里面:
- partial void ActionButtonClick (UIButton sender)
- {
- //---- show which button was clicked
- this.lblResult.Text = sender.CurrentTitle + " Clicked";
- }
現在,如果你運行應用程序,在動作按鈕上點擊,將會看到如下所示的效果:
此時,我們已經完整地經歷了用MonoTouch來開發基本iPhone應用程序的過程?,F在,你應該對MonoTouch應用程序的結構、利用事件處理用戶交互,以及用Actions來處理用戶交互有了基本的了解。