SQLの窓

2013年11月01日


VS2012 WPF(C#) : 『TKMP.DLL を使用したイベントによる非同期メール受信処理を Task(await) を使用して順次処理のように記述する』テンプレート

SkyDrive へ移動


Framework 4.5 では、Task<TResult> クラスによって非同期処理の結果を取得してあたかも同期処理のような記述を行う事ができるようになりましたが、既存の非同期処理をそのように書き換える為に、TaskCompletionSource<TResult> クラスを使用します。

単純に考えると、Task を戻り値とするメソッド内は全て管理されていて、その中で登録されたイベントは全て管理下に置かれるようです。イベントが終了するまで、メソッドが終わる事無く、TaskCompletionSource<TResult> クラスの TrySetResult( SetResult との違いは良く解りません )で、値をセットした時にメソッドが終了するように見えます。

こうする事によって、大きなメリットの一つとして、UI スレッドにふつうに戻って来て処理を行えるところであり、当然ループ内の一部として自然に行を追加しながら非同期を実現する事ができました



MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net;
using System.Windows;
using System.Windows.Input;
using System.Collections.ObjectModel;
using TKMP.Net;
using System.IO;
using TKMP.Reader;
using System.Threading;
using System.Threading.Tasks;

namespace WPF_DataGrid_MailGet1 {
	public partial class MainWindow : Window {

		private MainViewModel mvm = new MainViewModel();
		private ImapClient client = null;

		// *********************************************
		// コンストラクタ
		// *********************************************
		public MainWindow() {
			InitializeComponent();

			this.dataGrid1.DataContext = mvm;
		}

		// 接続および、メールヘッダの取得
		private async void actButton_Click(object sender, RoutedEventArgs e) {

			mvm.mail_data.Clear();

			BasicImapLogon logon = new BasicImapLogon(this.userName.Text, this.password.Password);
			client = new ImapClient(logon, "imap.gmail.com", 993);
			client.AuthenticationProtocol = AuthenticationProtocols.SSL;

			if (!client.Connect()) {
				return;
			}

			// メールデータ一覧を格納するオブジェクト
			IMailData[] md = client.GetMailList();

			// データがありません
			if (md == null) {
				return;
			}

			// メールデータの数
			mailCount.Text = md.Length.ToString();

			// 読込み制限
			int maxCount = 20;
			int idx = 0;

			// 非同期で全て表示
			foreach (var data in md) {

				idx++;
				if (idx > maxCount) {
					break;
				}

				// Framework 4.5 : 値を返す非同期処理
				MailReader reader = await ReadBodyAnsync( data );

				// UI スレッドに戻って来ているので、特殊な処理は必要無い
				string from = "";
				string subject = "";
				string mdate = "";
				// ヘッダの一覧より、目的のヘッダを探す
				foreach (TKMP.Reader.Header.HeaderString headerdata in reader.HeaderCollection) {

					if (headerdata.Name == "From") {
						from = headerdata.Data;
					}
					if (headerdata.Name == "Subject") {
						subject = headerdata.Data;
					}
					if (headerdata.Name == "Date") {
						mdate = headerdata.Data;
					}

				}

				// 行追加
				mvm.mail_data.Add(new ItemViewModel() {
					from = from,
					subject = subject,
					mdate = mdate
				});

			}
			// ソース的には、順次処理なので全てのデータ処理後のクローズ
			client.Close();

		}

		// *********************************************
		// 戻り値を返す事のできる非同期処理 【開始】
		// *********************************************
		private TaskCompletionSource<MailReader> tcs = null;
		private Task<MailReader> ReadBodyAnsync(IMailData MailData) {

			// 戻り値用のクラス
			tcs = new TaskCompletionSource<MailReader>();

			// 個別にイベント登録
			MailData.BodyLoaded += new EventHandler(MailData_event);
			// 非同期処理開始
			MailData.ReadBodyAnsync();

			return tcs.Task;
		}

		// 本来のイベント処理
		private void MailData_event(object sender, EventArgs e) {

			IMailData MailData = (IMailData)sender;

			// イベント削除
			MailData.BodyLoaded -= new EventHandler(MailData_event);

			// 本文無し( 本文が必要な場合は、false で、reader.MainText )
			MailReader reader = new MailReader(MailData.DataStream, true);

			// ****************************
			// 戻り値用のクラスの戻り値をセット
			// ****************************
			tcs.TrySetResult(reader);

		}
		// *********************************************
		// 戻り値を返す事のできる非同期処理 【終了】
		// *********************************************


		// ダブルクリック
		private void dataGrid1_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
			Debug.WriteLine(dataGrid1.SelectedIndex);

		}


	}
}

参考ページ

c# - Best way to convert callback-based async method to awaitable task - Stack Overflow
c# - TaskCompletionSource : When to use SetResult() versus TrySetResult(), etc - Stack Overflow

関連するページ

▼ このページの処理の元となった、通常のイベント非同期処理
WPF(C#) : 『DataGrid に、TKMP.DLL を使用して非同期にメールヘッダを受信する』 テンプレート



【VS(C#)の最新記事】
posted by lightbox at 2013-11-01 20:29 | VS(C#) | このブログの読者になる | 更新情報をチェックする
バッチ処理

Microsoft Office
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
PHP正規表現チェッカー
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり