LoginSignup
2
7

More than 5 years have passed since last update.

データバインドをシンプルに

Last updated at Posted at 2018-10-16

DataBindings

概要

設定クラス等をコントロールにデータバインドする場合について、
値が変更されたときに、現在値と比較して違っている場合だけ OK ボタンをクリック可能にしたい場合がある。
これを実現するには、通常、下記の手順で実装となる。

  1. 設定クラスを作成
  2. 設定クラスに INotifyPropertyChanged インターフェイスを実装
  3. 編集用コントロールを配置
  4. コントロールに設定クラスのインスタンスをデータバインド

が、INotifyPropertyChanged インターフェイスをいちいち実装するのが面倒。。

INotifyPropertyChanged インターフェイスは必要か

例えば、TextBox にデータバインドする場合、DataSourceUpdateMode を OnPropertyChanged にしても、プロパティの値が変更されるタイミングは、TextChanged イベントの後になるため、このイベントで値を比較しても正しい結果は得られない。

解決案

TextChanged イベントが発生したらデータソースを更新する処理を手動で入れてやる!

static void BindData(this Control control, string propertyName, object dataSource, string dataMember, Action onChanged = null)
{
    //control.DataBindings.Clear();
    var binding = control.DataBindings.Add(propertyName, dataSource, dataMember, true, DataSourceUpdateMode.Never);
    if (binding != null)
    {
        // デフォルトイベント発生時に手動でデータソースを更新
        // (DataSourceUpdateMode.OnPropertyChanged だと、TextBox.TextChanged イベント後にデータソースが更新されるため)
        var defaultEvent = control.GetType().GetDefaultEvent();
        if (defaultEvent != null)
        {
            defaultEvent.AddEventHandler(control, new EventHandler((sender, e) =>
            {
                binding.WriteValue();
                onChanged?.Invoke();
            }));
        }
        else binding.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
    }
}

値変更時のイベントは、コントロールによって TextChanged だったり ValueChanged だったりするため、DefaultEventAttribute で指定されているイベントを取得する。

static EventInfo GetDefaultEvent(this Type type) => type.GetEvent(type.GetAttribute<DefaultEventAttribute>()?.Name ?? string.Empty);

static TAttribute GetAttribute<TAttribute>(this ICustomAttributeProvider element, bool inherit = true) where TAttribute : Attribute
{
    if (element == null) throw new ArgumentNullException(nameof(element));
    return element.GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault() as TAttribute;
}

各コントロールと Default 属性値

Control DefaultProperty DefaultEvent DefaultBindingProperty
TextBox Text TextChanged Text
CheckBox Checked CheckedChanged CheckState
RadioButton Checked CheckedChanged Checked
NumericUpDown Value ValueChanged Value
DateTimePicker Value ValueChanged Value
DataGridView Text CellContentClick -
2
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7