コントロールを明示的に更新する - WPFアプリケーションでのApplication.DoEvents の実装
WPFアプリケーションで、コントロールを明示的に更新するコード、Application.DoEventsを処理するコードを紹介します。
プログラム
UI
下図のUIを作成します。
コード
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WpfMessagePump
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 100; i++) {
System.Threading.Thread.Sleep(200);
textBox.Text += "Message:" + Convert.ToString(i) + "\r\n";
DoEvents();
}
}
private void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
var callback = new DispatcherOperationCallback(ExitFrames);
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, callback, frame);
Dispatcher.PushFrame(frame);
}
/*
//下記のコードでも可
private void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Func<object, object> cfunc = new Func<object, object>(procd);
var callback = new DispatcherOperationCallback(ExitFrames);
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, callback, frame);
Dispatcher.PushFrame(frame);
}
*/
private object ExitFrames(object obj)
{
((DispatcherFrame)obj).Continue = false;
return null;
}
/*
//または下記のコードでも可
private void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
var callback = new DispatcherOperationCallback(obj =>
{
((DispatcherFrame)obj).Continue = false;
return null;
});
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, callback, frame);
Dispatcher.PushFrame(frame);
}
*/
}
}
解説
DispatcherFrameオブジェクトが、アプリケーションで保留中の作業項目を処理するループオブジェクトです。
BeginInvokeメソッドで、与えたデリゲートを指定した優先順位で非同期に実行します。今回のコードの場合は、第一引数のDispatcherPriorityでBackgroundを与えているため、他のすべての非アイドル状態の操作が完了した後に操作が処理されます。処理されるデリゲートがDispatcherOperationCallbackオブジェクトになります。デリゲートに渡すオブジェクトがDispatcherFrame オブジェクトになります。
PushFrameメソッドで、PushFrame メソッドの引数に与えたDispatcherFrameオブジェクトのループに入ります。ループの反復ごとに、ExitFramesコールバック関数が実行されます。コールバック関数で、Continueプロパティの値を確認してループの継続を判定します。今回のコードの場合は常にfalseとなるため、ループは常に終了します。
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。
[Button]をクリックします。forループで時間のかかる処理が実行されますが、ループを処理するごとに、テキストボックスが更新されメッセージが表示されます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用