「Xamarin.MacのNSTableViewでNSTableViewSourceを使う」の版間の差分

imported>Administrator
 
(4人の利用者による、間の17版が非表示)
1行目: 1行目:
==実装1==
== 実装2:View Base ==
Xamarin.MacにはNSTableViewSourceというNSTableViewを簡単に扱うための便利クラスがあるようだ。
[[Xamarin.Mac]]にはNSTableViewSourceというNSTableViewを簡単に扱うための便利クラスがあるようだ。


=== 列となるデータを準備する ===
まずはソースの元(テーブルの1行)となるクラスを用意する。
まずはソースの元(テーブルの1行)となるクラスを用意する。
<source lang="csharp">
<source lang="csharp">
11行目: 12行目:
</source>
</source>


=== 行となるデータソースを準備する ===
次にデータソースを用意する。
NSTableViewSourceクラスを継承してGetRowCountメソッドとGetViewForItemメソッドをオーバーライドすることで利用可能な状態となる。
Cellベースでは「GetObjectValue」のところがViewベースでは「GetViewForItem」となっている。
この例ではNSTableColumnクラスのIdentifierプロパティの値と、前述のStudyクラスの各プロパティ名の簡易自動マッピングを行っている。NSTableColumnクラスのIdentifierプロパティはInterface Builderで設定した。
また、別途IList<>インターフェースを実装しておくとLINQで操作できたり色々便利だった。無くてもよい。
<source lang="csharp">
        public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, nint row)
        {
            if (tableColumn.Identifier == null)
            {
                return null;
            }
            var item = _items[(int)row];
            var type = typeof(Study);
            var prop = type.GetProperty(tableColumn.Identifier, BindingFlags.Public | BindingFlags.Instance);
            if (prop == null)
            {// そんな名前のプロパティはない
                return null;
            }
            var val = prop.GetValue(item);
            if (val == null)
            {// 空っぽですわ
                return null;
            }
            switch (tableColumn.Identifier)
            {
                // CellベースではNSStringを返せばよかったが、ViewベースではNSView派生クラスを返さねばならない。
                // NSTableCellViewを返すとCellベースと同じような使用感となる。
                // カスタムセルを使用する場合は分岐するとよい。
                default:
                    var cellView = (NSTableCellView)tableView.MakeView(tableColumn.Identifier, this);
                    cellView.TextField.StringValue = val.ToString();
                    return cellView;
            }
        }
</source>
あとはCellベースと同じ。
== 実装1:Cell Base ==
[[Xamarin.Mac]]にはNSTableViewSourceというNSTableViewを簡単に扱うための便利クラスがあるようだ。
=== 列となるデータを準備する ===
まずはソースの元(テーブルの1行)となるクラスを用意する。
<source lang="csharp">
    public class Study
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }
</source>
=== 行となるデータソースを準備する ===
次にデータソースを用意する。
次にデータソースを用意する。
NSTableViewSourceクラスを継承してGetRowCountメソッドとGetObjectValueメソッドをオーバーライドすることで利用可能な状態となる。
NSTableViewSourceクラスを継承してGetRowCountメソッドとGetObjectValueメソッドをオーバーライドすることで利用可能な状態となる。
66行目: 129行目:
</source>
</source>


===使ってみる===
早速使ってみる。
早速使ってみる。
この例では
この例では
* Interface BuilderでMainWindow.xibファイルを開き、
* Interface BuilderでMainWindow.xibファイルを開き、
* NSTableViewを貼り付け、
* NSTableViewを貼り付け、
* Content Modeを「View Based」に設定し、
* Content Modeを「Cell Based」に設定し
* アウトレットは「_studyTableView」という名前にしておいた。
* アウトレットは「_studyTableView」という名前にしておいた。
構造
*NSTableView → この例では、_studyTableViewインスタンス
**NSTableColumn → この例では、これのIdentityと、Studyクラスのプロパティが一致したものに文字列を代入している
<source lang="csharp">
<source lang="csharp">
     public partial class MainWindowController : NSWindowController
     public partial class MainWindowController : NSWindowController
91行目: 161行目:
</source>
</source>


なんと、この状態で実行するとクリックしても行選択ができない。
なんと、この状態で実行するとテーブルの表示はされるが、クリックしても行選択ができない。


===行選択できるようにする===
これで良いのか知らんが以下で行選択が出来るようになった。
これで良いのか知らんが以下で行選択が出来るようになった。
<source lang="csharp">
<source lang="csharp">
106行目: 177行目:
             };
             };
         }
         }
</source>
===セルを編集できるようにする===
Interface Builderを開き、各カラムに「Editable」のチェックを入れる(最初から入っていると思う)。
設定対象はカラムでありセルじゃないよ(Identity Inspectorを開くとクラスがNSTableColumnとなってるやつ)。
多分こんな構造になっているはず
*NSTableView
**NSTableColumn ←これに「Editable」を設定する
***NSTextFieldCell
次にデータソースの以下のShouldEditTableColumnメソッドをオーバーライドし「true」を返すようにする。
前述のEditableのチェックをしておくことでこのメソッドが呼ばれるようになり、このメソッドでtrueを返すと実際に編集が可能な状態となるようだ。
<source lang="csharp">
    public class StudyTableViewSource : NSTableViewSource, IList<Study>
    {
        // 〜〜〜省略〜〜〜
        public override bool ShouldEditTableColumn(NSTableView tableView, NSTableColumn tableColumn, int row)
        {
            return true;
        }
    }
</source>
上記のShouldEditTableColumnメソッドのみでは編集はできるが、編集終了後に値が反映されず、編集前の状態に戻ってしまう。
そこで以下のSetObjectValueメソッドもオーバーライドする。
<source lang="csharp">
    public class StudyTableViewSource : NSTableViewSource, IList<Study>
    {
        // 〜〜〜省略〜〜〜
        public override void SetObjectValue(NSTableView tableView, NSObject theObject, NSTableColumn tableColumn, int row)
        {
            var item = Items[row];
            var type = typeof(Study);
            var prop = type.GetProperty(tableColumn.Identifier, BindingFlags.Public | BindingFlags.Instance);
            if (prop == null)
            {
                return;
            }
            prop.SetValue(item, theObject.ToString());
        }
    }
</source>
===セルのデザインを変える===
セルのデザインをいじくるにはデータソースの以下のメソッドをオーバーライドしてその中でいじくりまわす。
セルは初期状態でDrawsBackgroundプロパティがfalseに設定されており背景描画が無効化されているようなので、trueに設定したのちに各種操作をしている。
<source lang="csharp">
    public class StudyTableViewSource : NSTableViewSource, IList<Study>
    {
        // 〜〜〜省略〜〜〜
        public override void WillDisplayCell(NSTableView tableView, NSObject cell, NSTableColumn tableColumn, int row)
        {
            // 編集不可カラムの背景色を少し暗くしてみる
            if (tableColumn.Editable == false)
            {
                if (cell is NSTextFieldCell)
                {
                    var textfield = cell as NSTextFieldCell;
                    textfield.DrawsBackground = true;
                    textfield.BackgroundColor = NSColor.FromSrgb(0.9f, 0.9f, 0.9f, 1.0f);
                }
            }
        }
    }
</source>
</source>