やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

UI連動のためにイベントハンドラの登録と解除をした

色編集アプリのUIとして、NumericUpDownとHScrollBarを使いました。 これらの連動をするとき、イベントハンドラの登録と解除をすることで無限ループを回避しました。

連動

NumericUpDownのUIを操作して値を変更したとき、HScrollBarのUIも変更したいのです。 また、逆も同じです。 f:id:ytyaru:20160611160153p:plain

WindowsFormアプリでは、UIの制御はイベントを用います。 該当のUIにそれぞれValueChangedイベントを登録しました。

ここに相手のUIの値を変更する処理を入れればいいだけです。

private void hScrollBar1_ValueChanged(object sender, EventArgs e)
{
    numericUpDown1.Value = this.hScrollBar1.Value;
}

private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
    hScrollBar1.Value = this.numericUpDown1.Value;
}

無限ループ

これだと無限ループしてしまいます。 回避するためには、フラグを立てて強引に回避するか、イベントを解除すればよさそうです。

イベントの登録と解除

  1. 相手のUIのイベントを解除
  2. 相手のUIの値を設定
  3. 相手のUIのイベントを追加

public partial class ColorEditorForm : Form
{
    System.EventHandler numHdl1;
    System.EventHandler scrlHdl1;

    public ColorEditorForm()
    {
        numHdl1 += new System.EventHandler(numericUpDown1_ValueChanged);
        scrlHdl1 += new System.EventHandler(hScrollBar1_ValueChanged);

        numericUpDown1.ValueChanged += numHdl1;
        hScrollBar1.ValueChanged += scrlHdl1;
    }

    private void numericUpDown1_ValueChanged(object sender, EventArgs e)
    {
        hScrollBar1.ValueChanged -= scrlHdl1;
        hScrollBar1.Value = numericUpDown1.Value;
        hScrollBar1.ValueChanged += scrlHdl1;
    }

    private void hScrollBar1_ValueChanged(object sender, EventArgs e)
    {
        numericUpDown1.ValueChanged -= numHdl1;
        numericUpDown1.Value = hScrollBar1.Value;
        numericUpDown1.ValueChanged += numHdl1;
    }
}

2つのUIを連携させるとき、このような面倒があるという話でした。

フリーズしない?

わざと無限ループさせてみようと思って実験しました。 しかし、無事に実行できてしまいました。

  1. イベントの削除と再設定の部分をコメントアウト
  2. ビルドして実行
  3. NumericUpDownとHScrollBarをマウスやキーボードで適当に操作する
  4. 無限ループになってフリーズするとか、実行時エラーとか起きない なぜ?

private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
    // hScrollBar1.ValueChanged -= scrlHdl1;
    hScrollBar1.Value = numericUpDown1.Value;
    // hScrollBar1.ValueChanged += scrlHdl1;
}

private void hScrollBar1_ValueChanged(object sender, EventArgs e)
{
    // numericUpDown1.ValueChanged -= numHdl1;
    numericUpDown1.Value = hScrollBar1.Value;
    // numericUpDown1.ValueChanged += numHdl1;
}

どこかで誰かが何かしら上手いことやってくれているのかしら。 怖いから元に戻しておこう。