Hello, Mac – 演练Hello, Mac – Walkthrough

通过 Xamarin.Mac,可使用以 Objective-C 或 Swift 进行开发时所用的 macOS API 来以 C# 和 .NET 开发完全本机 Mac 应用。Xamarin.Mac allows for the development of fully native Mac apps in C# and .NET using the same macOS APIs that are used when developing in Objective-C or Swift. 由于 Xamarin.Mac 与 Xcode 直接集成,开发人员可以使用 Xcode 的 Interface Builder 创建应用的用户界面(或选择通过 C# 代码直接创建)。Because Xamarin.Mac integrates directly with Xcode, the developer can use Xcode's Interface Builder to create an app's user interfaces (or optionally create them directly in C# code).

此外,由于 Xamarin.Mac 应用程序通过 C# 和 .NET 编写而成,因而可与 Xamarin.iOS 和 Xamarin.Android 移动应用共享代码;同时在每个平台上实现本机体验。Additionally, since Xamarin.Mac applications are written in C# and .NET, code can be shared with Xamarin.iOS and Xamarin.Android mobile apps; all while delivering a native experience on each platform.

本文通过生成一个对按钮点击次数进行计数的简单 Hello, Mac 应用,介绍了通过 Xamarin.Mac、Visual Studio for Mac 以及 Xcode 的 Interface Builder 创建 Mac 应用需要用到的主要概念 :This article will introduce the key concepts needed to create a Mac app using Xamarin.Mac, Visual Studio for Mac and Xcode's Interface Builder by walking through the process of building a simple Hello, Mac app that counts the number of times a button has been clicked:

包含以下概念:The following concepts will be covered:

  • Visual Studio for Mac – 介绍 Visual Studio for Mac,以及如何使用 Visual Studio for Mac 创建 Xamarin.Mac 应用程序。Visual Studio for Mac – Introduction to the Visual Studio for Mac and how to create Xamarin.Mac applications with it.
  • Xamarin.Mac 应用程序剖析 – Xamarin.Mac 应用程序组成部分。Anatomy of a Xamarin.Mac Application – What a Xamarin.Mac application consists of.
  • Xcode 的 Interface Builder - 如何使用 Xcode 的 Interface Builder 定义应用的用户界面。Xcode’s Interface Builder – How to use Xcode’s Interface Builder to define an app’s user interface.
  • 输出口和操作 - 如何使用输出口和操作在用户界面中连接控件。Outlets and Actions – How to use Outlets and Actions to wire up controls in the user interface.
  • 部署/测试 – 如何运行和测试 Xamarin.Mac 应用。Deployment/Testing – How to run and test a Xamarin.Mac app.

要求Requirements

Xamarin.Mac 应用程序开发需要以下条件:Xamarin.Mac application development requires:

若要运行使用 Xamarin.Mac 构建的应用程序,需要:To run an application built with Xamarin.Mac, you will need:

  • 运行 macOS 10.7 或更高版本的 Mac 计算机。A Mac computer running macOS 10.7 or greater.

警告

即将发布的 Xamarin.Mac 4.8 版本仅支持 macOS 10.9 或更高版本。The upcoming Xamarin.Mac 4.8 release will only support macOS 10.9 or higher. 早期版本的 Xamarin.Mac 支持 macOS 10.7 或更高版本,但这些较旧的 macOS 版本缺少足够的 TLS 基础结构,无法支持 TLS 1.2。Previous versions of Xamarin.Mac supported macOS 10.7 or higher, but these older macOS versions lack sufficient TLS infrastructure to support TLS 1.2. 若要面向 macOS 10.7 或 macOS 10.8,请使用 Xamarin.Mac 4.6 或更早版本。To target macOS 10.7 or macOS 10.8, use Xamarin.Mac 4.6 or earlier.

在 Visual Studio for Mac 中启动新的 Xamarin.Mac 应用Starting a new Xamarin.Mac App in Visual Studio for Mac

如上所述,本指南将介绍如何创建名称为 Hello_Mac 的 Mac 应用,该应用会向主窗口添加一个按钮和标签。As stated above, this guide will walk through the steps to create a Mac app called Hello_Mac that adds a single button and label to the main window. 点击此按钮后,标签会显示已点击次数。When the button is clicked, the label will display the number of times it has been clicked.

若要开始,请执行以下步骤:To get started, do the following steps:

  1. 启动 Visual Studio for Mac:Start Visual Studio for Mac:

  2. 单击“新建项目...”按钮以打开“新建项目”对话框,然后依次选择“Mac” > “应用” > “Cocoa 应用”,单击“下一步”按钮: Click on the New Project... button to open the New Project dialog box, then select Mac > App > Cocoa App and click the Next button:

  3. 在“应用名称” 中输入 Hello_Mac,其他所有项保持默认值。Enter Hello_Mac for the App Name, and keep everything else as default. 单击“下一步” :Click Next:

  4. 确认该新项目在计算机中的位置:Confirm the location of the new project on your computer:

  5. 单击“创建” 按钮。Click the Create button.

Visual Studio for Mac 会创建新的 Xamarin.Mac 应用,并显示添加到此应用解决方案的默认文件:Visual Studio for Mac will create the new Xamarin.Mac app and display the default files that get added to the app's solution:

Visual Studio for Mac 使用与Visual Studio 2019 相同的解决方案和项目结构 。Visual Studio for Mac uses the same Solution and Project structure as Visual Studio 2019. 解决方案是可包含一个或多个项目的容器;项目可包含应用程序、支持库和测试应用程序等。“文件 > 新建项目” 模板会自动创建一个解决方案和应用程序项目。A solution is a container that can hold one or more projects; projects can include applications, supporting libraries, test applications, etc. The File > New Project template creates a solution and an application project automatically.

Xamarin.Mac 应用程序剖析Anatomy of a Xamarin.Mac Application

Xamarin.Mac 应用程序编程与使用 Xamarin.iOS 编程非常相似。Xamarin.Mac application programming is very similar to working with Xamarin.iOS. iOS 使用 Mac 所用的 CocoaTouch 框架(Cocoa 的精简版本)。iOS uses the CocoaTouch framework, which is a slimmed-down version of Cocoa, used by Mac.

