LoginSignup
13
17

More than 5 years have passed since last update.

Dispatcher.BeginInvokeでラムダ式を用いる

Last updated at Posted at 2015-09-03

背景

Taskを始めとする別スレッド内でUI Threadに関わる処理を行っているとき、DispatcherObjectの BeginInvoke メソッドを多用します。たとえば、Task内でプログレスバーを更新する場合は、


var pb = new ProgressBar();
pb.Maximum = 5;
var window = new Window() { Content = pb };

// ダメな例:Task内でUIに関わる処理を行うと例外が発生します
Task.Factory.StartNew(()=>{
    pb.Value++;
});

// 正しい例:UI にかかわるオブジェクトはDipatcherObjectを継承しているため、Invokeします
Task.Factory.StartNew(() =>
{
    pb.Dispatcher.BeginInvoke((Action)(()=> pb.Value++));
}

と記述します。一行で書けるとはいえ、コードが長くなりがちです。

 ラムダ式は直接指定できない

InvokeやBeginInvokeの引数はDelegate型のため、Action (Delegateの中の一つ)にキャストせず、ラムダ式を直接指定すると、

// ダメな例:ラムダ式はキャストしなければならない
Task.Factory.StartNew(() =>
{
    // ラムダ式 はデリゲート型ではないため、型 'System.Delegate' に変換できません
    pb.Dispatcher.BeginInvoke(()=> pb.Value++);
}

というエラーが発生します。そのため、簡単な処理を記述するたびに pb.Dispatcher.BeginInvoke((Action)(()=> {})) と長いコードを書かなければなりませんでした。

拡張メソッド & Actionを引数にした関数

そこで、僕は以下の拡張メソッドを定義し、


// 拡張メソッドはinternalの方が汚染がなくていいと思います
internal static DispatcherOperation DisBegInv(this DispatcherObject dispatcherObject, Action action)
{
    return dispatcherObject.Dispatcher.BeginInvoke(action);
}

// 腕にやさしいコード
Task.Factory.StartNew(() =>
{
    pb.DisBegInv(()=> pb.Value++));
}

とラムダ式を直接用いるようにしています。これで皆さんの腕が少しでも疲れないようになれば幸いです。

13
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
17