Xamarin.Mac의 데이터 바인딩 및 키-값 코딩

이 문서에서는 Xcode의 인터페이스 작성기에서 UI 요소에 데이터 바인딩을 허용하기 위해 키-값 코딩 및 키-값 관찰을 사용하는 방법을 설명합니다.

개요

Xamarin.Mac 애플리케이션에서 C# 및 .NET을 사용하는 경우 개발자와 Xcode에서 Objective-C 작업하는 것과 동일한 키-값 코딩 및 데이터 바인딩 기술에 액세스할 수 있습니다. Xamarin.Mac은 Xcode와 직접 통합되므로 코드를 작성하는 대신 Xcode의 인터페이스 작성기를 사용하여 UI 요소를 사용하여 데이터 바인딩에 사용할 수 있습니다.

Xamarin.Mac 애플리케이션에서 키-값 코딩 및 데이터 바인딩 기술을 사용하면 UI 요소를 채우고 작업하기 위해 작성하고 기본 코드의 양을 크게 줄일 수 있습니다. 또한 프런트 엔드 사용자 인터페이스(Model-View-Controller)에서 백업 데이터(데이터 모델)를 추가로 분리하여 보다 기본 더 유연하고 유연한 애플리케이션 디자인을 얻을 수 있습니다.

An example of the running app

이 문서에서는 Xamarin.Mac 애플리케이션에서 키-값 코딩 및 데이터 바인딩을 사용하는 기본 사항을 설명합니다. 이 문서에서 사용할 주요 개념과 기술을 다루므로 Hello, Mac 문서, 특히 Xcode 및 인터페이스 작성기 및 콘센트 및 작업 소개 섹션을 통해 작업하는 것이 좋습니다.

Xamarin.Mac Internals 문서의 섹션Objective-C대한 C# 클래스/메서드 노출을 살펴보고 C# 클래스 Objective-C 를 개체 및 UI 요소에 연결하는 데 사용되는 특성과 Export 특성을 설명 Register 합니다.

키-값 코딩이란?

KVC(키-값 코딩)는 인스턴스 변수 또는 접근자 메서드()를 통해 액세스하는 대신 키(특수 형식 문자열)를 사용하여 속성을 식별하여 개체의 속성에get/set 간접적으로 액세스하는 메커니즘입니다. Xamarin.Mac 애플리케이션에서 키-값 코딩 규격 접근자를 구현하면 KVO(키-값 관찰), 데이터 바인딩, 코어 데이터, Cocoa 바인딩 및 스크립트 기능과 같은 다른 macOS(이전의 OS X) 기능에 액세스할 수 있습니다.

Xamarin.Mac 애플리케이션에서 키-값 코딩 및 데이터 바인딩 기술을 사용하면 UI 요소를 채우고 작업하기 위해 작성하고 기본 코드의 양을 크게 줄일 수 있습니다. 또한 프런트 엔드 사용자 인터페이스(Model-View-Controller)에서 백업 데이터(데이터 모델)를 추가로 분리하여 보다 기본 더 유연하고 유연한 애플리케이션 디자인을 얻을 수 있습니다.

예를 들어 KVC 규격 개체의 다음 클래스 정의를 살펴보겠습니다.

using System;
using Foundation;

namespace MacDatabinding
{
    [Register("PersonModel")]
    public class PersonModel : NSObject
    {
        private string _name = "";

        [Export("Name")]
        public string Name {
            get { return _name; }
            set {
                WillChangeValue ("Name");
                _name = value;
                DidChangeValue ("Name");
            }
        }

        public PersonModel ()
        {
        }
    }
}

먼저 특성이 [Register("PersonModel")] 클래스를 등록하고 클래스를 Objective-C노출합니다. 그런 다음 클래스에서 NSObject 상속해야 합니다(또는 상속 NSObject되는 하위 클래스). 이렇게 하면 클래스가 KVC 규격이 될 수 있는 몇 가지 기본 메서드가 추가됩니다. 다음으로, 특성은 [Export("Name")] 속성을 노출 Name 하고 나중에 KVC 및 KVO 기술을 통해 속성에 액세스하는 데 사용할 키 값을 정의합니다.

마지막으로 속성 값에 대한 Key-Value Observed 변경 내용을 적용하려면 접근자가 해당 값 WillChangeValue 의 변경 내용과 메서드 호출(특성과 DidChangeValue 동일한 키를 지정)을 Export 래핑해야 합니다. 예시:

set {
    WillChangeValue ("Name");
    _name = value;
    DidChangeValue ("Name");
}

