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

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

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

####前回からの改良点
TreeView上のCell内で値を編集できるようにした

<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">

```cs
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(_treeView1 , "",100);
            //モデルのプロパティを指定する
            artistColumn.bindingPropertyName = "Artist";

            Gtk.TreeViewColumnEx songColumn = new Gtk.TreeViewColumnEx ();
            songColumn.Title = "Song Title";
            songColumn._mkCellRendererText(_treeView1 , "",100);
            songColumn.bindingPropertyName = "Title";
    
            Gtk.ListStore musicListStore = new Gtk.ListStore (typeof (Song));
            foreach (Song song in songs) {
                musicListStore.AppendValues (song);
            }
            
            _treeView1.Model = musicListStore;

            _treeView1._mkBinding();            
  
        }
    }      
    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; }
    }
}

```

#####TreeView拡張クラス

```cs
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 派生クラス

```csharp
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);
            }
    }

    public static void _setSelector_Property(this object obj, string propertyName ,dynamic value) {
        try
            {
                Type t = obj.GetType();
                PropertyInfo pi = t.GetProperty(propertyName,
                    BindingFlags.Public  
                    | BindingFlags.NonPublic |
                    BindingFlags.Instance | BindingFlags.Static); 

                MethodInfo setMethod = pi.GetSetMethod();
                setMethod.Invoke(obj, new Object[1] { value });

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


namespace Gtk {
    public class TreeViewColumnEx : TreeViewColumn {

        public String bindingPropertyName = "";
        private Gtk.ListStore listStore1 = null;
        public CellRendererText _mkCellRendererText(TreeView treeView , string title = "" , int width = 0 , bool isEditable = true, bool isExpand = false, bool isPackStart = true) {
            if (title != "") {
                this.Title = title;
            }
            Gtk.CellRendererTextEx CellRendererText1 = new Gtk.CellRendererTextEx();
            if (width != 0) {
                this.MinWidth = width;
            }
            this.Expand = isExpand;
            this.Sizing = TreeViewColumnSizing.Autosize;
            this.PackStart(CellRendererText1, isPackStart);
            listStore1 = (ListStore)treeView.Model;
            if (isEditable)
            {
                CellRendererText1.Editable = true;
                CellRendererText1.Edited += delegate(object o, EditedArgs args)
                {
                  
                    Gtk.CellRendererTextEx o1 = (Gtk.CellRendererTextEx)o;
                    TreePath treePath1 = new TreePath (args.Path);
                    TreeIter iter;
                    if (listStore1 != null)
                    {
                        listStore1.GetIter (out iter, treePath1);
                        object testModel1 = (object)listStore1.GetValue(iter, 0);
                        _setModelData(testModel1, bindingPropertyName, args.NewText);
                    }
                };
            }

            treeView.AppendColumn(this);
            return CellRendererText1;
        }

        public CellRendererPixbuf _mkCellRendererPixbuf(TreeView treeView , string title = "" ,int width = 0 , bool isExpand = false ,bool isPackStart = true) {
         
            if (title != "") {
                this.Title = title;
            }
            Gtk.CellRendererPixbuf CellRendererPixbuf1 = new Gtk.CellRendererPixbuf();

            if (width != 0) {
                this.MinWidth = width;
            }
            this.Expand = isExpand;
            this.Sizing = TreeViewColumnSizing.Autosize;
            listStore1 = (ListStore)treeView.Model;
            this.PackStart(CellRendererPixbuf1, isPackStart);
            //this.AddAttribute (CellRendererPixbuf1, "pixbuf", 0);  
            treeView.AppendColumn(this);
            return CellRendererPixbuf1;
        }

        public CellRendererToggle _mkCellRendererToggle(TreeView treeView , string title = "",int width = 0 , bool isToggled = false ,bool isExpand = false ,bool isPackStart = true) {
            if (title != "") {
                this.Title = title;
            }
            Gtk.CellRendererToggle CellRendererToggle1 = new Gtk.CellRendererToggle();
            if (width != 0) {
                this.MinWidth = width;
            }
            this.Expand = isExpand;
            this.Sizing = TreeViewColumnSizing.Autosize;
            listStore1 = (ListStore)treeView.Model;
            if (isToggled)
            {
                CellRendererToggle1.Toggled += delegate(object o, ToggledArgs args)
                {
                    TreeIter iter;
                    if (listStore1.GetIterFromString(out iter, args.Path))
                    {
                        object object1 = (object)listStore1.GetValue(iter, 0);
                        object value = object1._performSelector_Property(bindingPropertyName);
                        String val = Convert.ToBoolean(value) == true ? "false" : "true";
                        _setModelData(object1, bindingPropertyName, val);
                    }
                };
            }

            this.PackStart(CellRendererToggle1, isPackStart);
            treeView.AppendColumn(this);
            return CellRendererToggle1;
        }

        public CellRendererProgress _mkCellRendererProgress(TreeView treeView , string title = "", int width = 0 , bool isExpand = false ,bool isPackStart = true) {
            if (title != "") {
                this.Title = title;
            }
            Gtk.CellRendererProgress CellRendererProgress1 = new Gtk.CellRendererProgress();
            if (width != 0) {
                this.MinWidth = width;
            }
            this.Expand = isExpand;
            this.Sizing = TreeViewColumnSizing.Autosize;
            listStore1 = (ListStore)treeView.Model;
            this.PackStart(CellRendererProgress1, isPackStart);
            treeView.AppendColumn(this);
            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 column1 = (column as TreeViewColumnEx);

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

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

            object value = modelData._performSelector_Property(column1.bindingPropertyName);

            _setCellData(value, cell);

        }
        private void _setCellData(object value ,Gtk.CellRenderer cell)
        {
            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;
            }
        }
        
        private void _setModelData(object modelData1 , String bindingPropertyName1 , String value )
        {

            Type t = modelData1._getKata(bindingPropertyName1);
            if (value != null && t.Equals(typeof(String))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToString(value));
            }else if (value != null && t.Equals(typeof(int))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToInt32(value));
            }else if (value != null && t.Equals( typeof(double))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToDouble(value));
            }else if (value != null && t.Equals(typeof(long))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToInt64(value));
            }else if (value != null && t.Equals( typeof(Boolean))) {
                modelData1._setSelector_Property(bindingPropertyName1,Convert.ToBoolean(value));
            }else if (value != null && t.Equals( typeof(bool))) {
                modelData1._setSelector_Property(bindingPropertyName1,Convert.ToBoolean(value));
            }else if (value != null && t.Equals( typeof(DateTime))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToDateTime(value));
            }else if (value != null && t.Equals( typeof(decimal))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToDecimal(value));
            }else if (value != null && t.Equals( typeof(char))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToChar(value));
            }else if (value != null && t.Equals( typeof(byte))) {
                modelData1._setSelector_Property(bindingPropertyName1, Convert.ToByte(value));
            }
        }
    }
}

```

[Gtk3アプリ RiderとT4テンプレートでHelloWorld](https://qiita.com/iota_11/items/b877aa430801968eba31)に続く