泥庭

2011年11月1日

非同期的に1度だけ実行する。

Filed under: .NET, WPF — タグ: , — yone64 @ 7:30 PM

最近WPF関連の記事はバグ報告がメインになってしまって、寂しい限りです。いやWPF好きなんですけど。

前置きはそれぐらいにしてと、WPFに限らずですがイベントドリブンで複数のイベントに連動させて一つ処理を行う場合、一度実行すればよい処理を複数回実行してしまうことが少なからずあります。
といっても、言葉で説明しても難しいのでSampleを貼っておきます。 コードで語る(?)
https://skydrive.live.com/embedicon.aspx/.Public/AsyncOnce.zip?cid=a46d108f79f66d2b&sc=documents

実行画面がこちら。
image

よくある(?)、足算アプリです。主な機能は2つ。
・左側もしくは右側のテキストボックスに数字を入れると、合計値が計算されます。
・Resetボタンをクリックすると両側のテキストが0に初期化されます。結果、合計値も0になります。

で、主なコードは以下の通りです。

/// <summary>
/// +の左の値
/// </summary>
public int Left
{
    get { return left; }
    set
    {
        if (left == value) return;
        left = value;

        // 計算
        Calc();
        OnPropertyChanged("Left");
    }
}

/// <summary>
/// +の右の値
/// </summary>
public int Right
{
    get { return right; }
    set
    {
        if (right == value) return;
        right = value;

        // 計算
        Calc();
        OnPropertyChanged("Right");
    }
}

/// <summary>
/// 計算結果
/// </summary>
public int Answer
{
    get { return answer; }
    set
    {
        if (answer == value) return;
        answer = value;
        OnPropertyChanged("Answer");
    }
}

/// <summary>
/// リセットコマンドで実行されるメソッド
/// </summary>
/// <param name="obj"></param>
public void Reset(object obj)
{
    // 両方の値をリセット
    this.Left = 0;
    this.Right = 0;
}

/// <summary>
/// 計算ロジック
/// </summary>
private void Calc()
{
    // 同期的に計算すると複数回実行されてしまう。
    Answer = left + right;
}

左右それぞれのテキストボックスに対応する値が更新された場合にCalc()メソッドが呼び出されます。そのため、Reset()メソッド実行時には左右それぞれのプロパティーが更新されるため、Calc()が2回呼び出されることになります。
今回は、単なる足算なので、2度計算してもたいしたことはないんですが、重たい処理だったりすると複数回実行することはためらわれます。
そんな場合は、計算ロジックを以下のように変更することによって、Dispatcherを利用し非同期的に1度だけの呼び出しを実現します。

/// <summary>
/// 非同期実行が予約されているかを判定するフラグ
/// </summary>
private bool queueFlag = false;

/// <summary>
/// 非同期に計算するロジック
/// </summary>
private void Calc()
{
    if (queueFlag) return;
    queueFlag = true;
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
        queueFlag = false;
        Answer = Left + Right;
    }), null);
}

これで、無駄な処理実行が防げます。

#で、
この方法は、ApplicationクラスをViewModel側で使用したり、フラグを利用して処理を制御したりと、個人的にはイマイチ好きになれません。
各種MVVMフレームワークとか非同期構文(TaskとかRx)とかを使用してもっと簡潔に書けたりしないもんですかね?

コメントする »

まだコメントはありません。

RSS feed for comments on this post. TrackBack URI

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

WordPress.com Blog.

%d人のブロガーが「いいね」をつけました。