이 단계는 Xcode의 인터페이스 작성기에서 데이터 바인딩에 매우 중요합니다(이 문서의 뒷부분에서 볼 수 있듯이).

자세한 내용은 Apple의 키-값 코딩 프로그래밍 가이드를 참조하세요.

키 및 키 경로

는 개체의 특정 속성을 식별하는 문자열입니다. 일반적으로 키는 키-값 코딩 규격 개체의 접근자 메서드 이름에 해당합니다. 키는 ASCII 인코딩을 사용해야 하며 일반적으로 소문자로 시작하며 공백을 포함하지 않을 수 있습니다. 따라서 위의 Name 예제를 고려할 때 클래스의 Name 속성 키 값이 PersonModel 됩니다. 공개하는 속성의 키와 이름은 동일할 필요는 없습니다. 그러나 대부분의 경우 동일합니다.

키 경로는 트래버스할 개체 속성의 계층 구조를 지정하는 데 사용되는 점 구분 키의 문자열입니다. 시퀀스에서 첫 번째 키의 속성은 수신기를 기준으로 하며 각 후속 키는 이전 속성의 값을 기준으로 평가됩니다. 마찬가지로 점 표기법을 사용하여 C# 클래스에서 개체 및 해당 속성을 트래버스합니다.

예를 들어 클래스를 PersonModel 확장하고 속성을 추가 Child 한 경우:

using System;
using Foundation;

namespace MacDatabinding
{
    [Register("PersonModel")]
    public class PersonModel : NSObject
    {
        private string _name = "";
        private PersonModel _child = new PersonModel();

        [Export("Name")]
        public string Name {
            get { return _name; }
            set {
                WillChangeValue ("Name");
                _name = value;
                DidChangeValue ("Name");
            }
        }

        [Export("Child")]
        public PersonModel Child {
            get { return _child; }
            set {
                WillChangeValue ("Child");
                _child = value;
                DidChangeValue ("Child");
            }
        }

        public PersonModel ()
        {
        }
    }
}

자식 이름 self.Child.Name 에 대한 키 경로는 키 값이 사용된 방식에 따라 간단하게 Child.Name 사용됩니다.

키-값 코딩을 사용하여 값 가져오기

이 메서드는 ValueForKey 요청을 수신하는 KVC 클래스의 인스턴스를 기준으로 지정된 키(a NSString)에 대한 값을 반환합니다. 예를 들어 위에 정의된 클래스의 PersonModel 인스턴스인 경우Person:

// Read value
var name = Person.ValueForKey (new NSString("Name"));

그러면 해당 인스턴스에 대한 속성 값이 Name 반환됩니다 PersonModel.

키-값 코딩을 사용하여 값 설정

마찬가지로 요청을 SetValueForKey 수신하는 KVC 클래스의 인스턴스를 기준으로 지정된 키(a NSString)에 대한 값을 설정합니다. 따라서 아래와 같이 클래스의 인스턴스를 PersonModel 사용합니다.

// Write value
Person.SetValueForKey(new NSString("Jane Doe"), new NSString("Name"));

속성 값을 Name .로 변경합니다 Jane Doe.

값 변경 관찰

