Xamarin.Mac のアウトライン ビュー

この記事では、Xamarin.Mac アプリケーションでのアウトライン ビューの使用について説明しています。 Xcode および Interface Builder でのアウトライン ビューの作成と保守、およびプログラムによる操作について説明します。

Xamarin.Mac アプリケーションで C# と .NET を使用している場合、Objective-C や Xcode で開発者が使用しているのと同じアウトライン ビューにアクセスできます。 Xamarin.Mac は直接 Xcode と統合できるため、Xcode の Interface Builder を使用して、アウトライン ビューを作成および管理できます (または、必要に応じて、C# コードで直接作成することもできます)。

アウトライン ビューとは、ユーザーが階層データの行を展開または折りたたむことができるテーブルの一種です。 テーブル ビューと同様に、アウトライン ビューには一連の関連項目のデータが表示されます。行は個々の項目を表し、列はそれらの項目の属性を表します。 テーブル ビューとは異なり、アウトライン ビュー内の項目はフラット リストに含まれていないため、ハード ドライブ上のファイルやフォルダーなどの階層に編成されます。

アプリの実行例

この記事では、Xamarin.Mac アプリケーションでのアウトライン ビューの使用の基本について説明します。 まずは、Hello Mac に関する記事を参照することを強くお勧めします。特に、この記事で使用する主要な概念と手法について説明している「Xcode と Interface Builder の概要」セクションと「Outlet と Action」セクションを参照してください。

Xamarin.Mac Internals ドキュメントの「C# クラス/メソッドの Objective-C への公開」セクションも参照することをお勧めします。C# クラスを Objective-C オブジェクトと UI 要素に結び付けるために使われる Register および Export コマンドについて説明されています。

アウトライン ビューの概要

アウトライン ビューとは、ユーザーが階層データの行を展開または折りたたむことができるテーブルの一種です。 テーブル ビューと同様に、アウトライン ビューには一連の関連項目のデータが表示されます。行は個々の項目を表し、列はそれらの項目の属性を表します。 テーブル ビューとは異なり、アウトライン ビュー内の項目はフラット リストに含まれていないため、ハード ドライブ上のファイルやフォルダーなどの階層に編成されます。

アウトライン ビュー内の項目に他の項目が含まれている場合は、ユーザーが展開または折りたたむことができます。 展開可能な項目には、開閉用の三角形が表示されます。これは、項目が折りたたまれている場合は右を指し、項目が展開されている場合は下を指すます。 開閉用の三角形をクリックすると、項目が展開または折りたたまれます。

アウトライン ビュー (NSOutlineView) は、テーブル ビュー (NSTableView) のサブクラスであるため、その動作の多くを親クラスから継承します。 その結果、行または列の選択、列ヘッダーのドラッグによる列の再配置など、テーブル ビューでサポートされる多くの操作がアウトライン ビューでもサポートされます。 Xamarin.Mac アプリケーションは、これらの機能を制御でき、アウトライン ビューのパラメータ (コードまたは Interface Builder) を構成して、特定の操作を許可または禁止できます。

アウトライン ビューは、独自のデータを格納するのではなく、必要に応じて必要な行と列の両方を提供するデータ ソース (NSOutlineViewDataSource) に依存しています。

アウトライン ビューの動作をカスタマイズするには、アウトライン列の管理、機能選択の種類、行の選択と編集、カスタム追跡、個々の列と行のカスタム ビューをサポートするアウトライン ビュー デリゲート (NSOutlineViewDelegate) のサブクラスを指定します。

アウトライン ビューは、多くの動作と機能をテーブル ビューと共有しているため、この記事を読み進める前に、テーブル ビューのドキュメントを参照することをお勧めします。

Xcode でのアウトライン ビューの作成と管理

新しい Xamarin.Mac Cocoa アプリケーションを作成すると、既定で標準の空白のウィンドウが表示されます。 このウィンドウは、プロジェクトに自動的に含まれる .storyboard ファイルで定義されます。 Windows デザインを編集するには、ソリューション エクスプローラーで、Main.storyboard ファイルをダブルクリックします:

メイン ストーリーボードの選択

これにより、Xcode の Interface Builder でウィンドウ デザインが開きます:

