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窗口的最后一个标签页。现在,在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类型虽然好,不过我们打算把它们改为实际的类型。过一会我们会看到这样做会有什么不同。现在,双击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中打开它。现在在标签控件下面添加两个按钮,类似下图:
再次,我们要针对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的通用动作。现在,要做的就是把它关联到按钮的
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) { //---- showwhich button was clicked this.lblResult.Text = sender.CurrentTitle +" Clicked"; } |
现在,如果你运行应用程序,在动作按钮上点击,将会看到如下所示的效果:
此时,我们已经完整地经历了用MonoTouch来开发基本iPhone应用程序的过程。现在,你该对MonoTouch应用程序的结构、利用事件处理用户交互,以及用Actions来处理用户交互有了基本的了解。不过,还有一件重要的事情被忽略了,我们应用程序只具有一个界面。
MonoTouch:用.NET开发iPhone应用(上) |