Gtk3アプリのTreeViewの表示の簡略化

###Gtk3 TreeViewの表示の簡略化

<a href="https://www.mono-project.com/docs/gui/gtksharp/widgets/treeview-tutorial/">gtk-Sharpチュートリアル</a>に書かれているサンプルを簡略化します

####treeViewの表示の書き方の課題
CellRendererTextやSetCellDataFuncを毎回書くのが面倒
拡張クラスの中で実行させ、書く行数を減らす

<img width="500" alt="スクリーンショット 2020-03-29 12.53.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/825dc505-bfa3-0631-64eb-25a9e83bff95.png">

```csharp
using System;
using System.Collections.Generic;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

namespace treeView3GtkApplication
{
    class MainWindow : Window
    {

        [UI] private TreeView _treeView1 = null;

        List<Song> songs;

        public MainWindow() : this(new Builder("MainWindow.glade"))
        {
        }
        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            builder.Autoconnect(this);
            _mkTreeView();
        }        
        void _mkTreeView()
        {
            songs = new List<Song>();

            songs.Add (new Song ("Dancing DJs vs. Roxette", "Fading Like a Flower"));
            songs.Add (new Song ("Xaiver", "Give me the night"));
            songs.Add (new Song ("Daft Punk", "Technologic"));

            Gtk.TreeViewColumnEx artistColumn = new Gtk.TreeViewColumnEx ();
            artistColumn.Title = "Artist";
            //CellRenderの生成
            artistColumn._mkCellRendererText();
            //モデルのプロパティを指定する
            artistColumn.bindingPropertyName = "Artist";

            Gtk.TreeViewColumnEx songColumn = new Gtk.TreeViewColumnEx ();
            songColumn.Title = "Song Title";
            songColumn._mkCellRendererText();
            songColumn.bindingPropertyName = "Title";
            
            _treeView1.AppendColumn (artistColumn);
            _treeView1.AppendColumn (songColumn);

            Gtk.ListStore musicListStore = new Gtk.ListStore (typeof (Song));
            foreach (Song song in songs) {
                musicListStore.AppendValues (song);
            }
            
            _treeView1._mkBinding();
            
            _treeView1.Model = musicListStore;
        }
    }      
    public class Song
    {
        public Song (string artist, string title)
        {
            this.Artist = artist;
            this.Title = title;
        } 
        //リフレクションを有効にするためgetとsetを書く
        public string Artist { get; set; }
        public string Title { get; set; }
    }
}

```
#####解説
リフレクションを使うため、モデルにgeter seterを書く
treeViewを拡張クラスにする
treeViewColumnにExを追加した派生クラス(継承)をにする
bindingPropertyNameにモデルのプロパティを指定する

#####TreeView拡張クラス

```cs
using System;
using System.Reflection;
using Gtk;

namespace Gtk{

static class GtkExtensions
{
    public static void _mkBinding(this TreeView treeView)
    {
        foreach (TreeViewColumnEx column in treeView.Columns){
            
            if(!(column is TreeViewColumnEx)) {
                continue;
            }
            TreeViewColumnEx columnt1 = (column as TreeViewColumnEx);
             columnt1._mkBinding();
        }
    }
}

}
```

#####TreeViewColumnEx 派生クラス