KVO(키-값 관찰)를 사용하여 관찰자를 KVC 규격 클래스의 특정 키에 연결하고 해당 키의 값이 수정될 때마다 알림을 받을 수 있습니다(KVC 기술을 사용하거나 C# 코드에서 지정된 속성에 직접 액세스). 예시:

// Watch for the name value changing
Person.AddObserver ("Name", NSKeyValueObservingOptions.New, (sender) => {
    // Inform caller of selection change
    Console.WriteLine("New Name: {0}", Person.Name)
});

이제 클래스 인스턴스의 PersonPersonModel 속성이 수정될 때마다 Name 새 값이 콘솔에 기록됩니다.

자세한 내용은 Apple의 키-값 관찰 프로그래밍 가이드 소개를 참조하세요.

데이터 바인딩

다음 섹션에서는 C# 코드를 사용하여 값을 읽고 쓰는 대신 키-값 코딩 및 키-값 관찰 준수 클래스를 사용하여 Xcode의 Interface Builder에서 UI 요소에 데이터를 바인딩하는 방법을 보여 줍니다. 이러한 방식으로 데이터 모델을 표시하는 데 사용되는 뷰와 분리하여 Xamarin.Mac 애플리케이션을 보다 유연하고 쉽게 기본. 또한 작성해야 하는 코드의 양을 크게 줄입니다.

데이터 모델 정의

Interface Builder에서 UI 요소를 데이터 바인딩하려면 먼저 바인딩의 데이터 모델 역할을 하려면 Xamarin.Mac 애플리케이션에 정의된 KVC/KVO 규격 클래스가 있어야 합니다. 데이터 모델은 사용자 인터페이스에 표시될 모든 데이터를 제공하고 애플리케이션을 실행하는 동안 사용자가 UI에서 수행하는 데이터를 수정합니다.

예를 들어 직원 그룹을 관리하는 애플리케이션을 작성하는 경우 다음 클래스를 사용하여 데이터 모델을 정의할 수 있습니다.

using System;
using Foundation;
using AppKit;

namespace MacDatabinding
{
    [Register("PersonModel")]
    public class PersonModel : NSObject
    {
        #region Private Variables
        private string _name = "";
        private string _occupation = "";
        private bool _isManager = false;
        private NSMutableArray _people = new NSMutableArray();
        #endregion

        #region Computed Properties
        [Export("Name")]
        public string Name {
            get { return _name; }
            set {
                WillChangeValue ("Name");
                _name = value;
                DidChangeValue ("Name");
            }
        }

        [Export("Occupation")]
        public string Occupation {
            get { return _occupation; }
            set {
                WillChangeValue ("Occupation");
                _occupation = value;
                DidChangeValue ("Occupation");
            }
        }

        [Export("isManager")]
        public bool isManager {
            get { return _isManager; }
            set {
                WillChangeValue ("isManager");
                WillChangeValue ("Icon");
                _isManager = value;
                DidChangeValue ("isManager");
                DidChangeValue ("Icon");
            }
        }

        [Export("isEmployee")]
        public bool isEmployee {
            get { return (NumberOfEmployees == 0); }
        }

        [Export("Icon")]
        public NSImage Icon {
            get {
                if (isManager) {
                    return NSImage.ImageNamed ("group.png");
                } else {
                    return NSImage.ImageNamed ("user.png");
                }
            }
        }

        [Export("personModelArray")]
        public NSArray People {
            get { return _people; }
        }

        [Export("NumberOfEmployees")]
        public nint NumberOfEmployees {
            get { return (nint)_people.Count; }
        }
        #endregion

        #region Constructors
        public PersonModel ()
        {
        }

        public PersonModel (string name, string occupation)
        {
            // Initialize
            this.Name = name;
            this.Occupation = occupation;
        }

        public PersonModel (string name, string occupation, bool manager)
        {
            // Initialize
            this.Name = name;
            this.Occupation = occupation;
            this.isManager = manager;
        }
        #endregion

        #region Array Controller Methods
        [Export("addObject:")]
        public void AddPerson(PersonModel person) {
            WillChangeValue ("personModelArray");
            isManager = true;
            _people.Add (person);
            DidChangeValue ("personModelArray");
        }

        [Export("insertObject:inPersonModelArrayAtIndex:")]
        public void InsertPerson(PersonModel person, nint index) {
            WillChangeValue ("personModelArray");
            _people.Insert (person, index);
            DidChangeValue ("personModelArray");
        }

        [Export("removeObjectFromPersonModelArrayAtIndex:")]
        public void RemovePerson(nint index) {
            WillChangeValue ("personModelArray");
            _people.RemoveObject (index);
            DidChangeValue ("personModelArray");
        }

        [Export("setPersonModelArray:")]
        public void SetPeople(NSMutableArray array) {
            WillChangeValue ("personModelArray");
            _people = array;
            DidChangeValue ("personModelArray");
        }
        #endregion
    }
}

이 클래스의 대부분의 기능은 위의 키-값 코딩 섹션에 설명되어 있습니다. 그러나 이 클래스가 배열 컨트롤러 및 트리 컨트롤러의 데이터 모델 역할을 할 수 있도록 몇 가지 특정 요소와 추가된 사항을 살펴보겠습니다(나중에 데이터 바인딩 트리 뷰, 개요 뷰컬렉션 뷰에 사용 예정).

첫째, 직원이 관리자 NSArray 일 수 있기 때문에( 특히 NSMutableArray 값을 수정할 수 있도록) 관리되는 직원을 연결할 수 있도록 했습니다.

private NSMutableArray _people = new NSMutableArray();
...

[Export("personModelArray")]
public NSArray People {
    get { return _people; }
}

여기서 유의해야 할 두 가지 사항은 다음과 같습니다.

  1. 테이블 뷰, 개요 뷰 및 컬렉션과 같은 AppKit 컨트롤에 대한 Data Bind에 대한 요구 사항이므로 표준 C# 배열 또는 컬렉션 대신 사용 NSMutableArray 했습니다.
  2. 데이터 바인딩을 위해 직원 배열을 캐스팅 NSArray 하여 직원 배열을 노출하고 해당 C# 형식의 이름을 People{class_name}Array 형식으로 데이터 바인딩이 예상 personModelArray 하는 이름으로 변경했습니다(첫 번째 문자는 소문자로 설정됨).

다음으로 배열 컨트롤러 및 트리 컨트롤러를 지원하기 위해 몇 가지 특수 이름 public 메서드를 추가해야 합니다.

[Export("addObject:")]
public void AddPerson(PersonModel person) {
    WillChangeValue ("personModelArray");
    isManager = true;
    _people.Add (person);
    DidChangeValue ("personModelArray");
}

[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
    WillChangeValue ("personModelArray");
    _people.Insert (person, index);
    DidChangeValue ("personModelArray");
}

[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
    WillChangeValue ("personModelArray");
    _people.RemoveObject (index);
    DidChangeValue ("personModelArray");
}

[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
    WillChangeValue ("personModelArray");
    _people = array;
    DidChangeValue ("personModelArray");
}

이를 통해 컨트롤러는 표시되는 데이터를 요청하고 수정할 수 있습니다. 위에서 설명한 NSArray 것과 마찬가지로 이러한 명명 규칙에는 매우 구체적인 명명 규칙이 있습니다(일반적인 C# 명명 규칙과는 다릅니다).

  • addObject: - 배열에 개체를 추가합니다.
  • insertObject:in{class_name}ArrayAtIndex: - 클래스의 이름은 어디에 {class_name} 있습니다. 이 메서드는 지정된 인덱스의 배열에 개체를 삽입합니다.
  • removeObjectFrom{class_name}ArrayAtIndex: - 클래스의 이름은 어디에 {class_name} 있습니다. 이 메서드는 지정된 인덱스에서 배열의 개체를 제거합니다.
  • set{class_name}Array: - 클래스의 이름은 어디에 {class_name} 있습니다. 이 메서드를 사용하면 기존 캐리를 새 캐리로 바꿀 수 있습니다.

이러한 메서드 내에서 배열의 변경 내용과 DidChangeValue KVO 규정 준수를 WillChangeValue 위한 메시지를 래핑했습니다.

마지막으로 속성이 Icon 속성의 isManager 값을 사용하므로 isManager KVO 중 데이터 바인딩된 UI 요소에 Icon 속성 변경 내용이 반영되지 않을 수 있습니다.

[Export("Icon")]
public NSImage Icon {
    get {
        if (isManager) {
            return NSImage.ImageNamed ("group.png");
        } else {
            return NSImage.ImageNamed ("user.png");
        }
    }
}

이를 해결하기 위해 다음 코드를 사용합니다.

[Export("isManager")]
public bool isManager {
    get { return _isManager; }
    set {
        WillChangeValue ("isManager");
        WillChangeValue ("Icon");
        _isManager = value;
        DidChangeValue ("isManager");
        DidChangeValue ("Icon");
    }
}

접근자는 자체 키 외에도 키 isManagerWillChangeValue 대한 Icon 메시지와 DidChangeValue 메시지를 전송하므로 변경 내용도 볼 수 있습니다.

이 문서의 나머지 부분 전체에서 PersonModel 데이터 모델을 사용합니다.

단순 데이터 바인딩

데이터 모델이 정의되어 있으므로 Xcode의 인터페이스 작성기에서 데이터 바인딩의 간단한 예제를 살펴보겠습니다. 예를 들어 위에서 정의한 것을 편집하는 데 사용할 수 있는 양식을 Xamarin.Mac 애플리케이션에 PersonModel 추가해 보겠습니다. 몇 가지 텍스트 필드와 확인란을 추가하여 모델의 속성을 표시하고 편집합니다.

먼저 Interface Builder의 Main.storyboard 파일에 새 뷰 컨트롤러추가하고 해당 클래스SimpleViewController의 이름을 지정하겠습니다.

Adding a new view controller with a class named SimpleViewController.

다음으로, Mac용 Visual Studio 돌아가서 SimpleViewController.cs 파일(프로젝트에 자동으로 추가됨)을 편집하고 양식에 PersonModel 데이터를 바인딩할 인스턴스를 노출합니다. 다음 코드를 추가합니다.

private PersonModel _person = new PersonModel();
...

[Export("Person")]
public PersonModel Person {
    get {return _person; }
    set {
        WillChangeValue ("Person");
        _person = value;
        DidChangeValue ("Person");
    }
}

다음으로 보기가 로드되면 인스턴스를 PersonModel 만들어 이 코드로 채웁니다.

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

    // Set a default person
    var Craig = new PersonModel ("Craig Dunn", "Documentation Manager");
    Craig.AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
    Craig.AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
    Craig.AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
    Craig.AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
    Craig.AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
    Person = Craig;

}

이제 양식을 만들고 Main.storyboard 파일을 두 번 클릭하여 Interface Builder에서 편집할 수 있도록 열어야 합니다. 폼을 다음과 같이 레이아웃합니다.

Editing the storyboard in Xcode

키를 통해 Person 노출한 양식에 PersonModel 데이터를 바인딩하려면 다음을 수행합니다.

  1. 직원 이름 텍스트 필드를 선택하고 바인딩 검사전환합니다.

  2. 바인딩 상자를 선택하고 드롭다운에서 단순 보기 컨트롤러를 선택합니다. 다음으로 키 경로를 입력 self.Person.Name합니다.

    Entering self dot person dot name for the Key Path.

  3. 직업 텍스트 필드를 선택하고 상자에 바인딩을 검사 드롭다운에서 단순 보기 컨트롤러를 선택합니다. 다음으로 키 경로를 입력 self.Person.Occupation합니다.

    Entering self dot Person dot Occupation for the Key Path.

  4. Employee is a Manager 확인란을 선택하고 바인딩 상자를 검사 드롭다운에서 간단한 보기 컨트롤러를 선택합니다. 다음으로 키 경로를 입력 self.Person.isManager합니다.

    Entering self dot Person dot isManager for the Key Path.

  5. 직원 수 관리 텍스트 필드를 선택하고 바인딩 상자를 검사 드롭다운에서 단순 보기 컨트롤러를 선택합니다. 다음으로 키 경로를 입력 self.Person.NumberOfEmployees합니다.

    Entering self dot Person dot NumberOfEmployees for the Key Path.

  6. 직원이 관리자가 아닌 경우 직원 수 관리 레이블 및 텍스트 필드를 숨기려고 합니다.

  7. 직원 관리 레이블 수를 선택하고 숨겨진 턴다운을 확장하고 바인딩 상자를 검사 드롭다운에서 단순 보기 컨트롤러를 선택합니다. 다음으로 키 경로를 입력 self.Person.isManager합니다.

    Entering self dot Person dot isManager for the Key Path for non-managers.

  8. 값 변환기 드롭다운에서 선택합니다NSNegateBoolean.

    Selecting the NSNegateBoolean key transformation

  9. 그러면 데이터 바인딩에 속성 값 isManager 이 있으면 레이블이 숨겨지 false게 됩니다.

  10. 직원 관리 텍스트 필드 수에 대해 7단계와 8단계를 반복합니다.

  11. 변경 내용을 저장하고 Mac용 Visual Studio 돌아가 Xcode와 동기화합니다.

애플리케이션을 실행하면 속성의 값이 Person 양식에 자동으로 채워집니다.

Showing an auto-populated form

사용자가 폼을 변경하면 뷰 컨트롤러의 Person 속성에 다시 기록됩니다. 예를 들어 직원 선택 취소는 관리자 가 인스턴스를 PersonPersonModel 업데이트하고 직원 수 관리 레이블 및 텍스트 필드는 데이터 바인딩을 통해 자동으로 숨겨집니다.

Hiding the number of employees for non-managers

테이블 뷰 데이터 바인딩

이제 데이터 바인딩의 기본 사항을 살펴보았습니다. 이제 배열 컨트롤러 및 데이터 바인딩을 사용하여 테이블 뷰에 대한 보다 복잡한 데이터 바인딩 작업을 살펴보겠습니다. 테이블 뷰 작업에 대한 자세한 내용은 테이블 뷰 설명서를 참조하세요.

먼저 Interface Builder의 Main.storyboard 파일에 새 뷰 컨트롤러추가하고 해당 클래스TableViewController의 이름을 지정하겠습니다.

Adding a new view controller with a class named TableViewController.

다음으로, TableViewController.cs 파일(프로젝트에 자동으로 추가됨)을 편집하고 양식에 데이터를 바인딩할 클래스의 PersonModel 배열(NSArray)을 공개하겠습니다. 다음 코드를 추가합니다.

private NSMutableArray _people = new NSMutableArray();
...

[Export("personModelArray")]
public NSArray People {
    get { return _people; }
}
...

[Export("addObject:")]
public void AddPerson(PersonModel person) {
    WillChangeValue ("personModelArray");
    _people.Add (person);
    DidChangeValue ("personModelArray");
}

[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
    WillChangeValue ("personModelArray");
    _people.Insert (person, index);
    DidChangeValue ("personModelArray");
}

[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
    WillChangeValue ("personModelArray");
    _people.RemoveObject (index);
    DidChangeValue ("personModelArray");
}

[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
    WillChangeValue ("personModelArray");
    _people = array;
    DidChangeValue ("personModelArray");
}

데이터 모델 정의 섹션에서 위의 클래스에서 수행한 PersonModel 것처럼 배열 컨트롤러가 컬렉션PersonModels에서 데이터를 읽고 쓸 수 있도록 특별히 명명된 공용 메서드 4개를 공개했습니다.

다음으로 뷰가 로드되면 다음 코드로 배열을 채워야 합니다.

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

    // Build list of employees
    AddPerson (new PersonModel ("Craig Dunn", "Documentation Manager", true));
    AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
    AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
    AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
    AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
    AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
    AddPerson (new PersonModel ("Larry O'Brien", "API Documentation Manager", true));
    AddPerson (new PersonModel ("Mike Norman", "API Documenter"));

}