Xcode での UI の編集

Library Inspector の検索ボックスに「outline」と入力すると、アウトライン ビュー コントロールを見つけやすくなります。

ライブラリからアウトライン ビューを選択

アウトライン ビューを Interface Editor の View Controller にドラッグし、View Controller のコンテンツ領域を塗りつぶし、それを Constraint Editor のウィンドウで縮小拡大する場所に設定します。

制約の編集

Interface Hierarchy でアウトライン ビューを選択すると、Attribute Inspector で次のプロパティを使用できます。

スクリーンショットは、属性インスペクターで使用できるプロパティを示しています。

  • Outline Column - 階層データが表示されるテーブル列。
  • Autosave Outline Column - true の場合、アウトライン列は自動的に保存され、次回のアプリケーションの実行時にも維持されます。
  • Indentation - 展開された項目の下の列をインデントする量。
  • Indentation Follows Cells - true の場合、インデント マークはセルに合わせてインデントされます。
  • Autosave Expanded Items - true の場合、項目の展開/折りたたみ状態は自動的に保存され、次回のアプリケーションの実行時にも維持されます。
  • Content Mode - ビュー (NSView) またはセル (NSCell) を使用して、行や列にデータを表示できます。 macOS 10.7 以降では、ビューを使用する必要があります。
  • Floats Group Rows - true の場合、テーブル ビューでは、グループ化されたセルが浮かんでいるように描画されます。
  • Columns - 表示する列の数を定義します。
  • Headers - true の場合、列にはヘッダーが含まれます。
  • Reordering - true の場合、ユーザーは、テーブル内の列をドラッグして並べ替えることができます。
  • Resizing - true の場合、ユーザーは、列のヘッダーをドラッグして列のサイズを変更できます。
  • Column Sizing - テーブルで列のサイズを自動的に設定する方法を制御します。
  • Highlight - セルを選択したときにテーブルで使用する強調表示の種類を制御します。
  • Alternate Rows - true の場合、他の行は別の背景色になります。
  • Horizontal Grid - セルの間で横に引く罫線の種類を選択します。
  • Vertical Grid - セルの間で縦に引く罫線の種類を選択します。
  • Grid Color - セルの罫線の色を設定します。
  • Background - セルの背景色を設定します。
  • Selection - ユーザーによるテーブル内のセルの選択方法を制御できます。
    • Multiple - true の場合、ユーザーは複数の行と列を選択できます。
    • Column - true の場合、ユーザーは列を選択できます。
    • Type Select - true の場合、ユーザーは文字を入力して行を選択できます。
    • Empty - true の場合、ユーザーは、行や列を選択する必要はなく、テーブルでは選択を行うことができません。
  • Autosave - 自動保存されるときのテーブル形式の名前。
  • Column Information - true の場合、列の順序と幅が自動保存されます。
  • Line Breaks - セルでの改行の処理方法を選択します。
  • Truncates Last Visible Line - true の場合、セルの境界内に収まらないデータは切り取られます。

重要

従来の Xamarin.Mac アプリケーションを管理している場合を除き、NSCell ベースのテーブル ビューではなく、NSView ベースのアウトライン ビューを使用する必要があります。 NSCell はレガシと見なされており、今後サポートされなくなる可能性があります。

Interface Hierarchy で Table Column を選択すると、Attribute Inspector で次のプロパティを使用できます。

スクリーンショットは、属性インスペクターで選択したテーブル列に使用できるプロパティを示しています。

  • Title - 列のタイトルを設定します。
  • Alignment - セル内のテキストの配置を設定します。
  • Title Font - セルのヘッダー テキストのフォントを選択します。
  • Sort Key - 列内のデータの並べ替えに使用するキーです。 ユーザーがこの列を並べ替えることができない場合は、空白のままにします。
  • Selector - 並べ替えの実行に使用する Action です。 ユーザーがこの列を並べ替えることができない場合は、空白のままにします。
  • Order - 列のデータの並べ替え順序です。
  • Resizing - 列のサイズ変更の種類を選択します。
  • Editable - true の場合、ユーザーはセル ベース テーブル内のセルを編集できます。
  • Hidden - true の場合、列は非表示になります。

