C#で常駐アプリを開発しています。
以前、常時監視処理を実装すると、右クリックのメニューが動かなくなる件でご相談しました。
その際は、コンポーネント内で右クリックメニューと常時監視処理(無限ループ)を実装していたため、
常時監視処理で止まってしまい、右クリックメニューの描画が出来ませんでした。
そのため、それぞれのスレッドを非同期処理にすることで解決出来ました。
【C#】【.net】常駐アプリ用のコンポーネントでツールに付与したイベントが動かない
その後、別スレッドで動作させる常時監視処理にエラーハンドリングの処理を導入しようと考えました。
エラーハンドリング自体は出来たのですが、以前と同じように右クリックメニューが動かなくなる状態になりました。
後述しますが、エラーハンドリングをするために実行しているスレッドが終わるまで待つ(Task.wait)処理を使っているからかもしれません。
別スレッドのエラーハンドリングを非同期で実施するにはどうしたらよいでしょうか?
概要
接続されたカードリーダーからカード情報を取得して、カード情報を処理したいと考えています。
常駐アプリとして実装して、右クリックメニューからアプリケーションを終了させられるようにします。
状況
右クリックメニュー(UI)と常時監視する処理は実装出来ました。
それぞれ別スレッドで稼働させることでどちらか片方が完了しない状態にはならなくなりました。
TaskのErrorを取得してハンドリングする事は出来ます。
公式の実装方法を参考に、Task.Wait
で終了、もしくはエラーが出るまで待たせるようにしました。
例外処理 (タスク並列ライブラリ)
ただし、別スレッドの処理が実行されている間は、右クリックのメニューのスレッドが止まってしまいます(ローディングのアイコンが表示しっぱなし)。
cs
1public NotifyIconWrapper() 2{ 3 InitializeComponent(); 4 5 // 終了メニューのイベントリスナーを設定 6 this.toolStripMenuItemExit.Click += new EventHandler(this.ToolStripMenuItemExitClick); 7 8 // 省略 9 10 this.nfcReaderTask.Start(); 11 try 12 { 13 // エラーが発生するまで待つ 14 this.nfcReaderTask.Wait(); 15 } 16 catch (AggregateException ae) 17 { 18 // 省略 19 } 20} 21
また、エラーが発生してタスクが止まると右クリックメニューが選択できるようになります。
ソース
App.xaml.cs
タスクトレイのアイコンについては、常時監視の処理も含めてNotifyIconWrapper
コンポーネントクラスを別途用意しました。
App.xaml.csでインスタンスを作成することでコンポーネントを有効にしています。
using Sample.Components; using System; using System.Windows; namespace Sample { /// <summary> /// App.xaml の相互作用ロジック /// </summary> public partial class App : Application { /// <summary> /// タスクトレイに表示するアイコン /// </summary> private NotifyIconWrapper notifyIcon = new NotifyIconWrapper(); }
NotifyIconWrapper コンポーネント
常駐アプリで行う、常時監視の処理を実装しています。
最初に記載しましたが、常時監視の処理をそのまま書くとUIの描画が止まるのでTask
を作り別スロットで処理しています。
cs
1using Sample.Classes.NfcReader; 2using System; 3using System.ComponentModel; 4using System.Diagnostics; 5using System.Threading.Tasks; 6using System.Windows; 7 8namespace Sample.Components 9{ 10 11 /// <summary> 12 /// タスクランナー用のアイコン 13 /// </summary> 14 public partial class NotifyIconWrapper : Component 15 { 16 17 private Task nfcReaderTask; 18 19 /// <summary> 20 /// コンストラクタ 21 /// </summary> 22 public NotifyIconWrapper() 23 { 24 InitializeComponent(); 25 26 // 終了メニューのイベントリスナーを設定 27 this.toolStripMenuItemExit.Click += new EventHandler(this.ToolStripMenuItemExitClick); 28 29 // カードリーダー用タスク追加 30 this.nfcReaderTask = new Task(() => 31 { 32 // カードリーダーのインスタン作成 33 NfcMain nfcMain = new NfcMain(); 34 while (true) 35 { 36 try 37 { 38 // ハンドルが初期状態以外であれば 39 if (nfcMain.context != IntPtr.Zero) continue; 40 // カード読み込み実行 41 nfcMain.start(); 42 } 43 catch 44 { 45 Debug.WriteLine("Task実行中にエラー発生"); 46 throw new AggregateException("カードリーダーに接続できませんでした。"); 47 } 48 } 49 }); 50 51 // 別スレッドでカードリーダーの監視処理を実行開始 52 this.nfcReaderTask.Start(); 53 try 54 { 55 // 元の処理が終わるか、エラーが発生するまで待つ 56 this.nfcReaderTask.Wait(); 57 } 58 catch (AggregateException ae) 59 { 60 // エラーが発生した場合はエラーメッセージを表示 61 MessageBox.Show( 62 ae.InnerException.Message, 63 "サンプルキャプション", 64 MessageBoxButton.OK, 65 MessageBoxImage.Hand 66 ); 67 68 foreach (var e in ae.InnerExceptions) 69 { 70 if (e is CustomException) 71 { 72 Console.WriteLine(e.Message); 73 } 74 else 75 { 76 throw; 77 } 78 } 79 } 80 } 81 82 /// <summary> 83 /// コンテキストメニュー、「終了」のイベント 84 /// </summary> 85 /// <param name="sender"></param> 86 /// <param name="e"></param> 87 private void ToolStripMenuItemExitClick(object sender, EventArgs e) 88 { 89 System.Windows.Application.Current.Shutdown(); 90 } 91 } 92 93 public class CustomException : Exception 94 { 95 public CustomException(String message) : base(message) 96 { 97 98 } 99 } 100}
回答2件
あなたの回答
tips
プレビュー