이제 테이블 뷰를 만들고 Main.storyboard 파일을 두 번 클릭하여 인터페이스 작성기에서 편집할 수 있도록 열어야 합니다. 다음과 같이 표시되도록 테이블을 레이아웃합니다.

Laying out a new table view

테이블에 바인딩된 데이터를 제공하기 위해 배열 컨트롤러 를 추가해야 합니다. 다음을 수행합니다.

  1. 라이브러리 검사기에서 인터페이스 편집기로 배열 컨트롤러끕니다.

    Selecting an Array Controller from the Library

  2. 인터페이스 계층 구조에서 배열 컨트롤러선택하고 특성 검사자로 전환합니다.

    Selecting the Attributes Inspector

  3. 수업 이름대해 입력 PersonModel 하고 더하기 단추를 클릭하고 세 개의 키를 추가합니다. 이름을 지정 Occupation 하고 isManager다음을 수행합니다.Name

    Adding the required key paths to the Object Controller.

  4. 그러면 배열 컨트롤러가 배열을 관리하는 내용과 표시해야 하는 속성(키를 통해)을 알 수 있습니다.

  5. 바인딩 검사자로 전환하고 콘텐츠 배열 아래에서 바인딩 및 테이블 뷰 컨트롤러 선택합니다. 다음의 모델 키 경로를 입력합니다 self.personModelArray.

    Entering a key path

  6. 이렇게 하면 배열 컨트롤러가 뷰 컨트롤러에 노출된 배열 PersonModels 과 연결됩니다.