また、ハンドルを左または右 (列の右側の垂直方向の中心) にドラッグすると列のサイズを変更できます。

テーブル ビューで各列を選択して、最初の列のタイトルとして Product を指定し、2 番目の列に Details を指定します。

Interface Hierarchy で Table Cell View (NSTableViewCell) を選択すると、Attribute Inspector で次のプロパティを使用できます。

スクリーンショットは、属性インスペクターで選択したテーブル セルに使用できるプロパティを示しています。

これらはすべて、標準ビューのプロパティです。 この列の行のサイズを変更することもできます。

Interface Hierarchy で Table Cell View (これは既定で NSTextField です) を選択すると、Attribute Inspector で次のプロパティを使用できます。

スクリーンショットは、属性インスペクターで選択したテーブル ビュー セルに使用できるプロパティを示していまs。

ここで設定する標準テキスト フィールドのプロパティはすべて用意されています。 既定では、標準のテキスト フィールドを使用して、列内のセルのデータが表示されます。

Interface Hierarchy で Table Cell View (NSTableFieldCell) を選択すると、Attribute Inspector で次のプロパティを使用できます。

スクリーンショットは、選択したテーブル ビュー セルで使用できるプロパティを示しています。

ここで最も重要な設定は、次のとおりです。

  • Layout - この列のセルのレイアウト方法を選択します。
  • Uses Single Line Mode - true の場合、セルは 1 行に制限されます。
  • First Runtime Layout Width - true の場合、アプリケーションの初回実行時に設定 (手動または自動的に) されているセルの幅を使用します。
  • Action - セルに対して Edit Action を送信するタイミングを制御します。
  • Behavior - セルが選択可能または編集可能かどうかを定義します。
  • Rich Text - true の場合、セルには書式設定およびスタイル設定されたテキストが表示されます。
  • Undo - true の場合、セルは元に戻す動作を担います。

Interface Hierarchy の Table Column の下部にある Table Cell View (NSTableFieldCell) を選択します。

テーブル セル ビューの選択

この操作を行うと、特定の列に対して作成されたすべてのセルの基本 Pattern として使用されている Table Cell View を編集できます。

Action と Outlet の追加

他の Cocoa UI コントロールと同様に、Action と Outlet を使用して (必要な機能に基づく)、アウトライン ビューとその列とセルを C# コードに公開する必要があります。

このプロセスは、公開するアウトライン ビュー要素でも同じです。

  1. Assistant Editor に切り替えて、ViewController.h ファイルが選択されていることを確認します。

    正しい .h ファイルの選択

  2. Interface Hierarchy からアウトライン ビューを選択し、Ctrl キーを押しながらクリックして ViewController.h ファイルにドラッグします。

  3. ProductOutline という名前のアウトライン ビューの Outlet を作成します。

    属性インスペクターの ProductOutline というアウトレットを示すスクリーンショット。

  4. ProductColumn と DetailsColumn という名前のテーブル列の Outlet を作成します。

    スクリーンショットは、属性インスペクターの DetailsColumn という名前のアウトレットを示しています。

  5. 変更内容を保存し、Visual Studio for Mac に戻って Xcode と同期します。

次に、アプリケーションの実行時にアウトラインのデータの一部を表示するコードを記述します。

アウトライン ビューの設定

次に、Interface Builder で設計されており、Outlet 経由で公開されているアウトライン ビューで、それを設定するための C# コードを作成する必要があります。

まずは、個々の行とサブ製品のグループの情報を保持するために、新しい Product クラスを作成しましょう。 ソリューション エクスプローラーでプロジェクトを右クリックし、[Add]>[New File...] を選択します。[General]>[Empty Class] を選択し、[Name] で「Product」と入力して、[New] ボタンをクリックします。

空のクラスの作成

Product.cs ファイルを次のようにします。

using System;
using Foundation;
using System.Collections.Generic;

namespace MacOutlines
{
    public class Product : NSObject
    {
        #region Public Variables
        public List<Product> Products = new List<Product>();
        #endregion

        #region Computed Properties
        public string Title { get; set;} = "";
        public string Description { get; set;} = "";
        public bool IsProductGroup {
            get { return (Products.Count > 0); }
        }
        #endregion