```cs
using System;
using System.Reflection;
using Gtk;
using Gdk;

public static class objectExtensions {

    public static object _performSelector_Property(this object obj, string propertyName) {

            try
            {
                Type magicType = obj.GetType();
                PropertyInfo pi = magicType.GetProperty(propertyName,
                    BindingFlags.Public | BindingFlags.NonPublic |
                    BindingFlags.Instance | BindingFlags.Static);

                MethodInfo getMethod = pi.GetGetMethod();
                object result = getMethod.Invoke(obj, null);

                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
    }
}

namespace Gtk {

	public class TreeViewColumnEx : TreeViewColumn {

            public String bindingPropertyName = "";

            public CellRendererText _mkCellRendererText(string title = "",bool isPackStart = true) {

            if (title != "") {
                this.Title = title;
            }

            Gtk.CellRendererText CellRendererText1 = new Gtk.CellRendererText();
            this.PackStart(CellRendererText1, isPackStart);

            return CellRendererText1;
        }

        public CellRendererPixbuf _mkCellRendererPixbuf(string title = "",bool isPackStart = true) {
            if (title != "") {
                this.Title = title;
            }
            Gtk.CellRendererPixbuf CellRendererPixbuf1 = new Gtk.CellRendererPixbuf();
            this.PackStart(CellRendererPixbuf1, isPackStart);
            return CellRendererPixbuf1;
        }

        public CellRendererToggle _mkCellRendererToggle(string title = "",bool isPackStart = true) {
            if (title != "") {
                this.Title = title;
            }
            Gtk.CellRendererToggle CellRendererToggle1 = new Gtk.CellRendererToggle();
            this.PackStart(CellRendererToggle1, isPackStart);
            return CellRendererToggle1;
        }

        public CellRendererProgress _mkCellRendererProgress(string title = "",bool isPackStart = true) {

            if (title != "") {
                this.Title = title;
            }

            Gtk.CellRendererProgress CellRendererProgress1 = new Gtk.CellRendererProgress();
            this.PackStart(CellRendererProgress1, isPackStart);
            return CellRendererProgress1;

        }

        public void _mkBinding() {
            if(this.Cells.Length > 0) {
                this.SetCellDataFunc(this.Cells[0], new Gtk.TreeCellDataFunc(_RenderCellDo));
            }
        }

        private void _RenderCellDo(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {

            if(!(column is TreeViewColumnEx)) {
                return;
            }

            TreeViewColumnEx columnt1 = (column as TreeViewColumnEx);

            if(columnt1.bindingPropertyName == "" || columnt1.bindingPropertyName == null) {
                Console.WriteLine("PropertyNameがない");
                return;
            }

            object classObj = (object)model.GetValue(iter, 0);

            object value = classObj._performSelector_Property(columnt1.bindingPropertyName);

            if (value != null && cell is Gtk.CellRendererText && (value is String)) {
                (cell as Gtk.CellRendererText).Text = value as String;
            }else if (value != null && cell is Gtk.CellRendererText && (value is int)) {
                (cell as Gtk.CellRendererText).Text = ((int)value).ToString();
            }else if (value != null && cell is Gtk.CellRendererText && (value is long)) {
                (cell as Gtk.CellRendererText).Text = ((long)value).ToString();
            }else if(value != null && cell is Gtk.CellRendererText && (value is DateTime)) {
                (cell as Gtk.CellRendererText).Text = ((DateTime)value).ToString();
            } else if(value != null && cell is Gtk.CellRendererPixbuf && (value is String)) {
                (cell as Gtk.CellRendererPixbuf).Pixbuf = new Pixbuf(null, (value as String));
            } else if(value != null && cell is Gtk.CellRendererToggle && (value is String)) {
                (cell as Gtk.CellRendererToggle).Active = Convert.ToBoolean((value is String));
            } else if(value != null && cell is Gtk.CellRendererProgress && (value is String)) {
                (cell as Gtk.CellRendererProgress).Value = Convert.ToInt32((value is String));
            } else if(value != null && cell is Gtk.CellRendererPixbuf && (value is byte[])) {
                (cell as Gtk.CellRendererPixbuf).Pixbuf = new Pixbuf((byte[])value);
            } else if(value != null && cell is Gtk.CellRendererToggle && (value is Boolean)) {
                (cell as Gtk.CellRendererToggle).Active = (Boolean)value;
            } else if(value != null && cell is Gtk.CellRendererProgress && (value is int)) {
                (cell as Gtk.CellRendererProgress).Value = (int)value;
            }

        }
    }
}

```

https://qiita.com/iota_11/items/cf5ac9c11969ad8b8307

[Gtk3アプリのComboBoxの表示の簡略化](https://qiita.com/tana_/items/ec508adf3113ebd2a225)に続く