이제 테이블 뷰를 배열 컨트롤러에 바인딩해야 합니다. 다음을 수행합니다.

  1. 테이블 뷰 및 바인딩 검사기를 선택합니다.

    Selecting the Table View and Binding Inspector.

  2. 테이블 내용 턴다운 아래에서 바인딩 대상 및 배열 컨트롤러 선택합니다. 컨트롤러 키 필드에 대해 입력 arrangedObjects 합니다.

    Defining the controller key

  3. Employee 열 아래에서 테이블 뷰 셀선택합니다. 값 턴다운 아래의 바인딩 검사기에서 바인딩 대상 및 표 셀 뷰 선택합니다. 모델 키 경로에 대해 입력 objectValue.Name 합니다.

    Setting the model key path for the Employee column.

  4. objectValue 는 배열 컨트롤러에서 관리되는 배열의 현재 PersonModel 값입니다.

  5. 직업 열에서 테이블 뷰 셀선택합니다. 값 턴다운 아래의 바인딩 검사기에서 바인딩 대상 및 표 셀 뷰 선택합니다. 모델 키 경로에 대해 입력 objectValue.Occupation 합니다.

    Setting the model key path for the Occupation column.

  6. 변경 내용을 저장하고 Mac용 Visual Studio 돌아가 Xcode와 동기화합니다.

