DOBON.NETプログラミング道掲示板
(現在 過去ログ5 を表示中)
HOME
HELP
新規作成
新着記事
トピック表示
発言ランク
ファイル一覧
検索
過去ログ
[
最新記事及び返信フォームをトピックトップへ
]
[ トピック内全4記事(1-4 表示) ] <<
0
>>
■34817
/ inTopicNo.1)
DLL内のスレッドからイベントを発行すると、受信したフォームでラベルが更新できない
▼
■
□投稿者/ tomy
一般人(8回)-(2021/07/02(Fri) 14:54:59)
環境/言語:[Windows10/C#/VisualStudio2019/.NET Framework4.8]
分類:[.NET]
VisualStudio 2019のC#でDLL内でスレッドを作成し、スレッドからイベントを発行するようにしています。
具体的には、フォームからDLLのポーリング開始メソッドを呼び出す。
ポーリング開始メソッドはスレッドを作成して処理を終了(フォームに制御が戻る)
スレッドは外部機器に対して定期的に通信のポーリングを実行し、情報を読みだして内部の変数に保存します。
状態変化したら、状態変化イベントを発行します。
状態変化イベントはフォーム側で受け取って、ラベルにデータを表示する。
というようなものを作成していますが、下記のエラーが発生します。
---------------
例外がスローされました: 'System.InvalidOperationException' (System.Windows.Forms.dll の中)
有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'label3' がアクセスされました。
---------------
異なるスレッドからラベルにアクセスした為にエラーになっています。
フォーム側でラベルに表示するメソッドを書いて、
private void DispValue(decimal val)
{
label3.Text = val.ToString();
}
フォームのイベント処理で下記のようにInvokeで呼び出せばラベルを更新はできました。
this.Invoke(new Action<decimal>(this.DispValue), CommDll.Instance.Value);
しかし、スレッド自体はDLL内部にあるため、フォーム側でそれを意識するのは話が違うなあと思っております。
DLL内のスレッドからフォームと同じスレッドの処理(?)に情報を渡して、そこからイベント発行すればラベルの更新もできるのかな?と思うのですが、方法がわからず・・・。
何か良い手段はないでしょうか。
引用返信
削除キー/
編集
削除
■34818
/ inTopicNo.2)
Re[1]: DLL内のスレッドからイベントを発行すると、受信したフォームでラベルが更新できない
▲
▼
■
□投稿者/ 魔界の仮面弁士
大御所(1367回)-(2021/07/02(Fri) 15:59:03)
2021/07/02(Fri) 16:05:34 編集(投稿者)
■
No34817
に返信(tomyさんの記事)
> 異なるスレッドからラベルにアクセスした為にエラーになっています。
御存知の通り、「Label」や「Form」を操作できるのは、
その UI スレッドのみです。
同期的な呼び出しであれ非同期的な呼び出しであれ、
他のスレッドから直接操作してはいけません。
> しかし、スレッド自体はDLL内部にあるため、フォーム側でそれを意識するのは話が違うなあと思っております。
別スレッドで発生したイベントなのであれば、意識しないと駄目ですよ。
たとえばフォームに BackgroundWorker を貼って使った場合、
DoWork イベントは UI スレッドではなく、ワーカースレッドとなりますよね。
それと同じ話だと思います。
private void button1_Click(object sender, EventArgs e)
{
Debug.WriteLine($"Click - {this.InvokeRequired} - {Thread.CurrentThread.ManagedThreadId}");
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Debug.WriteLine($"ProgressChanged - {this.InvokeRequired} - {Thread.CurrentThread.ManagedThreadId}");
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
((BackgroundWorker)sender).ReportProgress(64);
Debug.WriteLine($"DoWork - {this.InvokeRequired} - {Thread.CurrentThread.ManagedThreadId}");
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.WriteLine($"RunWorkerCompleted - {this.InvokeRequired} - {Thread.CurrentThread.ManagedThreadId}");
}
イベントが UI スレッドであるかどうかが分からない場合には、
InvokeRequired プロパティで判断できます。
UI スレッドに作業を依頼するメソッドは、御存知 Invoke/BeginInvoke です。
> DLL内のスレッドからフォームと同じスレッドの処理(?)に情報を渡して、
https://stackoverflow.com/questions/1698889/
引用返信
削除キー/
編集
削除
■34819
/ inTopicNo.3)
Re[2]: DLL内のスレッドからイベントを発行すると、受信したフォームでラベルが更新できない
▲
▼
■
□投稿者/ tomy
一般人(9回)-(2021/07/02(Fri) 16:13:46)
■
No34818
に返信(魔界の仮面弁士さんの記事)
>>しかし、スレッド自体はDLL内部にあるため、フォーム側でそれを意識するのは話が違うなあと思っております。
>
> 別スレッドで発生したイベントなのであれば、意識しないと駄目ですよ。
うーん、なるほど、それではやはりイベントを受け取ってから、フォーム側で別スレッドかどうかを判断してやる必要があるのですね。
>> DLL内のスレッドからフォームと同じスレッドの処理(?)に情報を渡して、
>EventHandler<T> などの「戻り値が不要なデリゲート」ならばこんな感じ。
ありがとうございます。
もうちょっと調べてみます。
引用返信
削除キー/
編集
削除
■34820
/ inTopicNo.4)
Re[3]: DLL内のスレッドからイベントを発行すると、受信したフォームでラベルが更新できない
▲
▼
■
□投稿者/ tomy
一般人(10回)-(2021/07/02(Fri) 16:44:38)
ありがとうございました。
教えていただいた方法で無事にUIスレッドにイベントを発行できるようになりました。
解決
済
み!
引用返信
削除キー/
編集
削除
トピック内ページ移動 / <<
0
>>
このトピックに書きこむ
過去ログには書き込み不可
Mode/
通常管理
表示許可
Pass/
HOME
HELP
新規作成
新着記事
トピック表示
発言ランク
ファイル一覧
検索
過去ログ
-
Child Tree
-