2007年12月22日土曜日

Control.Invoke / InvokeThrough について

先日 IP*Works! SSH V8 .NET Edition で .NET CF 用のちょっとしたコードを書いてみたら、あるイベント処理内でテキストボックスにデータを表示しようとしたところ例外が発生し "External application error: Control.Invoke must be used to interact with controls created on a separate thread." と表示されました。

別のイベント処理では問題なかったのでちょっと開発部隊に確認してみたところ、以下のような内容の返答がありました。

コンポーネントは効率向上等様々な理由から内部的にマルチスレッド処理されており、UI スレッド外のスレッド処理中に発生したイベントから UI スレッドのテキストボックス等にアクセスしようとするとこの例外が発生する。InvokeThrough を使用するか、delegate を使用して対処することになるだろう。

WinForm や WebForm 用のコンポーネントには InvokeThrough プロパティが用意されていますので、

sftp1.InvokeThrough = this;

のようにすることでイベント処理を delegate を使用せずに書けます。しかし .NET CF 用コンポーネントにはこのプロパティはありません。このような場合は以下のようなコードを用意することで対応します。

private delegate void putTextDelegate(String text);
private void putText(String text)
{
if (InvokeRequired)
{
// 別スレッドから呼ばれた時の処理
BeginInvoke(new putTextDelegate(putText), new object[] { text });
return;
}
// 同一スレッドから呼ばれた場合はそのまま出力
tbResponse.Text += text;
tbResponse.Select(tbResponse.Text.Length, 0);
tbResponse.ScrollToCaret();
}

これは SSH 以外の製品でもご利用可能です。以上、ご参考まで。

1 件のコメント:

nsj.blog さんのコメント...

.NET Edition の InvokeThrough に関しては、開発部隊でも導入が検討されているようです。これが導入されればユーザが delegate や BeginInvoke を使用することなくイベント処理をかけますので、期待したいところです。