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

###Gtk3アプリのComboBoxの表示の簡略化
<img width="350" alt="スクリーンショット 2020-03-29 12.53.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/ef7fc9f0-5ea9-c5e4-d985-26d47c2b1f71.png">
ComboBoxの表示の書き方の課題

CellRendererTextやSetCellDataFuncを毎回書くのが面倒
拡張クラスの中で実行させ、書く行数を減らす

gladeファイルにCombBoxを配置します。

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

namespace ComboBoxGtkApplication
{
    class MainWindow : Window
    {
        
        [UI] private ComboBox _comboBox1 = null;

        List<Song> songs;

        public MainWindow() : this(new Builder("MainWindow.glade"))
        {
        }
        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            builder.Autoconnect(this);
            _mkComboBox();
        }        
        void _mkComboBox()
        {
            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"));

            _comboBox1._mkCellRendererText("Artist");

            Gtk.ListStore musicListStore = new Gtk.ListStore (typeof (Song));
            foreach (Song song in songs) {
                musicListStore.AppendValues (song);
            }
            
            _comboBox1._mkBinding();

            _comboBox1.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を書く
ComboBoxクラスを拡張クラスにする
CellRendererTextExにCellRendererTextを親クラスにした派生クラス(継承)を作る
CellRendererTextExの中にbindingPropertyNameにモデルのプロパティを指定する

####ComboBoxクラスを拡張クラス

CellRendererTextを継承クラスにする

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

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

        return null;
    }
}

namespace Gtk {

        public partial class CellRendererTextEx : Gtk.CellRendererText {
         public string BindingPropertyName = "";
        }

        public static partial class ComboxExtensions {

        static public void _comboInit(ComboBox Combox1)
        {
            Combox1.Clear();
        }

        static public Gtk.CellRendererText _mkCellRendererText(this ComboBox Combox1 ,string baindingName) {

            _comboInit(ComboBox);
            Gtk.CellRendererTextEx CellRendererTextEx1 = new Gtk.CellRendererTextEx();
            CellRendererTextEx1.BindingPropertyName = baindingName;
            Combox1.PackStart(CellRendererTextEx1, true);
            return CellRendererTextEx1;
        }

        static public void _mkBinding(this ComboBox Combox1) {
            if(Combox1.Cells.Length > 0) {
                Combox1.SetCellDataFunc(Combox1.Cells[0], new Gtk.CellLayoutDataFunc(_RenderComboDo));
            }
        }

        static private void _RenderComboDo(
            Gtk.ICellLayout cell_layout,
            Gtk.CellRenderer cell,
            Gtk.ITreeModel model,
            Gtk.TreeIter iter) {

            if(!(cell is Gtk.CellRendererTextEx)) {
                return;
            }
            if((cell as Gtk.CellRendererTextEx).BindingPropertyName == "" ||
                (cell as Gtk.CellRendererTextEx).BindingPropertyName == null) {
                Console.WriteLine("PropertyNameがない");
                return;
            }

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

            object value = classObj._performSelector_Property((cell as Gtk.CellRendererTextEx).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.CellRendererPixbuf && (value is String)) {
                (cell as Gtk.CellRendererPixbuf).Pixbuf = new Pixbuf((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;
            }else if(value != null && cell is Gtk.CellRendererProgress && (value is int)) {
                (cell as Gtk.CellRendererProgress).Value = (int)value;
            }
        }
    }
}
```

[Ubuntu Gtkアプリ イベントハンドラー編](https://qiita.com/tana_/items/11a33d88c0eacf931d4e)に続く