        #region Constructors
        public Product ()
        {
        }

        public Product (string title, string description)
        {
            this.Title = title;
            this.Description = description;
        }
        #endregion
    }
}

次に、NSOutlineDataSource のサブクラスを作成して、アウトラインのデータを要求どおりに指定する必要があります。 ソリューション エクスプローラーでプロジェクトを右クリックし、[Add]>[New File...] を選択します。[General]>[Empty Class] を選択し、[Name] に「ProductOutlineDataSource」と入力して、[New] ボタンをクリックします。

ProductTableDataSource.cs ファイルを編集して、次のようにします。

using System;
using AppKit;
using CoreGraphics;
using Foundation;
using System.Collections;
using System.Collections.Generic;

namespace MacOutlines
{
    public class ProductOutlineDataSource : NSOutlineViewDataSource
    {
        #region Public Variables
        public List<Product> Products = new List<Product>();
        #endregion

        #region Constructors
        public ProductOutlineDataSource ()
        {
        }
        #endregion

        #region Override Methods
        public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item)
        {
            if (item == null) {
                return Products.Count;
            } else {
                return ((Product)item).Products.Count;
            }

        }

        public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item)
        {
            if (item == null) {
                return Products [childIndex];
            } else {
                return ((Product)item).Products [childIndex];
            }

        }

        public override bool ItemExpandable (NSOutlineView outlineView, NSObject item)
        {
            if (item == null) {
                return Products [0].IsProductGroup;
            } else {
                return ((Product)item).IsProductGroup;
            }

        }
        #endregion
    }
}

このクラスでは、アウトライン ビューの項目用のストレージがあり、テーブル内の行数を返すように GetChildrenCount がオーバーライドされます。 GetChild は、(アウトライン ビューによって要求された) 特定の親または子項目を返し、ItemExpandable は、指定された項目を親または子として定義します。

最後に、アウトラインの動作を指定する NSOutlineDelegate のサブクラスを作成する必要があります。 ソリューション エクスプローラーでプロジェクトを右クリックし、[Add]>[New File...] を選択します。[General]>[Empty Class] を選択し、[Name] に「ProductOutlineDelegate」と入力して、[New] ボタンをクリックします。

ProductOutlineDelegate.cs ファイルを編集して、次のようにします。

using System;
using AppKit;
using CoreGraphics;
using Foundation;
using System.Collections;
using System.Collections.Generic;

namespace MacOutlines
{
    public class ProductOutlineDelegate : NSOutlineViewDelegate
    {
        #region Constants
        private const string CellIdentifier = "ProdCell";
        #endregion

        #region Private Variables
        private ProductOutlineDataSource DataSource;
        #endregion

        #region Constructors
        public ProductOutlineDelegate (ProductOutlineDataSource datasource)
        {
            this.DataSource = datasource;
        }
        #endregion

        #region Override Methods

        public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
            // This pattern allows you reuse existing views when they are no-longer in use.
            // If the returned view is null, you instance up a new view
            // If a non-null view is returned, you modify it enough to reflect the new data
            NSTextField view = (NSTextField)outlineView.MakeView (CellIdentifier, this);
            if (view == null) {
                view = new NSTextField ();
                view.Identifier = CellIdentifier;
                view.BackgroundColor = NSColor.Clear;
                view.Bordered = false;
                view.Selectable = false;
                view.Editable = false;
            }

            // Cast item
            var product = item as Product;

            // Setup view based on the column selected
            switch (tableColumn.Title) {
            case "Product":
                view.StringValue = product.Title;
                break;
            case "Details":
                view.StringValue = product.Description;
                break;
            }

            return view;
        }
        #endregion
    }
}

ProductOutlineDelegate のインスタンスを作成するときに、アウトラインにデータを提供する ProductOutlineDataSource のインスタンスも渡します。 GetView メソッドでは、ビュー (データ) を返して、give 列と行のセルを表示します。 可能であれば、新しいビューを作成する必要がない場合は、既存のビューを再利用してセルを表示します。