项目中所含文件如下:Take a look at the files in the project:

  • Main.cs 包含应用的主入口点。 Main.cs contains the main entry point of the app. 启动应用时,Main 类会包含运行的首个方法。When the app is launched, the Main class contains the very first method that is run.
  • AppDelegate.cs 包含的 AppDelegate 类负责侦听操作系统中的事件。 AppDelegate.cs contains the AppDelegate class that is responsible for listening to events from the operating system.
  • Info.plist 包含应用属性,例如应用程序名称和图标等属性。Info.plist contains app properties such as the application name, icons, etc.
  • Entitlements.plist 包含应用的授权,并允许访问 Sandboxing 和 iCloud 支持等。Entitlements.plist contains the entitlements for the app and allows access to things such as Sandboxing and iCloud support.
  • Main.storyboard 定义应用的用户界面(窗口和菜单),通过 Segues 设计窗口间的互连。Main.storyboard defines the user interface (Windows and Menus) for an app and lays out the interconnections between Windows via Segues. Storyboard 是包含视图(用户界面元素)定义的 XML 文件。Storyboards are XML files that contain the definition of views (user interface elements). 此文件可在 Xcode 内由 Interface Builder 创建和维护。This file can be created and maintained by Interface Builder inside of Xcode.
  • ViewController.cs 是主窗口的控制器。ViewController.cs is the controller for the main window. 控制器会在另一文章中进行详细介绍,但现在,可将控制器理解为任何特定视图的主引擎。Controllers will be covered in detail in another article, but for now, a controller can be thought of the main engine of any particular view.
  • ViewController.designer.cs 包含有助于与主屏幕用户界面进行集成的联结代码。ViewController.designer.cs contains plumbing code that helps integrate with the main screen’s user interface.

以下部分将简要介绍这些文件。The following sections, will take a quick look through some of these files. 之后会进行详细介绍,但现在了解相关基础知识会很有帮助。Later, they will be explored in more detail, but it’s a good idea to understand their basics now.

Main.csMain.cs

Main.cs 文件非常简单。The Main.cs file is very simple. 此文件包含静态 Main 方法,用于创建新 Xamarin.Mac 应用实例和传递处理 OS 事件的类的名称,在本示例中为 AppDelegate 类:It contains a static Main method which creates a new Xamarin.Mac app instance and passes the name of the class that will handle OS events, which in this case is the AppDelegate class:

using System;
using System.Drawing;
using Foundation;
using AppKit;
using ObjCRuntime;

namespace Hello_Mac
{
    class MainClass
    {
        static void Main (string[] args)
        {
            NSApplication.Init ();
            NSApplication.Main (args);
        }
    }
}

AppDelegate.csAppDelegate.cs

AppDelegate.cs 文件包含负责创建窗口和侦听 OS 事件的 AppDelegate 类:The AppDelegate.cs file contains an AppDelegate class, which is responsible for creating windows and listening to OS events:

using AppKit;
using Foundation;

namespace Hello_Mac
{
    [Register ("AppDelegate")]
    public class AppDelegate : NSApplicationDelegate
    {
        public AppDelegate ()
        {
        }

        public override void DidFinishLaunching (NSNotification notification)
        {
            // Insert code here to initialize your application
        }

        public override void WillTerminate (NSNotification notification)
        {
            // Insert code here to tear down your application
        }
    }
}

如果开发人员之前未生成过 iOS 应用,则可能对此代码并不熟悉,但其实此代码非常简单。This code is probably unfamiliar unless the developer has built an iOS app before, but it’s fairly simple.

应用实例化后,DidFinishLaunching 方法会运行,并实际上负责创建应用的窗口以及启动在其中显示视图的过程。The DidFinishLaunching method runs after the app has been instantiated, and it’s responsible for actually creating the app's window and beginning the process of displaying the view in it.

用户或系统实例化应用关闭时会调用 WillTerminate 方法。The WillTerminate method will be called when the user or the system has instantiated a shutdown of the app. 开发人员可使用此方法在应用退出前最终确定应用(例如保存用户参数设置或窗口大小和位置)。The developer should use this method to finalize the app before it quits (such as saving user preferences or window size and location).

ViewController.csViewController.cs

Cocoa(以及其派生产品 CocoaTouch)使用“模型视图控制器” (MVC) 模式。Cocoa (and by derivation, CocoaTouch) uses what’s known as the Model View Controller (MVC) pattern. ViewController 声明表示控制实际应用窗口的对象。The ViewController declaration represents the object that controls the actual app window. 通常,对于每个创建的窗口(以及窗口内许多其他项),都存在一个负责窗口生命周期的控制器,例如显示窗口、向窗口添加新视图(控件)等。Generally, for every window created (and for many other things within windows), there is a controller, which is responsible for the window’s lifecycle, such as showing it, adding new views (controls) to it, etc.

ViewController 类是主窗口的控制器。The ViewController class is the main window’s controller. 此控制器负责主窗口的生命周期。The controller is responsible for the life cycle of the main window. 之后会详细进行介绍,现在快速了解即可:This will be examined in detail later, for now take a quick look at it:

using System;

using AppKit;
using Foundation;

namespace Hello_Mac
{
    public partial class ViewController : NSViewController
    {
        public ViewController (IntPtr handle) : base (handle)
        {
        }

        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Do any additional setup after loading the view.
        }

        public override NSObject RepresentedObject {
            get {
                return base.RepresentedObject;
            }
            set {
                base.RepresentedObject = value;
                // Update the view, if already loaded.
            }
        }
    }
}

ViewController.Designer.csViewController.Designer.cs

主窗口类的设计器文件最初为空,但通过 Xcode Interface Builder 创建用户界面时会由 Visual Studio for Mac 自动进行填充:The designer file for the Main Window class is initially empty, but it will be automatically populated by Visual Studio for Mac as the user interface is created with Xcode Interface Builder:

// WARNING
//
// This file has been generated automatically by Visual Studio for Mac to store outlets and
// actions made in the UI designer. If it is removed, they will be lost.
// Manual changes to this file may not be handled correctly.
//
using Foundation;