애플리케이션을 실행하면 테이블이 다음 배열 PersonModels로 채워집니다.

Running the application, which populates the array of PersonModels.

개요 보기 데이터 바인딩

개요 뷰에 대한 데이터 바인딩은 테이블 뷰에 대한 바인딩과 매우 유사합니다. 주요 차이점은 배열 컨트롤러 대신 트리 컨트롤러사용하여 개요 보기에 바인딩된 데이터를 제공한다는 것입니다. 개요 보기 작업에 대한 자세한 내용은 개요 보기 설명서를 참조하세요.

먼저 Interface Builder의 Main.storyboard 파일에 새 뷰 컨트롤러추가하고 해당 클래스OutlineViewController의 이름을 지정하겠습니다.

Adding a new view controller with a class named OutlineViewController.

다음으로, OutlineViewController.cs 파일(프로젝트에 자동으로 추가됨)을 편집하고 양식에 데이터를 바인딩할 클래스의 PersonModel 배열(NSArray)을 공개하겠습니다. 다음 코드를 추가합니다.

private NSMutableArray _people = new NSMutableArray();
...

[Export("personModelArray")]
public NSArray People {
    get { return _people; }
}
...

[Export("addObject:")]
public void AddPerson(PersonModel person) {
    WillChangeValue ("personModelArray");
    _people.Add (person);
    DidChangeValue ("personModelArray");
}