アウトラインを設定するには、MainWindow.cs ファイルを編集して、AwakeFromNib メソッドを次のようにします。

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

    // Create data source and populate
    var DataSource = new ProductOutlineDataSource ();

    var Vegetables = new Product ("Vegetables", "Greens and Other Produce");
    Vegetables.Products.Add (new Product ("Cabbage", "Brassica oleracea - Leaves, axillary buds, stems, flowerheads"));
    Vegetables.Products.Add (new Product ("Turnip", "Brassica rapa - Tubers, leaves"));
    Vegetables.Products.Add (new Product ("Radish", "Raphanus sativus - Roots, leaves, seed pods, seed oil, sprouting"));
    Vegetables.Products.Add (new Product ("Carrot", "Daucus carota - Root tubers"));
    DataSource.Products.Add (Vegetables);

    var Fruits = new Product ("Fruits", "Fruit is a part of a flowering plant that derives from specific tissues of the flower");
    Fruits.Products.Add (new Product ("Grape", "True Berry"));
    Fruits.Products.Add (new Product ("Cucumber", "Pepo"));
    Fruits.Products.Add (new Product ("Orange", "Hesperidium"));
    Fruits.Products.Add (new Product ("Blackberry", "Aggregate fruit"));
    DataSource.Products.Add (Fruits);

    var Meats = new Product ("Meats", "Lean Cuts");
    Meats.Products.Add (new Product ("Beef", "Cow"));
    Meats.Products.Add (new Product ("Pork", "Pig"));
    Meats.Products.Add (new Product ("Veal", "Young Cow"));
    DataSource.Products.Add (Meats);

    // Populate the outline
    ProductOutline.DataSource = DataSource;
    ProductOutline.Delegate = new ProductOutlineDelegate (DataSource);

}

アプリケーションを実行すると、次が表示されます。

折りたたまれたビュー

アウトライン ビューでノードを展開すると、次のようになります。

展開されたビュー

列による並べ替え

ユーザーが列ヘッダーをクリックしてテーブルを並べ替えられるようにしましょう。 まず、Main.storyboard ファイルをダブルクリックして、Interface Builder で編集用に開きます。 Product 列を選択し、[Sort Key] に「Title」、[Selector] に「compare:」と入力して、[Order] で Ascending を選択します。

並べ替えキーの順序の設定

変更内容を保存し、Visual Studio for Mac に戻って Xcode と同期します。

次に、ProductOutlineDataSource.cs ファイルを編集して、次のメソッドを追加します。

public void Sort(string key, bool ascending) {

    // Take action based on key
    switch (key) {
    case "Title":
        if (ascending) {
            Products.Sort ((x, y) => x.Title.CompareTo (y.Title));
        } else {
            Products.Sort ((x, y) => -1 * x.Title.CompareTo (y.Title));
        }
        break;
    }
}

public override void SortDescriptorsChanged (NSOutlineView outlineView, NSSortDescriptor[] oldDescriptors)
{
    // Sort the data
    Sort (oldDescriptors [0].Key, oldDescriptors [0].Ascending);
    outlineView.ReloadData ();
}

Sort メソッドを使用すると、特定の Product クラス フィールドに基づいて、データ ソース内のデータを昇順または降順で並べ替えることができます。 オーバーライドされた SortDescriptorsChanged メソッドが、列見出しをクリックするたびに呼び出されます。 Interface Builder で設定したキー値と、その列の並べ替え順序が渡されます。

アプリケーションを実行して列ヘッダーをクリックすると、行がその列ごとに並べ替えられます。

並べ替えられた出力の例

行の選択

ユーザーが 1 つの行を選択できるようにする場合は、Main.storyboard ファイルをダブルクリックして、Interface Builder で編集用に開きます。 Interface Hierarchy でアウトライン ビューを選択し、Attribute Inspector の [Multiple] チェックボックスのチェックを外します。

[複数] 設定を変更できる属性インスペクターを示すスクリーンショット。

変更内容を保存し、Visual Studio for Mac に戻って Xcode と同期します。

次に、ProductOutlineDelegate.cs ファイルを編集し、次のメソッドを追加します。

public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
{
    // Don't select product groups
    return !((Product)item).IsProductGroup;
}