namespace Hello_Mac
{
    [Register ("ViewController")]
    partial class ViewController
    {
        void ReleaseDesignerOutlets ()
        {
        }
    }
}

设计器文件不应直接编辑,因为设计器文件会由 Visual Studio for Mac 自动管理,以提供 pluming 代码,通过该代码可访问已添加到应用中任意窗口或视图的控件。Designer files should not be edited directly, as they’re automatically managed by Visual Studio for Mac to provide the plumbing code that allows access to controls that have been added to any window or view in the app.

创建 Xamarin.Mac 应用项目以及基本了解其组件后,可切换到 Xcode,使用 Interface Builder 创建用户界面。With the Xamarin.Mac app project created and a basic understanding of its components, switch to Xcode to create the user interface using Interface Builder.

Info.plistInfo.plist

Info.plist 文件包含 Xamarin.Mac 应用的相关信息,例如其“名称” 和“捆绑标识符” :The Info.plist file contains information about the Xamarin.Mac app such as its Name and Bundle Identifier:

它还可定义用于在“主界面”下拉菜单下显示 Xamarin.Mac 应用的用户界面的 StoryboardIt also defines the Storyboard that will be used to display the user interface for the Xamarin.Mac app under the Main Interface dropdown. 在上面的示例中,下拉菜单中的 Main 关联到“解决方案资源管理器” 中项目源树的 Main.storyboardIn example above, Main in the dropdown relates to the Main.storyboard in the project's source tree in the Solution Explorer. 它还定义应用图标,具体是通过指定包含图标的资产目录 (在此示例中为“应用图标” )。It also defines the app's icons by specifying the Asset Catalog that contains them (AppIcon in this case).

Entitlements.plistEntitlements.plist

应用的 Entitlements.plist 文件控制着 Xamarin.Mac 应用具有的权利,例如 SandboxingiCloudThe app's Entitlements.plist file controls entitlements that the Xamarin.Mac app has such as Sandboxing and iCloud:

对于 Hello World 示例,无需权利。For the Hello World example, no entitlements will be required. 下一部分介绍如何使用 Xcode 的 Interface Builder 编辑 Main.storyboard 文件和定义 Xamarin.Mac 应用的 UI。The next section shows how to use Xcode's Interface Builder to edit the Main.storyboard file and define the Xamarin.Mac app's UI.

Xcode 和 Interface Builder 简介Introduction to Xcode and Interface Builder

作为 Xcode 的一部分,Apple 已创建名为 Interface Builder 的工具,开发人员通过该工具可在设计器中直观地创建用户界面。As part of Xcode, Apple has created a tool called Interface Builder, which allows a developer to create a user interface visually in a designer. Xamarin.Mac 与 Interface Builder 集成非常流畅,可通过与 Objective-C 用户相同的工具创建 UI。Xamarin.Mac integrates fluently with Interface Builder, allowing UI to be created with the same tools as Objective-C users.

若要开始,请双击“解决方案资源管理器” 中的 Main.storyboard 文件将其打开,以便在 Xcode 和 Interface Builder 中进行编辑:To get started, double-click the Main.storyboard file in the Solution Explorer to open it for editing in Xcode and Interface Builder:

这会启动 Xcode,其如以下屏幕截图所示:This should launch Xcode and look like this screenshot:

开始设计界面前,请快速了解 Xcode 概述,熟悉将会使用的主要功能。Before starting to design the interface, take a quick overview of Xcode to orient with the main features that will be used.

备注

开发人员无需使用 Xcode 和 Interface Builder 来创建 Xamarin.Mac 应用的用户界面,可直接通过 C# 代码创建 UI,但这超出了本文的讨论范围。The developer doesn't have to use Xcode and Interface Builder to create the user interface for a Xamarin.Mac app, the UI can be created directly from C# code but that is beyond the scope of this article. 为简单起见,本教程其余部分会使用 Interface Builder 来创建用户界面。For the sake of simplicity, it will be using Interface Builder to create the user interface throughout the rest of this tutorial.

Xcode 组件Components of Xcode

从 Visual Studio for Mac 的 Xcode 中打开 .storyboard 文件时,“项目导航器” 位于左侧,“界面层次结构” 和“界面编辑器” 位于中间,“属性和实用程序” 部分位于右侧:When opening a .storyboard file in Xcode from Visual Studio for Mac, it opens with a Project Navigator on the left, the Interface Hierarchy and Interface Editor in the middle, and a Properties & Utilities section on the right:

后续部分介绍其中每个 Xcode 功能的作用以及如何使用这些功能创建 Xamarin.Mac 应用的界面。The following sections take a look at what each of these Xcode features do and how to use them to create the interface for a Xamarin.Mac app.

项目导航Project Navigation

打开 .storyboard 文件在 Xcode 中进行编辑时,Visual Studio for Mac 会在后台创建 Xcode 项目文件 ,以便在 Visual Studio for Mac 和 Xcode 之间传递更改。When opening a .storyboard file for editing in Xcode, Visual Studio for Mac creates a Xcode Project File in the background to communicate changes between itself and Xcode. 之后,开发人员从 Xcode 切换回 Visual Studio for Mac 时,对此项目所作的任何更改都将通过 Visual Studio for Mac 与 Xamarin.Mac 项目同步。Later, when the developer switches back to Visual Studio for Mac from Xcode, any changes made to this project are synchronized with the Xamarin.Mac project by Visual Studio for Mac.

通过“项目导航” 部分,开发人员可在组成此填充码 Xcode 项目的所有文件之间导航。The Project Navigation section allows the developer to navigate between all of the files that make up this shim Xcode project. 通常,开发人员只会对此列表中的 .storyboard 文件感兴趣,例如 Main.storyboardTypically, they will only be interested in the .storyboard files in this list such as Main.storyboard.

界面层次结构Interface Hierarchy

通过“界面层次结构”部分,开发人员可轻松访问用户界面的多个关键属性,例如占位符和主窗口 。The Interface Hierarchy section allows the developer to easily access several key properties of the user interface such as its Placeholders and main Window. 可使用此部分访问组成用户界面的各个元素(视图),并通过在层次结构内拖动这些元素来调整其嵌套方式。This section can be used to access the individual elements (views) that make up the user interface and to adjust the way they are nested by dragging them around within the hierarchy.

