C# で数値のエディットボックスとスライダーを連動させる

C# で数値のエディットボックス(NumericUpDown)とスライダー(TrackBar)を連動させる方法を調べた記録です。
まずWIN32API でスライダーと呼んでいた(と記憶していた)ものがトラックバーという名前になっていたところで結構探してしまいました。さらにコモンコントロールの一覧に含まれていなかったりしたのもちょっと悩みました。

トラックバーのつまみの大きさはデフォルトで固定なのですが、プロパティのAutoSize をFalse にすると小さくすることが出来るようになります。

コントロールと内部のデータを連動させるにはデータバインディングという方法を使いますが、そのためにBindingSource というクラスを利用します。BindingSource はコントロールと内部データの間を仲介するものでデータの変更通知などのサービスを提供することにより開発が簡素化されます。詳しくはググってください。ここでは手っ取り早く使いたい時の参考となるよう実例を説明します。

「すべてのWindowsフォーム」に含まれるBindingSource をフォームにドロップすると、フォームデザイナの下の方にBindingSource が追加されます。それからBindingSource のプロパティのDataSource を設定します。

ここで設定しているData というのは独自に作成するクラスです。このクラスには変更通知のための仕組みを組み込みます。コントロールの変更を内部データに反映させるのは勝手にやってくれるのですが、内部データの変更をコントロールに反映させる処理は自分で記述しなければなりません。やり方はhttp://msdn.microsoft.com/ja-jp/library/ms184414.aspx に載っていますが一応説明を。

namespace CsTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            form1BindingSource.DataSource = new Data();
        }
    }
    /// <summary>
    /// NumericUpDown とTrackBar にバインドされるデータ
    /// </summary>
    public class Data : INotifyPropertyChanged
    {
        /// <summary>
        /// INotifyPropertyChanged から継承したイベントデリゲート
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// イベント通知
        /// </summary>
        /// <param name="info"></param>
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        int _value;
        public int Value
        {
            get { return _value; }
            set
            {
                if (value != _value)
                {
                    _value = value;
                    // このプロパティ名を渡してイベント通知
                    NotifyPropertyChanged("Value");
                }
            }
        }
    }
}

まず、Data クラスにはプロパティを持たせます。Data クラスは、INotifyPropertyChanged を継承し、PropertyChanged イベントを実装します。これは、データ変更を通知したいクラスに推奨されている方法です。上記コードのData クラスのValue というプロパティでは値が設定されたときにPropertyChanged イベントを発生させています。BindingSource クラスがこのイベントをうまいことコントロールの方に伝えてくれるようです。

Data クラスの準備が出来たら、コントロール側でデータバインディングを設定します。プロパティの(DataBindings)の詳細項目で、Value にバインドするデータソースを指定します。さらに、データソース更新モードとしてOnPropertyChanged を指定しておきます。この設定をNumericUpDown とTrackBar の双方で行います。最後に、フォームの初期化でInitializeComponent() を呼び出した後にBindingSource のDataSource にData のインスタンスを渡しておきます。


これで、数値エディットとスライダーがリアルタイムに連動します。データソース更新モードをOnValidation のままにしておくと、値がリアルタイムに反映されませんでした。ただ、このままだとスライダーのつまみを動かしている間中、プロパティのset が呼び出され続けてしまうのでちょっともったいないかも知れませんし、アンドゥのために古い値を記録しておこうと思ったときにちょっと面倒くさそうな気がします。