これにより、ユーザーはアウトライン ビューのあらゆる行を選択できるようになります。 ユーザーに選択させたくない項目がある場合は、その項目の ShouldSelectItem に対して false を返します。ユーザーにどの項目も選択させたくない場合は、すべての項目に対して false を返します。

複数行の選択

ユーザーが複数の行を選択できるようにする場合は、Main.storyboard ファイルをダブルクリックして、Interface Builder で編集用に開きます。 Interface Hierarchy でアウトライン ビューを選択し、Attribute Inspector の [Multiple] チェックボックスをオンにします。

属性インスペクターを示すスクリーンショット。[複数] を選択できます。

変更内容を保存し、Visual Studio for Mac に戻って Xcode と同期します。

次に、ProductOutlineDelegate.cs ファイルを編集し、次のメソッドを追加します。

public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
{
    // Don't select product groups
    return !((Product)item).IsProductGroup;
}

これにより、ユーザーはアウトライン ビューのあらゆる行を選択できるようになります。 ユーザーに選択させたくない項目がある場合は、その項目の ShouldSelectRow に対して false を返します。ユーザーにどの項目も選択させたくない場合は、すべての項目に対して false を返します。

入力による行の選択

選択したアウトライン ビューでユーザーが文字を入力して、その文字が含まれている最初の行を選択できるようにする場合は、Main.storyboard ファイルをダブルクリックして、Interface Builder で編集用に開きます。 Interface Hierarchy でアウトライン ビューを選択し、Attribute Inspector の [Type Select] チェックボックスをオンにします。

行の種類の編集

変更内容を保存し、Visual Studio for Mac に戻って Xcode と同期します。

ここで、ProductOutlineDelegate.cs ファイルを編集し、次のメソッドを追加しましょう。

public override NSObject GetNextTypeSelectMatch (NSOutlineView outlineView, NSObject startItem, NSObject endItem, string searchString)
{
    foreach(Product product in DataSource.Products) {
        if (product.Title.Contains (searchString)) {
            return product;
        }
    }

    // Not found
    return null;
}

GetNextTypeSelectMatch メソッドでは、特定の searchString を受け取り、その Title にその文字列が含まれている最初の Product の項目を返します。

列の並べ替え

ユーザーがアウトライン ビューで並べ替える列をドラッグできるようにする場合は、Main.storyboard ファイルをダブルクリックして、Interface Builder で編集用に開きます。 Interface Hierarchy でアウトライン ビューを選択し、Attribute Inspector の [Reordering] チェックボックスをオンにします。

[並べ替え] を選択できる属性インスペクターを示すスクリーンショット。

[Autosave] プロパティに値を指定して Column Information フィールドにチェックを入れている場合、テーブルのレイアウトに加えた変更は自動保存され、次回アプリケーションが実行されたときに復元されます。

変更内容を保存し、Visual Studio for Mac に戻って Xcode と同期します。

ここで、ProductOutlineDelegate.cs ファイルを編集し、次のメソッドを追加しましょう。

public override bool ShouldReorder (NSOutlineView outlineView, nint columnIndex, nint newColumnIndex)
{
    return true;
}

ShouldReorder メソッドでは、newColumnIndex にドラッグして並べ替える必要がある列の true を返す必要があります。それ以外の場合は、false を返します。

アプリケーションを実行する場合は、列ヘッダーをドラッグして列を並べ替えることができます。

列の並べ替えの例

セルの編集

ユーザーが特定のセルの値を編集できるようにする場合は、ProductOutlineDelegate.cs ファイルを編集し、GetViewForItem メソッドを次のように変更します。

public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
    // Cast item
    var product = item as Product;

    // This pattern allows you reuse existing views when they are no-longer in use.
    // If the returned view is null, you instance up a new view
    // If a non-null view is returned, you modify it enough to reflect the new data
    NSTextField view = (NSTextField)outlineView.MakeView (tableColumn.Title, this);
    if (view == null) {
        view = new NSTextField ();
        view.Identifier = tableColumn.Title;
        view.BackgroundColor = NSColor.Clear;
        view.Bordered = false;
        view.Selectable = false;
        view.Editable = !product.IsProductGroup;
    }

    // Tag view
    view.Tag = outlineView.RowForItem (item);

    // Allow for edit
    view.EditingEnded += (sender, e) => {

        // Grab product
        var prod = outlineView.ItemAtRow(view.Tag) as Product;

        // Take action based on type
        switch(view.Identifier) {
        case "Product":
            prod.Title = view.StringValue;
            break;
        case "Details":
            prod.Description = view.StringValue;
            break;
        }
    };

    // Setup view based on the column selected
    switch (tableColumn.Title) {
    case "Product":
        view.StringValue = product.Title;
        break;
    case "Details":
        view.StringValue = product.Description;
        break;
    }

    return view;
}