界面编辑器Interface Editor

“界面编辑器”部分提供了用户界面图形化布局的设计面 。从“属性和实用程序” 部分的“库” 中拖动元素来创建设计。The Interface Editor section provides the surface on which the user interface is graphically laid out. Drag elements from the Library section of the Properties & Utilities section to create the design. 用户界面元素(视图)添加到设计图面后,会添加到“界面层次结构” 部分,从而使其显示于“界面编辑器” 中。As user interface elements (views) are added to the design surface, they will be added to the Interface Hierarchy section in the order that they appear in the Interface Editor.

属性和实用程序Properties & Utilities

“属性和实用程序” 部分分为两个主要部分,即“属性” (又名“检查器”)和“库” :The Properties & Utilities section is divided into two main sections, Properties (also called Inspectors) and the Library:

本部分起初基本为空,但开发人员在“用户编辑器” 或“界面层次结构” 中选择元素后,“属性” 部分内会填充有开发人员可调整的特定元素和属性的相关信息。Initially this section is almost empty, however if the developer selects an element in the Interface Editor or Interface Hierarchy, the Properties section will be populated with information about the given element and properties that they can adjust.

“属性”部分内具有 8 个不同的检查器选项卡,如下所示 :Within the Properties section, there are eight different Inspector Tabs, as shown in the following illustration:

属性和实用程序类型Properties & Utility Types

由左至右,这些选项卡依次为:From left-to-right, these tabs are:

  • 文件检查器 – 文件检查器显示文件信息,例如正在编辑的 Xib 文件的文件名称和位置。File Inspector – The File Inspector shows file information, such as the file name and location of the Xib file that is being edited.
  • 快速帮助 – 快速帮助选项卡基于 Xcode 中所选内容提供相应背景帮助。Quick Help – The Quick Help tab provides contextual help based on what is selected in Xcode.
  • 标识检查器 – 标识检查器提供有关所选控件/视图的信息。Identity Inspector – The Identity Inspector provides information about the selected control/view.
  • 属性检查器 – 通过属性检查器,开发人员可自定义所选控件/视图的各种属性。Attributes Inspector – The Attributes Inspector allows the developer to customize various attributes of the selected control/view.
  • 大小检查器 – 通过大小检查器,开发人员可控制所选控件/视图的大小和调整大小。Size Inspector – The Size Inspector allows the developer to control the size and resizing behavior of the selected control/view.
  • 连接检查器 – 连接检查器显示所选控件的“输出口” 和“操作” 连接。Connections Inspector – The Connections Inspector shows the Outlet and Action connections of the selected controls. 后文将详细介绍输出口和操作。Outlets and Actions will be discussed in detail below.
  • 绑定检查器 – 通过绑定检查器,开发人员可配置控件,以使其值自动绑定到数据模型。Bindings Inspector – The Bindings Inspector allows the developer to configure controls so that their values are automatically bound to data models.
  • 视图效果检查器 – 通过视图效果检查器,开发人员可对控件指定效果,例如动画。View Effects Inspector – The View Effects Inspector allows the developer to specify effects on the controls, such as animations.

使用“库” 部分查找要放入设计器的控件和对象,从而以图形方式生成用户界面:Use the Library section to find controls and objects to place into the designer to graphically build the user interface:

创建界面Creating the Interface

了解 Xcode IDE 和 Interface Builder 的基础知识后,开发人员便可创建主视图的用户界面。With the basics of the Xcode IDE and Interface Builder covered, the developer can create the user interface for the main view.

请按照这些步骤使用 Interface Builder:Follow these steps to use Interface Builder:

  1. 在 Xcode 中,从“库” 部分拖动“Push Button” :In Xcode, drag a Push Button from the Library Section:

  2. 将此按钮拖放到“界面编辑器” 中的“视图” (在“窗口控制器” 下方):Drop the button onto the View (under the Window Controller) in the Interface Editor:

  3. 单击“属性检查器” 中的 Title 属性,将此按钮的标题更改为“Click Me” :Click on the Title property in the Attribute Inspector and change the button's title to Click Me:

  4. 从“库” 部分拖动“标签” :Drag a Label from the Library Section:

  5. 将此标签拖放到“界面编辑器” 中此按钮旁的“窗口” 中:Drop the label onto the Window beside the button in the Interface Editor:

  6. 按住此标签上的右控点,将其拖动至靠近窗口边缘的位置:Grab the right handle on the label and drag it until it is near the edge of the window:

  7. 选择刚才在“界面编辑器” 中添加的按钮,然后单击窗口底部的“约束编辑器” 图标:Select the Button just added in the Interface Editor, and click the Constraints Editor icon at the bottom of the window:

  8. 在编辑器顶部,单击顶部左侧的红色 I 型光标At the top of the editor, click the Red I-Beams at the top and left. 这样,调整窗口大小后,此按钮会保持处于屏幕左上角的相同位置。As the window is resized, this will keep the button in the same location at the top left corner of the screen.

  9. 接下来,选中“高度” 和“宽度” 框,并使用默认大小。Next, check the Height and Width boxes and use the default sizes. 这样,窗口大小调整后,此按钮会保持相同大小。This keeps the button at the same size when the window resizes.

  10. 单击“添加 4 个约束” 按钮添加约束,然后关闭编辑器。Click the Add 4 Constraints button to add the constraints and close the editor.

  11. 选择此标签,然后再次单击“约束编辑器” 图标:Select the label and click the Constraints Editor icon again:

  12. 通过单击“约束编辑器” 顶部、右侧和左侧的红色 I 型光标,指示此标签处于其特定的 X 和 Y 位置,以及在运行的应用程序中窗口大小调整时进行扩展和收缩。By clicking Red I-Beams at the top, right and left of the Constraints Editor, tells the label to be stuck to its given X and Y locations and to grow and shrink as the window is resized in the running application.

  13. 再次选中“高度” 框并使用默认大小,然后单击“添加 4 个约束” 按钮添加约束,然后关闭编辑器。Again, check the Height box and use the default size, then click the Add 4 Constraints button to add the constraints and close the editor.

  14. 保存用户界面更改。Save the changes to the user interface.