[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
    WillChangeValue ("personModelArray");
    _people.Insert (person, index);
    DidChangeValue ("personModelArray");
}

[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
    WillChangeValue ("personModelArray");
    _people.RemoveObject (index);
    DidChangeValue ("personModelArray");
}

[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
    WillChangeValue ("personModelArray");
    _people = array;
    DidChangeValue ("personModelArray");
}

데이터 모델 정의 섹션에서 위의 클래스에서 수행한 PersonModel 것처럼 트리 컨트롤러가 컬렉션PersonModels에서 데이터를 읽고 쓸 수 있도록 특별히 명명된 네 가지 공용 메서드를 공개했습니다.

다음으로 뷰가 로드되면 다음 코드로 배열을 채워야 합니다.

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

    // Build list of employees
    var Craig = new PersonModel ("Craig Dunn", "Documentation Manager");
    Craig.AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
    Craig.AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
    Craig.AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
    Craig.AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
    Craig.AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
    AddPerson (Craig);

    var Larry = new PersonModel ("Larry O'Brien", "API Documentation Manager");
    Larry.AddPerson (new PersonModel ("Mike Norman", "API Documenter"));
    AddPerson (Larry);

}

이제 개요 보기를 만들고 Main.storyboard 파일을 두 번 클릭하여 인터페이스 작성기에서 편집할 수 있도록 열어야 합니다. 다음과 같이 표시되도록 테이블을 레이아웃합니다.

Creating the outline view

개요에 바인딩된 데이터를 제공하기 위해 트리 컨트롤러 를 추가해야 합니다. 다음을 수행합니다.

  1. 라이브러리 검사기에서 인터페이스 편집기로 트리 컨트롤러끕니다.

    Selecting a Tree Controller from the Library

  2. 인터페이스 계층 구조에서 트리 컨트롤러선택하고 특성 검사기로 전환합니다.

    Selecting the Attribute Inspector

  3. 수업 이름대해 입력 PersonModel 하고 더하기 단추를 클릭하고 세 개의 키를 추가합니다. 이름을 지정 Occupation 하고 isManager다음을 수행합니다.Name

    Adding the required key paths for PersonModel.

  4. 이렇게 하면 트리 컨트롤러가 배열을 관리하는 내용과 표시해야 하는 속성(키를 통해)을 알려줍니다.

  5. 트리 컨트롤러 섹션에서 자식에 대해 입력 personModelArray 하고, 개수 아래에 입력 NumberOfEmployees 하고, 리프 아래에 입력 isEmployee 합니다.

    Setting the Tree Controller key paths

  6. 이렇게 하면 트리 컨트롤러에서 자식 노드를 찾을 수 있는 위치, 자식 노드의 수 및 현재 노드에 자식 노드가 있는지를 알 수 있습니다.

  7. 바인딩 검사자로 전환하고 콘텐츠 배열 아래에서 바인딩 및 파일의 소유자 선택합니다. 다음의 모델 키 경로를 입력합니다 self.personModelArray.

    Editing the key path

  8. 이렇게 하면 트리 컨트롤러가 뷰 컨트롤러에 노출된 배열 PersonModels 과 연결됩니다.

이제 개요 뷰를 트리 컨트롤러에 바인딩해야 합니다. 다음을 수행합니다.

  1. 개요 보기를 선택하고 바인딩 검사기에서 다음을 선택합니다.

    Selecting the Outline View and Binding Inspector.

  2. 개요 보기 콘텐츠 턴다운 아래에서 바인딩 대상 및 트리 컨트롤러 선택합니다. 컨트롤러 키 필드에 대해 입력 arrangedObjects 합니다.

    Setting the controller key

  3. Employee 열 아래에서 테이블 뷰 셀선택합니다. 값 턴다운 아래의 바인딩 검사기에서 바인딩 대상 및 표 셀 뷰 선택합니다. 모델 키 경로에 대해 입력 objectValue.Name 합니다.

    Entering the model key path value objectValue dot Name.

  4. objectValue 는 트리 컨트롤러에서 관리되는 배열의 현재 PersonModel 값입니다.

  5. 직업 열에서 테이블 뷰 셀선택합니다. 값 턴다운 아래의 바인딩 검사기에서 바인딩 대상 및 표 셀 뷰 선택합니다. 모델 키 경로에 대해 입력 objectValue.Occupation 합니다.

    Entering the model key path value objectValue dot Occupation.

  6. 변경 내용을 저장하고 Mac용 Visual Studio 돌아가 Xcode와 동기화합니다.