アプリケーションを実行するとユーザーはテーブル ビューのセルを編集できます。

セルの編集の例

アウトライン ビューでの画像の使用

NSOutlineViewのセルの一部として画像を含めるには、アウトライン ビューの NSTableViewDelegate's GetView メソッドによってデータが返される方法を変更して、一般的なNSTextFieldの代わりにNSTableCellViewを使用する必要があります。 次に例を示します。

public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
    // Cast item
    var product = item as Product;

    // This pattern allows you reuse existing views when they are no-longer in use.
    // If the returned view is null, you instance up a new view
    // If a non-null view is returned, you modify it enough to reflect the new data
    NSTableCellView view = (NSTableCellView)outlineView.MakeView (tableColumn.Title, this);
    if (view == null) {
        view = new NSTableCellView ();
        if (tableColumn.Title == "Product") {
            view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
            view.AddSubview (view.ImageView);
            view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
        } else {
            view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
        }
        view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
        view.AddSubview (view.TextField);
        view.Identifier = tableColumn.Title;
        view.TextField.BackgroundColor = NSColor.Clear;
        view.TextField.Bordered = false;
        view.TextField.Selectable = false;
        view.TextField.Editable = !product.IsProductGroup;
    }

    // Tag view
    view.TextField.Tag = outlineView.RowForItem (item);

    // Allow for edit
    view.TextField.EditingEnded += (sender, e) => {

        // Grab product
        var prod = outlineView.ItemAtRow(view.Tag) as Product;

        // Take action based on type
        switch(view.Identifier) {
        case "Product":
            prod.Title = view.TextField.StringValue;
            break;
        case "Details":
            prod.Description = view.TextField.StringValue;
            break;
        }
    };

    // Setup view based on the column selected
    switch (tableColumn.Title) {
    case "Product":
        view.ImageView.Image = NSImage.ImageNamed (product.IsProductGroup ? "tags.png" : "tag.png");
        view.TextField.StringValue = product.Title;
        break;
    case "Details":
        view.TextField.StringValue = product.Description;
        break;
    }

    return view;
}

詳細については、画像の使用に関するドキュメントの アウトライン ビューでの画像の使用に関するセクションを参照してください。

データ バインディング アウトライン ビュー

Xamarin.Mac アプリケーションで Key-Value Coding と Data Binding の手法を使用すると、UI 要素を設定して操作するために記述および管理が必要なコードの量を大幅に減らすことができます。 また、バッキング データ (データ モデル) をフロントエンド ユーザー インターフェイス (Model-View-Controller) からさらに切り離すことで、アプリケーション デザインを管理しやすくなるという利点もあります。

キーと値のコーディング (KVC) は、インスタンス変数やアクセサー メソッド (get/set) を介してアクセスするのではなく、キー (特別にフォーマットされた文字列) を使用してプロパティを識別し、オブジェクトのプロパティに間接的にアクセスするためのメカニズムです。 Xamarin.Mac アプリケーションで Key-Value Coding に準拠したアクセサーを実装すると、Key-Value Observing (KVO)、Data Binding、Core Data、Cocoa バインディング、スクリプト機能など、他の macOS 機能にアクセスできます。

詳細については、Data Binding と Key-Value Coding に関するドキュメントの「アウトライン ビューのデータ バインディング」セクションを参照してください。

まとめ

この記事では、Xamarin.Mac アプリケーションでのアウトライン ビューの使用について詳しく説明しました。 アウトライン ビューのさまざまな種類と使用方法、Xcode の Interface Builder でアウトライン ビューを作成および管理する方法、C# コードでアウトライン ビューを操作する方法について確認しました。