调整控件大小和移动控件时,请注意 Interface Builder 会根据 macOS 人机界面指南提供有用的快捷提示。While resizing and moving controls around, notice that Interface Builder gives helpful snap hints that are based on macOS Human Interface Guidelines. 这些指南有助于开发人员创建出外观和风格为 Mac 用户所熟悉的优质应用。These guidelines will help the developer to create high quality apps that will have a familiar look and feel for Mac users.

在“界面层次结构”部分中可查看组成用户界面的元素布局和层次结构的显示方式 :Look in the Interface Hierarchy section to see how the layout and hierarchy of the elements that make up the user interface are shown:

如果需要,开发人员可从此处选择要进行编辑的项,或通过拖动对 UI 元素进行重新排序。From here the developer can select items to edit or drag to reorder UI elements if needed. 例如,如果某 UI 元素被另一元素覆盖,开发人员可将其拖动到列表底部,使其成为窗口上最顶层的项。For example, if a UI element was being covered by another element, they could drag it to the bottom of the list to make it the top-most item on the window.

用户界面创建后,开发人员需要公开 UI 项,以便 Xamarin.Mac 可进行访问和在 C# 代码中与之交互。With the user interface created, the developer will need to expose the UI items so that Xamarin.Mac can access and interact with them in C# code. 接下来的“输出口和操作” 部分中介绍了其执行方法。The next section, Outlets and Actions, shows how to do this.

输出口和操作Outlets and Actions

输出口操作是什么?So what are Outlets and Actions? 在传统的 .NET 用户界面编程中,用户界面中的控件在添加时会自动作为属性公开。In traditional .NET user interface programming, a control in the user interface is automatically exposed as a property when it’s added. 然而在 Mac 中情况则不同,如果仅将控件添加到视图,代码不可对其进行访问。Things work differently in Mac, simply adding a control to a view doesn’t make it accessible to code. 开发人员必须对代码显式公开 UI。The developer must explicitly expose the UI element to code. 为此,Apple 提供了两个选项:In order do this, Apple provides two options:

  • 输出口 – 输出口类似于属性。Outlets – Outlets are analogous to properties. 如果开发人员将控件连接到输出口,则控件会通过属性对代码公开,从而使控件可执行诸如附加事件处理程序和调用方法等操作。If the developer wires up a control to an Outlet, it’s exposed to the code via a property, so they can do things like attach event handlers, call methods on it, etc.
  • 操作 - 操作类似于 WPF 中的命令模式。Actions – Actions are analogous to the command pattern in WPF. 例如,对控件执行操作时,比如单击按钮,则控件会自动在代码中调用方法。For example, when an Action is performed on a control, say a button click, the control will automatically call a method in the code. 操作功能强大且非常方便,因为开发人员可对同一操作连接多个控件。Actions are powerful and convenient because the developer can wire up many controls to the same Action.

在 Xcode 中,会通过拖动控件 直接将输出口操作添加到代码。In Xcode, Outlets and Actions are added directly in code via Control-dragging. 更具体地说,这意味着若要创建“输出口”或“操作”,开发人员需选择要添加“输出口”和“操作”的控件元素,按住键盘上的 Ctrl 键,然后将此控件直接拖到代码中 。More specifically, this means that to create an Outlet or Action, the developer will choose a control element to add an Outlet or Action to, hold down the Control key on the keyboard, and drag that control directly into the code.

对于 Xamarin.Mac 开发人员,这意味着开发人员应拖动到与要创建输出口操作的 C# 文件所对应的 Objective-C 存根文件中。For Xamarin.Mac developers, this means that the developer will drag into the Objective-C stub files that correspond to the C# file where they want to create the Outlet or Action. Visual Studio for Mac 创建一个名为 ViewController.h 的文件作为其生成的填充码 Xcode 项目的一部分,以便使用 Interface Builder:Visual Studio for Mac created a file called ViewController.h as part of the shim Xcode Project it generated to use Interface Builder:

此存根 .h 文件反映了创建新的 NSWindow 时自动添加到 Xamarin.Mac 项目的 ViewController.designer.csThis stub .h file mirrors the ViewController.designer.cs that is automatically added to a Xamarin.Mac project when a new NSWindow is created. 此文件用于同步对 Interface Builder 所作的更改,且会在此文件中创建输出口操作,从而使 UI 元素对 C# 代码公开。This file will be used to synchronize the changes made by Interface Builder and is where the Outlets and Actions are created so that UI elements are exposed to C# code.

添加输出口Adding an Outlet

基本了解输出口操作后,请创建输出口将创建的标签对 C# 代码公开。With a basic understanding of what Outlets and Actions are, create an Outlet to expose the Label created to our C# code.

请执行以下操作:Do the following:

  1. 在 Xcode 中屏幕右上角,单击“双圆” 按钮,打开“助手编辑器” :In Xcode at the far right top-hand corner of the screen, click the Double Circle button to open the Assistant Editor:

  2. 此时 Xcode 会切换为拆分视图模式,“界面编辑器” 位于一边,“代码编辑器” 位于另一边。The Xcode will switch to a split-view mode with the Interface Editor on one side and a Code Editor on the other.

  3. 请注意,Xcode 已自动在“代码编辑器” 中选取 ViewController.m 文件,这是不正确的。Notice that Xcode has automatically picked the ViewController.m file in the Code Editor, which is incorrect. 通过以上关于什么是输出口操作的讨论可知,开发人员需要选中 ViewController.hFrom the discussion on what Outlets and Actions are above, the developer will need to have the ViewController.h selected.

  4. 在“代码编辑器” 顶部,单击“自动链接” 并选择 ViewController.h 文件:At the top of the Code Editor click on the Automatic Link and select the ViewController.h file:

  5. 此时 Xcode 应选择了正确的文件:Xcode should now have the correct file selected:

  6. 最后一个步骤至关重要!:如果未选中正确的文件,则无法创建输出口和操作,或者会公开给 C# 中错误的类! The last step was very important!: if you didn't have the correct file selected, you won't be able to create Outlets and Actions, or they will be exposed to the wrong class in C#!

  7. 在“界面编辑器” 中,按住键盘上的 Ctrl 键,单击并将前面创建的标签拖动到代码编辑器中(@interface ViewController : NSViewController {} 代码下方):In the Interface Editor, hold down the Control key on the keyboard and click-drag the label created above onto the code editor just below the @interface ViewController : NSViewController {} code:

  8. 会显示一个对话框。A dialog box will be displayed. 使“连接” 保持设置为“输出口” ,然后在“名称” 中输入 ClickedLabelLeave the Connection set to Outlet and enter ClickedLabel for the Name:

  9. 单击“连接” 按钮,创建输出口Click the Connect button to create the Outlet:

  10. 保存对文件所做的更改。Save the changes to the file.