애플리케이션을 실행하면 개요가 다음 배열 PersonModels로 채워집니다.

Running the application, which populates our array of PersonModels.

컬렉션 뷰 데이터 바인딩

컬렉션 뷰를 사용한 데이터 바인딩은 배열 컨트롤러가 컬렉션에 대한 데이터를 제공하는 데 사용되므로 테이블 뷰를 사용한 바인딩과 매우 비슷합니다. 컬렉션 보기에는 미리 설정된 표시 형식이 없으므로 사용자 상호 작용 피드백을 제공하고 사용자 선택을 추적하기 위해 더 많은 작업이 필요합니다.

Important

Xcode 7 및 macOS 10.11 이상의 문제로 인해 Storyboard(.storyboard) 파일 내에서 컬렉션 뷰를 사용할 수 없습니다. 따라서 .xib 파일을 계속 사용하여 Xamarin.Mac 앱에 대한 컬렉션 뷰를 정의해야 합니다. 자세한 내용은 컬렉션 뷰 설명서를 참조하세요.

네이티브 크래시 디버깅

데이터 바인딩에서 실수를 하면 관리되지 않는 코드에서 네이티브 크래시가 발생하고 Xamarin.Mac 애플리케이션이 오류와 함께 SIGABRT 완전히 실패할 수 있습니다.

Example of a native crash dialog box

일반적으로 데이터 바인딩 중에 네이티브 크래시가 발생하는 주요 원인은 다음과 같습니다.

  1. 데이터 모델은 .의 NSObject하위 클래스 또는 NSObject 상속되지 않습니다.
  2. 특성을 사용하는 [Export("key-name")] 데 Objective-C 속성을 노출하지 않았습니다.
  3. 접근자의 값 WillChangeValue 과 메서드 호출에 대한 변경 내용을 래핑하지 않았습니다(특성과 DidChangeValue 동일한 키를 Export 지정).
  4. 인터페이스 작성기에서 바인딩 검사에서 잘못되었거나 잘못 입력된 키가 있습니다.

크래시 디코딩

데이터 바인딩을 찾아서 수정하는 방법을 보여 줄 수 있도록 데이터 바인딩에서 네이티브 크래시가 발생해 보겠습니다. 인터페이스 작성기에서 컬렉션 뷰 예제에서 첫 번째 레이블의 바인딩을 다음으로 NameTitle변경해 보겠습니다.

Editing the binding key

변경 사항을 저장하고 Mac용 Visual Studio 다시 전환하여 Xcode와 동기화하고 애플리케이션을 실행해 보겠습니다. 컬렉션 뷰가 표시되면 키와 함께 속성을 노출하지 않으므로 애플리케이션이 일시적으로 오류(Mac용 Visual Studio 애플리케이션 출력에 표시됨)PersonModelSIGABRT 충돌Title합니다.

Example of a binding error

애플리케이션 출력에서 오류 맨 위로 스크롤하면 문제를 해결하는 키를 확인할 수 있습니다.

Finding the issue in the error log

이 줄은 바인딩하는 개체에 키가 Title 존재하지 않는다는 것을 나타냅니다. Interface Builder에서 바인딩을 Name 다시 변경하고 저장, 동기화, 다시 빌드 및 실행하면 애플리케이션이 문제 없이 예상대로 실행됩니다.

요약

이 문서에서는 Xamarin.Mac 애플리케이션에서 데이터 바인딩 및 키-값 코딩 작업을 자세히 살펴보았습니다. 먼저 KVC(키-값 코딩) 및 KVO(키-값 관찰)를 사용하여 C# 클래스 Objective-C 를 노출하는 방법을 살펴보았습니다. 다음으로, KVO 규격 클래스를 사용하고 Xcode의 인터페이스 작성기에서 UI 요소에 데이터 바인딩하는 방법을 보여 줍니다. 마지막으로 배열 컨트롤러 및 트리 컨트롤러를 사용하는 복잡한 데이터 바인딩을 보여 줍니다.