Eto.FormsでTreeGridView
さて、Eto.Formsの紹介もかなり進んできました。あとは表とツリーあたりでしょうか。
しかし、表(GridView
)については公式サンプルで十分かと思います。
なので、表は割愛してツリーについて紹介します。
Eto.Formsには、ツリー型のコントロールが2つあります。
両者は使い方も比較的似ているので、今回はTreeGridView
を使ってみます。
ツリーと表(グリッド)をまとめたコントロールとなります。
TreeGridView Class
http://api.etoforms.picoe.ca/html/T_Eto_Forms_TreeGridView.htm
要注意事項
既にGitHubのプルリクエストにおいて、TreeGridViewの仕様追加が行われています。 このため、次バージョン(おそらく2.4)では、TreeGridViewは現状よりも使いやすくなるはずです。
TreeGridViewで表示するデータ
TreeGridView
は、DataStore
プロパティに設定した値を表示します。
DataStore
には通常、TreeGridItemCollection
型のインスタンスを設定します。
TreeGridItemCollection
は、APIを見れば分かるとおり、基本的にはObservableCollectionを継承しています。
コレクションの中身は、ITreeGridItem
インタフェースですが、通常は基本実体型であるTreeGridItem
を使います。
TreeGridItem
は、木構造を作るための再帰的なChildren
プロパティや、関連するParent
,Count
プロパティの他に、ツリーノードの状態を示すExpanded
プロパティなどがあります。
TreeGridItem
を作るサンプルコードを示します。
var item = new TreeGridItem( new object[] { "foo", true, 42 } );
これは1個のデータの中身を作っていますが、加えて、木構造を別途作る必要があります。
木構造を含んだデータを作成するメソッドのサンプルを示します。 単一アイテムの中身を作るメソッド(MakeItem)と、木構造を加えてアイテム群を返すメソッド(PrepareItems)の組み合わせです。
protected TreeGridItem MakeItem(string name, bool isFolder, int size) { return new TreeGridItem( new object[] { name, isFolder, size }); } protected IEnumerable<TreeGridItem> PrepareItems() { var drivec = MakeItem("C:", true, 32); yield return drivec; var windows = MakeItem("windows", true, 32); drivec.Children.Add(windows); var coredll = MakeItem("core.dll", false, 98451206); windows.Children.Add(coredll); var miscdll = MakeItem("misc.dll", false, 45461876); windows.Children.Add(miscdll); var drivez = MakeItem("Z:", true, 32); yield return drivez; var folderBin = MakeItem("bin", true, 32); drivez.Children.Add(folderBin); var exe = MakeItem("MyApp.exe", false, 1683204); folderBin.Children.Add(exe); var dll = MakeItem("MyLib.dll", false, 489560); folderBin.Children.Add(dll); var folderDat = MakeItem("data", true, 32); drivez.Children.Add(folderDat); var dat1 = MakeItem("config.dat", false, 4096); folderDat.Children.Add(dat1); var folderPatch = MakeItem("patches", true, 32); folderDat.Children.Add(folderPatch); var patch1 = MakeItem("patch1.dat", false, 464795); folderPatch.Children.Add(patch1); var patch2 = MakeItem("patch2.dat", false, 50129); folderPatch.Children.Add(patch2); var patch3 = MakeItem("patch3.dat", false, 2204568); folderPatch.Children.Add(patch3); var dat2 = MakeItem("characters.dat", false, 8715625); folderDat.Children.Add(dat2); }
これで、次のような木構造のデータができます。
- C:
- windows
- core.dll
- misc.dll
- windows
- Z:
- bin
- MyApp.exe
- MyLib.dll
- data
- config.dat
- patches
- patch1.dat
- patch2.dat
- patch3.dat
- characters.dat
- bin
TreeGridViewの設定
次に、TreeGridViewのインスタンスを生成、設定するサンプルを示します。
var MyList = new TreeGridItemCollection(); // MyListに中身を追加 var view = new TreeGridView { DataStore = MyList }; view.Columns.Add(new GridColumn { HeaderText = "Name", DataCell = new TextBoxCell(0) }); view.Columns.Add(new GridColumn { HeaderText = "Folder", DataCell = new CheckBoxCell(1) }); view.Columns.Add(new GridColumn { HeaderText = "Size", DataCell = new TextBoxCell(2) });
TreeGridViewはDataStore
プロパティにインスタンスを設定し、そのインスタンスによって表示を定めます。
直接表示データを追加・変更するメソッドはありません。
続きは表(グリッド)としての列定義です。 GridColumn.DataCellには、表示形式に応じた設定を行います。 TextBoxCellやCheckBoxCellのコンストラクタには、通常はintかstringを設定します。 intならDataStoreの各インスタンス(配列)のインデックスを示し、stringならインスタンス(オブジェクト)のプロパティ名を示します。
これでDataStoreの内容がDataGridViewで表示可能になりました。
サンプルコード全体
実際に動作するサンプルコード全体を示します。
using System.Collections.Generic; using Eto.Forms; using Eto.Drawing; namespace EtoSample_TreeGridView { public class MainForm : Form { TreeGridItemCollection MyList = new TreeGridItemCollection(); TreeGridView view; public MainForm() { Title = "My Eto Form"; ClientSize = new Size(300, 300); MyList.AddRange(PrepareItems()); view = new TreeGridView { DataStore = MyList }; view.Columns.Add(new GridColumn { HeaderText = "Name", DataCell = new TextBoxCell(0) }); view.Columns.Add(new GridColumn { HeaderText = "Folder", DataCell = new CheckBoxCell(1) }); view.Columns.Add(new GridColumn { HeaderText = "Size", DataCell = new TextBoxCell(2) }); var name = new TextBox { }; var add = new Button { Text = "Add" }; add.Click += (s, e) => { var node = view.SelectedItem as TreeGridItem; if (node == null) return; node.Children.Add(MakeItem(name.Text, false, 12345)); }; Content = new StackLayout { Padding = 10, Items = { new StackLayoutItem { Control = view, Expand = true, HorizontalAlignment = HorizontalAlignment.Stretch, }, new StackLayoutItem { Control = name, HorizontalAlignment = HorizontalAlignment.Stretch, }, add, } }; var quitCommand = new Command { MenuText = "Quit" }; quitCommand.Executed += (sender, e) => Application.Instance.Quit(); Menu = new MenuBar { Items = { new ButtonMenuItem { Text = "&File", Items = { } }, }, QuitItem = quitCommand, }; } #region TreeGridItem protected TreeGridItem MakeItem(string name, bool isFolder, int size) { return new TreeGridItem( new object[] { name, isFolder, size }); } protected IEnumerable<TreeGridItem> PrepareItems() { var drivec = MakeItem("C:", true, 32); yield return drivec; var windows = MakeItem("windows", true, 32); drivec.Children.Add(windows); var coredll = MakeItem("core.dll", false, 98451206); windows.Children.Add(coredll); var miscdll = MakeItem("misc.dll", false, 45461876); windows.Children.Add(miscdll); var drivez = MakeItem("Z:", true, 32); yield return drivez; var folderBin = MakeItem("bin", true, 32); drivez.Children.Add(folderBin); var exe = MakeItem("MyApp.exe", false, 1683204); folderBin.Children.Add(exe); var dll = MakeItem("MyLib.dll", false, 489560); folderBin.Children.Add(dll); var folderDat = MakeItem("data", true, 32); drivez.Children.Add(folderDat); var dat1 = MakeItem("config.dat", false, 4096); folderDat.Children.Add(dat1); var folderPatch = MakeItem("patches", true, 32); folderDat.Children.Add(folderPatch); var patch1 = MakeItem("patch1.dat", false, 464795); folderPatch.Children.Add(patch1); var patch2 = MakeItem("patch2.dat", false, 50129); folderPatch.Children.Add(patch2); var patch3 = MakeItem("patch3.dat", false, 2204568); folderPatch.Children.Add(patch3); var dat2 = MakeItem("characters.dat", false, 8715625); folderDat.Children.Add(dat2); } #endregion } }
起動すると、トップレベルの項目だけが表示されます。
閉じているツリーを開くこともできます。
TreeGridViewのフォルダ項目を選び、下のTextBoxに名前を入力して、下のAddボタンを押せば、TreeGridViewの選んだフォルダの下位に項目を追加できます。 ただし、Addボタンを押した直後は、表示は更新されません。
いったん親ノードを閉じて、再度開くと、追加した項目が表示されます。
追加直後にコードでExpanded
プロパティにfalse, trueと続けて設定してみましたが、自動表示更新はできませんでした。
まとめ
TreeGridViewについて、データの準備からコントロールの設定まで含めてサンプルを示しました。
TreeViewやTreeGridViewは使いやすいとはいえませんが、いざとなればこういった要素も使えますということで。