添加操作Adding an Action

接下来,对 C# 代码公开按钮。Next, expose the button to C# code. 与上面的标签类似,开发人员可将按钮连接到输出口Just like the Label above, the developer could wire the button up to an Outlet. 由于只希望对点击的按钮响应,因此改用操作Since we only want to respond to the button being clicked, use an Action instead.

请执行以下操作:Do the following:

  1. 请确保 Xcode 仍位于“助手编辑器” 中,且 ViewController.h 文件在“代码编辑器” 中可见。Ensure that Xcode is still in the Assistant Editor and the ViewController.h file is visible in the Code Editor.

  2. 在“界面编辑器” 中,按住键盘上的 Ctrl 键,单击并将前面创建的按钮拖动到代码编辑器中(@property (assign) IBOutlet NSTextField *ClickedLabel; 代码下方):In the Interface Editor, hold down the Control key on the keyboard and click-drag the button created above onto the code editor just below the @property (assign) IBOutlet NSTextField *ClickedLabel; code:

  3. 将“连接” 类型更改为“操作” :Change the Connection type to Action:

  4. 输入 ClickedButton 作为名称Enter ClickedButton as the Name:

  5. 单击“连接” 按钮,创建操作Click the Connect button to create Action:

  6. 保存对文件所做的更改。Save the changes to the file.

用户界面连接和公开给 C# 代码后,请切换回 Visual Studio for Mac,使其同步在 Xcode 和 Interface Builder 中所作的更改。With the user interface wired-up and exposed to C# code, switch back to Visual Studio for Mac and let it synchronize the changes made in Xcode and Interface Builder.

备注

对第一个应用创建用户界面、输出口和操作可能花费了较长的时间,且工作看起来较大,但其实大部分时间是用于介绍许多新概念和新功能 。It probably took a long time to create the user interface and Outlets and Actions for this first app, and it may seem like a lot of work, but a lot of new concepts were introduced and a lot of time was spent covering new ground. 使用 Interface Builder 练习一段时间后,一两分钟内便可创建此界面及其所有的输出口和操作 。After practicing for a while and working with Interface Builder, this interface and all its Outlets and Actions can be created in just a minute or two.

与 Xcode 同步更改Synchronizing Changes with Xcode

开发人员从 Xcode 切换回 Visual Studio for Mac 时,在 Xcode 中所作的任何更改将会自动与 Xamarin.Mac 项目同步。When the developer switches back to Visual Studio for Mac from Xcode, any changes that they have made in Xcode will automatically be synchronized with the Xamarin.Mac project.

在“解决方案资源管理器”中选择 ViewController.designer.cs,查看 C# 代码中如何连接输出口和操作 :Select the ViewController.designer.cs in the Solution Explorer to see how the Outlet and Action have been wired up in the C# code:

注意 ViewController.designer.cs 文件中的这两个定义:Notice how the two definitions in the ViewController.designer.cs file:

[Outlet]
AppKit.NSTextField ClickedLabel { get; set; }

[Action ("ClickedButton:")]
partial void ClickedButton (Foundation.NSObject sender);

与 Xcode 的 ViewController.h 文件中的定义对齐:Line up with the definitions in the ViewController.h file in Xcode:

@property (assign) IBOutlet NSTextField *ClickedLabel;
- (IBAction)ClickedButton:(id)sender;

Visual Studio for Mac 会侦听对 .h 文件的更改,然后在相应的 .designer.cs 文件中自动同步这些更改,以将其公开给应用。Visual Studio for Mac listens for changes to the .h file, and then automatically synchronizes those changes in the respective .designer.cs file to expose them to the app. 请注意,ViewController.designer.cs 是一个分部类,因此 Visual Studio for Mac 不必修改 ViewController.cs,它会覆盖开发人员对此类所作的任何更改。Notice that ViewController.designer.cs is a partial class, so that Visual Studio for Mac doesn't have to modify ViewController.cs which would overwrite any changes that the developer has made to the class.

正常情况下,开发人员不需要打开 ViewController.designer.cs,此处提供仅为了介绍方便。Normally, the developer will never need to open the ViewController.designer.cs, it was presented here for educational purposes only.

备注

大多数情况下,Visual Studio for Mac 会自动发现 Xcode 中所作的任何更改,并将其同步到 Xamarin.Mac 项目。In most situations, Visual Studio for Mac will automatically see any changes made in Xcode and sync them to the Xamarin.Mac project. 如果同步不自动进行,请切换回 Xcode,然后再次切换到 Visual Studio for Mac。In the off occurrence that synchronization doesn't automatically happen, switch back to Xcode and then back to Visual Studio for Mac again. 这通常会开始同步周期。This will normally kick off a synchronization cycle.

编写代码Writing the Code

创建用户界面并将其 UI 元素通过输出口和操作公开给代码后,便可开始编写代码以最终完成程序 。With the user interface created and its UI elements exposed to code via Outlets and Actions, we are finally ready to write the code to bring the program to life.

对于此示例应用,每次单击第一个按钮时,会更新标签,显示该按钮的已点击次数。For this sample app, every time the first button is clicked, the label will be updated to show how many times the button has been clicked. 为完成此操作,请通过在“解决方案资源管理器”中双击 ViewController.cs 文件以将它打开进行编辑 :To accomplish this, open the ViewController.cs file for editing by double-clicking it in the Solution Explorer:

