< 0 個と 1 個 | プロパティのデリゲート >

March 12, 2009

DoEvents

DoEvents っていうと、VB6 時代に使ったなーとか妙に懐かしいです。C とか C++ だとこんな実装をしてました。

void DoEvents (void)
{
    MSG msg;

    while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
}

要するに、メインのメッセージループの内側で、同期的にメッセージループを実行してメッセージキュー内にたまってるメッセージを捌かせるもので、主に同期処理の合間に GUI が固まらないようにする目的で使うやつです。Borland 系では Application->ProcessMessages () がおんなじ様な実装になってたんだと思います。多分。

WPF では DispatcherFrame クラスがメッセージループを表わすらしく、Dispatcher.PushFrame でそれを実行できます。たまってたメッセージを処理し終えた際にループを終了する必要がありますが、ディスパッチスレッドに優先度の低い処理としてメッセージループの終了を登録しておくことで実現します。

実際の実装方法は MSDN のあちこちにありますが、関数一個にした版をとりあえず上げときます。

/// <summary>
/// 現在メッセージ待ち行列の中にある全てのUIメッセージを処理します。
/// </summary>

public static void DoEvents ()
{
    // うちっかわの DispatcherFrame を作成
    var nestedFrame = new DispatcherFrame ();

    // DispatcherFrame (= 実行ループ) を終了させるコールバック
    DispatcherOperationCallback callback = (frame) => { ((DispatcherFrame) frame).Continue = false; return null;

    // 非同期で実行する
    // 優先度を Background にしているので、このコールバックは
    // ほかに処理するメッセージがなくなったら実行される
    var operation = Dispatcher.CurrentDispatcher.BeginInvoke (DispatcherPriority.Background, callback, nestedFra

    // うちっかわの実行ループを開始する
    Dispatcher.PushFrame (nestedFrame);

    // コールバックのオペレーションが完了していない場合、強制終了する
    if (operation.Status != DispatcherOperationStatus.Completed)
    {
        operation.Abort ();
    }
}

トラックバック

このエントリーにトラックバック:
http://frog.raindrop.jp/cgi-bin/mt/mt-tb.cgi/2344

コメント

コメントする

※ コメントスパム対策のため、コメント本文はおはよう、こんにちわ、こんばんわのいずれかより始めるようにしてください。

name:
email:

※ 必要ですが、表示しません。

url:
情報を保存する ?