[C#]コントロールの値をずばっとまるごと保存、展開する。

画面コントロールを作成している時、設定ファイルにコントロールの値を保存したり展開したりする場合があります。
一つのコントロールを追加した時、そのコントロールに対しての処理を書かないでなんとかならないか考えました。

標準の画面コントロールはSystem.Windows.Forms.Controlから派生していますが、それぞれコントロールが持つ値のプロパティは異なっています。
その異なっている部分をDynamicを使用して吸収し、ControlのTypeから判定して設定すべきプロパティに値を入れたりします。

コントロールに対し値を保持するデータクラス

    /// <summary>
    /// Control's property.
    /// </summary>
    public struct Property
    {
        public string Name { get; set; }
        public dynamic Value { get; set; }
    }

Dynamicを使用したアクセッサ

    /// <summary>
    /// GetValue() Value is get.
    /// SetValue() Value is set;
    /// </summary>
    public struct GetSet
    {
        public Func<dynamic, dynamic> GetValue;
        public Action<dynamic, dynamic> SetValue;
    }

Type毎にDynaimcのアクセッサのDictionaryを作成

取得したいコントロールに合わせてアクセッサの定義をします。ここに記述されていないコントロールは対象外になります。

        public static Dictionary<Type, GetSet> GetTypeList()
        {
            /// Register Dictionary.
            /// SetValue for control type.
            /// GetValue for control type.

            /// ex)
            /// dic.Add( typeof(Control type), 
            ///     new GetSet() { GetValue = (p) => (Control setter),
            ///                    SetValue = (p) => (Control getter) });
             
            var dic = new Dictionary<Type, GetSet>();

            dic.Add(typeof(TextBox), new GetSet() { GetValue = (p) => p.Text, SetValue = (p, v) => p.Text = v });
            dic.Add(typeof(RadioButton), new GetSet() { GetValue = (p) => p.Checked, SetValue = (p, v) => p.Checked = v });
            dic.Add(typeof(ComboBox), new GetSet() { GetValue = (p) => p.SelectedIndex, SetValue = (p, v) => p.SelectedIndex = (int)v });
            dic.Add(typeof(DateTimePicker), new GetSet() { GetValue = (p) => p.Value, SetValue = (p, v) => p.Value = DateTime.Parse(v) });
            dic.Add(typeof(CheckBox), new GetSet() { GetValue = (p) => p.Checked, SetValue = (p, v) => p.Checked = v });
            dic.Add(typeof(ListBox), new GetSet() { GetValue = (p) => p.SelectedIndex, SetValue = (p, v) => p.SelectedIndex = (int)v });
            dic.Add(typeof(TrackBar), new GetSet() { GetValue = (p) => p.Value, SetValue = (p, v) => p.Value = (int)v });
            dic.Add(typeof(VScrollBar), new GetSet() { GetValue = (p)=> p.Value, SetValue = (p, v) => p.Value = (int)v });

            return dic;
        }

このDictionaryを使用して、値を保存、展開する関数を作成します。

全てのコントロールの値を取得する

        /// <summary>
        /// Control value is get
        /// </summary>
        /// <param name="coll">Control collection</param>
        /// <returns>Control value</returns>
        public static Property[] Get(System.Windows.Forms.Control.ControlCollection coll)
        {
            var dic = GetTypeList();
            var ret = new List<Property>();

            /// Control scanning
            foreach(Control ctrl in coll)
            {
                /// Child control recurisve call
                if(ctrl.Controls.Count > 0 )
                {
                    var c_ctrl = Get(ctrl.Controls);

                    ret.AddRange(c_ctrl);
                }
                /// know control, value is get
                else
                {
                    if (dic.ContainsKey(ctrl.GetType()))
                    {
                        ret.Add(new Property() { Name = ctrl.Name, Value = dic[ctrl.GetType()].GetValue(ctrl) });
                    }
                }
            }

            return ret.ToArray();
        }

全てのコントロールの値を設定する

        /// <summary>
        /// Control value is set
        /// </summary>
        /// <param name="coll">Control collection</param>
        /// <param name="val">Configuration file of a value</param>
        public static void Set(System.Windows.Forms.Control.ControlCollection coll, Property[] val)
        {
            var dic = GetTypeList();
            var ret = new List<Property>();

            /// Control scanning 
            foreach (Control ctrl in coll)
            {
                /// Child control recursive call
                if (ctrl.Controls.Count > 0)
                {
                    Set(ctrl.Controls, val);
                }
                /// know control, value is set
                else
                {
                    if (dic.ContainsKey(ctrl.GetType()))
                    {
                        var currentValue = val.Where(n => ((n.Name.Any()) && (n.Name == ctrl.Name)));
                        if (currentValue.Any())
                        {
                            dic[ctrl.GetType()].SetValue(ctrl, currentValue.First().Value);
                        }
                    }
                }
            }
        }

Formに貼りつけた全てのコントロールに対し値を保存、展開する処理を記述します。
コントロールの値はProperty型のデータクラスを使用し、この値はJSON形式にして保存・展開することにします。

JSONについてはこちらのエントリーを参照してください。
コントロールの値をファイルに保存

        /// <summary>
        /// Save all control value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Save_Click(object sender, EventArgs e)
        {
            /// Get all control value by ControlProperty method.
            var ctrlList = ControlProperty.ControlProperty.Get(this.Controls);

            /// Write all control value use JSON file.
            System.IO.File.WriteAllText("ctrl.json", DynamicJson.Serialize(ctrlList.ToArray()));
        }

ファイルからコントロールの値を設定

        /// <summary>
        /// Set all Contorl value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Load_Click(object sender, EventArgs e)
        {
            /// Read all control value by JSON file.
            ControlProperty.Property[] val = DynamicJson.Parse( System.IO.File.ReadAllText("ctrl.json"));

            /// Set all control value by ControProperty method.
            ControlProperty.ControlProperty.Set(this.Controls, val);
        }

これでコントロールを追加しても何もしなくても値が保存・展開されます。


実行画面

<追記>
このソースを公開致します。
https://github.com/motoki-kimura/ControlProperty

DynamicJsonを参照に加えることで、コンパイルが成功します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


This blog is kept spam free by WP-SpamFree.