首先,在 ViewController 类中创建类级别变量以跟踪已发生的点击数。First, create a class-level variable in the ViewController class to track the number of clicks that have happened. 编辑类定义,使其类似于如下所示:Edit the class definition and make it look like the following:

namespace Hello_Mac
{
    public partial class ViewController : NSViewController
    {
        private int numberOfTimesClicked = 0;
        ...

接下来,在同一类 (ViewController) 中,替代 ViewDidLoad 方法和某些代码,从而设置标签的初始消息:Next, in the same class (ViewController), override the ViewDidLoad method and add some code to set the initial message for the label:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Set the initial value for the label
    ClickedLabel.StringValue = "Button has not been clicked yet.";
}

请使用 ViewDidLoad,不要使用 Initialize 等其他方法,因为 OS 从 .storyboard 加载和实例化用户界面后会调用 ViewDidLoadUse ViewDidLoad, instead of another method such as Initialize, because ViewDidLoad is called after the OS has loaded and instantiated the user interface from the .storyboard file. 如果开发人员在 .storyboard 文件完全加载和实例化之前尝试访问标签控件,则会出现 NullReferenceException 错误,因为此时标签控件尚不存在 。If the developer tried to access the label control before the .storyboard file has been fully loaded and instantiated, they would get a NullReferenceException error because the label control would not exist yet.

下一步,添加代码以对用户点击按钮作出响应。Next, add the code to respond to the user clicking the button. 将下面的分部方法添加到 ViewController 类:Add the following partial method to the ViewController class:

partial void ClickedButton (Foundation.NSObject sender) {
    // Update counter and label
    ClickedLabel.StringValue = string.Format("The button has been clicked {0} time{1}.",++numberOfTimesClicked, (numberOfTimesClicked < 2) ? "" : "s");
}

此代码会附加到在 Xcode 和 Interface Builder 中创建的操作,且每次用户点击按钮时都会调用此代码。This code attaches to the Action created in Xcode and Interface Builder and will be called any time the user clicks the button.

测试应用程序Testing the Application

现在即可生成并运行应用,确保其可按预期运行。It’s time to build and run the app to make sure it runs as expected. 开发人员可在一个步骤中同时生成和运行应用,或者只生成应用而不运行。The developer can build and run all in one step, or they can build it without running it.

生成应用时,开发人员可选择所需的版本类型:Whenever an app is built, the developer can choose what kind of build they want:

  • 调试 – 调试版本会编译到 .app(应用程序)文件,其中包含的一些额外元数据可使开发人员在应用运行时进行相关调试。Debug – A debug build is compiled into an .app (application) file with a bunch of extra metadata that allows the developer to debug what’s happening while the app is running.
  • 发布 – 发布版本也会创建 .app 文件,但其中不包含调试调试信息,因此其大小更小,执行速度更快。Release – A release build also creates an .app file, but it doesn’t include debug information, so it’s smaller and executes faster.

开发人员可以从 Visual Studio for Mac 屏幕左上角的“配置选择器” 中选择生成的类型:The developer can select the type of build from the Configuration Selector at the upper left-hand corner of the Visual Studio for Mac screen:

生成应用程序Building the Application

本示例中,只需调试版本,因此请确保选择“调试” 。In the case of this example, we just want a debug build, so ensure that Debug is selected. 首先,通过按 ⌘B 或在“生成” 菜单中选择“生成所有” ,生成应用。Build the app first by either pressing ⌘B, or from the Build menu, choose Build All.

如果没有任何错误,则 Visual Studio for Mac 状态栏中会显示“生成成功” 消息。If there weren't any errors, a Build Succeeded message will be displayed in Visual Studio for Mac's status bar. 如果出现错误,请检查项目,并确定是否正确执行了上述步骤。If there were errors, review the project and make sure that the steps above have been followed correctly. 请首先确认代码(Xcode 和 Visual Studio for Mac 中的代码)与本教程中的代码匹配。Start by confirming that the code (both in Xcode and in Visual Studio for Mac) matches the code in the tutorial.

运行应用程序Running the Application

可通过三种方式运行应用:There are three ways to run the app:

  • ⌘+EnterPress ⌘+Enter.
  • 在“运行” 菜单中,选择“调试” 。From the Run menu, choose Debug.
  • 单击 Visual Studio for Mac 工具栏中的“播放” 按钮(位于“解决方案资源管理器” 上方)。Click the Play button in the Visual Studio for Mac toolbar (just above the Solution Explorer).

应用会生成(如果尚未生成),以调试模式启动并显示主界面窗口:The app will build (if it hasn’t been built already), start in debug mode and display its main interface window:

如果多次点击按钮,则标签会更新计数:If the button is clicked a few times, the label should be updated with the count:

下一步Where to Next

了解 Xamarin.Mac 应用程序基础知识后,请阅读以下文档,进行深入了解:With the basics of working with a Xamarin.Mac application down, take a look at the following documents to get a deeper understanding:

  • Storyboard 简介 - 此文提供有关 Xamarin.Mac 应用中的 Storyboard 的简介。Introduction to Storyboards - This article provides an introduction to working with Storyboards in a Xamarin.Mac app. 其中介绍了如何使用 Storyboard 和 Xcode 的 Interface Builder 创建和维护应用 UI。It covers creating and maintaining the app's UI using storyboards and Xcode's Interface Builder.
  • 窗口 - 本文介绍 Xamarin.Mac 应用程序中窗口和窗格的相关内容。Windows - This article covers working with Windows and Panels in a Xamarin.Mac application. 其中包括在 Xcode 和 Interface Builder 中创建和维护窗口与窗格、从 .xib 文件加载窗口和窗格、使用窗口以及响应 C# 代码中的窗口。It covers creating and maintaining Windows and Panels in Xcode and Interface builder, loading Windows and Panels from .xib files, using Windows and responding to Windows in C# code.
  • 对话框 - 本文介绍如何在 Xamarin.Mac 应用程序中使用对话框和模式窗口。Dialogs - This article covers working with Dialogs and Modal Windows in a Xamarin.Mac application. 其中包含如何在 Xcode 和 Interface Builder 中创建和维护模式窗口、使用标准对话框、显示以及响应 C# 代码中的窗口。It covers creating and maintaining Modal Windows in Xcode and Interface builder, working with standard dialogs, displaying and responding to Windows in C# code.
  • 警告 - 本文介绍 Xamarin.Mac 应用程序中警告的相关内容。Alerts - This article covers working with Alerts in a Xamarin.Mac application. 其中包括通过 C# 代码创建和显示警告以及响应警告。It covers creating and displaying Alerts from C# code and responding to Alerts.
  • 菜单 - 从屏幕顶部的应用程序主菜单到可在窗口中任意位置出现的弹出菜单和上下文菜单,Mac 应用程序用户界面中的各个部分都会使用到菜单。Menus - Menus are used in various parts of a Mac application's user interface; from the application's main menu at the top of the screen to pop up and contextual menus that can appear anywhere in a window. 菜单是构成 Mac 应用程序用户体验的一个组成部分。Menus are an integral part of a Mac application's user experience. 本文介绍如何在 Xamarin.Mac 应用程序中使用 Cocoa 菜单。This article covers working with Cocoa Menus in a Xamarin.Mac application.
  • 工具栏 - 本文介绍 Xamarin.Mac 应用程序中工具栏的相关内容。Toolbars - This article covers working with Toolbars in a Xamarin.Mac application. 其中包含It covers creating and maintaining. 如何在 Xcode 和 Interface Builder 中创建和维护工具栏、如何使用输出口和操作对代码公开工具栏项、如何启用和禁用工具栏项以及响应 C# 代码中的工具栏项。Toolbars in Xcode and Interface builder, how to expose the Toolbar Items to code using Outlets and Actions, enabling and disabling Toolbar Items and finally responding to Toolbar Items in C# code.
  • 表视图 - 本文介绍如何使用 Xamarin.Mac 应用程序中表视图。Table Views - This article covers working with Table Views in a Xamarin.Mac application. 其中包含在如何 Xcode 和 Interface Builder 中创建和维护表视图、如何使用输出口和操作对代码公开表视图项、如何填充表项以及响应 C# 代码中的表视图项。It covers creating and maintaining Table Views in Xcode and Interface builder, how to expose the Table View Items to code using Outlets and Actions, populating Table Items and finally responding to Table View Items in C# code.
  • 大纲视图 - 本文介绍如何在 Xamarin.Mac 应用程序中使用大纲视图。Outline Views - This article covers working with Outline Views in a Xamarin.Mac application. 其中包含如何在 Xcode 和 Interface Builder 中创建和维护大纲视图、如何使用输出口和操作对代码公开大纲视图项、填充大纲项以及响应 C# 代码中的大纲视图项。It covers creating and maintaining Outline Views in Xcode and Interface builder, how to expose the Outline View Items to code using Outlets and Actions, populating Outline Items and finally responding to Outline View Items in C# code.
  • 源列表 - 本文介绍如何 Xamarin.Mac 应用程序中使用源列表。Source Lists - This article covers working with Source Lists in a Xamarin.Mac application. 其中包含如何在 Xcode 和 Interface Builder 中创建和维护源列表、如何使用输出口和操作对代码公开源列表项、如何填充源列表项以及响应 C# 代码中的源列表项。It covers creating and maintaining Source Lists in Xcode and Interface builder, how to expose the Source Lists Items to code using Outlets and Actions, populating Source List Items and finally responding to Source List Items in C# code.
  • 集合视图 - 本文介绍如何在 Xamarin.Mac 应用程序中使用集合视图。Collection Views - This article covers working with Collection Views in a Xamarin.Mac application. 其中包含如何在 Xcode 和 Interface Builder 中创建和维护集合视图、如何使用操作对代码公开集合视图元素、如何填充集合视图以及响应 C# 代码中的集合视图。It covers creating and maintaining Collection Views in Xcode and Interface builder, how to expose the Collection View elements to code using Outlets and Actions, populating Collection Views and finally responding to Collection Views in C# code.
  • 图像 - 本文介绍如何在 Xamarin.Mac 应用中使用图像和图标。Working with Images - This article covers working with Images and Icons in a Xamarin.Mac application. 其中包括如何创建和维护用于创建应用图标的图像以及如何在 C# 代码和 Xcode 的 Interface Builder 中使用图像。It covers creating and maintaining the images needed to create an app's Icon and using Images in both C# code and Xcode's Interface Builder.

Mac 示例库包含即时可用的代码示例,以便于学习 Xamarin.Mac。The Mac Samples Gallery contains ready-to-use code examples to help learn Xamarin.Mac.

SourceWriter 示例应用是一个完整的 Xamarin.Mac 应用示例(其中包含用户在典型 Mac 应用程序中可能希望找到的许多功能)。One complete Xamarin.Mac app that includes many of the features a user would expect to find in a typical Mac application is the SourceWriter Sample App. SourceWriter 是一个非常简单的源代码编辑器,提供代码补全和简单语法突出显示支持。SourceWriter is a simple source code editor that provides support for code completion and simple syntax highlighting.

SourceWriter 代码已经完全注释,且在可用时,提供了相关链接,链接涵盖了从关键技术或方法到 Xamarin.Mac 文档中的相关信息。The SourceWriter code has been fully commented and, where available, links have been provided from key technologies or methods to relevant information in the Xamarin.Mac documentation.

总结Summary

本文介绍标准 Xamarin.Mac 应用的基础知识。This article covered the basics of a standard Xamarin.Mac app. 其中包括如何在 Visual Studio for Mac 中创建新应用,如何在 Xcode 和 Interface Builder 中设计用户界面,如何使用输出口 和操作 对 C# 代码公开 UI 元素,如何添加代码处理 UI 元素,以及最终生成和测试 Xamarin.Mac 应用。It covered creating a new app in Visual Studio for Mac, designing the user interface in Xcode and Interface Builder, exposing UI elements to C# code using Outlets and Actions, adding code to work with the UI elements and finally, building and testing a Xamarin.Mac app.