我在C#win表单项目中阅读了UNSEEN电子邮件。有些时候有附加文件,下载有一些时间,所以我的项目的UI将在下载完成期间锁定。我使用ThreadPool来解决这个问题。
这是我的代码:
System.Threading.ThreadPool.QueueUserWorkItem((o) =>
{
for (int i = 0; i < lstEmailAddress.Count; i++)
{
Get(imap[i], lstEmailAddress[i].MailBox, out Emails[i]);
}
this.BeginInvoke(new Action(() =>
{
for (int i = 0; i < lstEmailAddress.Count; i++)
{
for (int j = 0; j < Emails[i].Count; j++)
{
Database.EmailRecieve_Insert(Emails[i][j]);
}
arrEmailUserControl[i].txtRecievedCount.Text = (Convert.ToInt32(arrEmailUserControl[i].txtRecievedCount.Text) + Emails[i].Count).ToString();
}
}));
});
这是我使用的Get方法:
private bool Get(Imap4Client imap, string[,] MailBox, out List<EmailStruct> Emails)
{
Emails = new List<EmailStruct>();
try
{
for (int i = 0; i < MailBox.GetLength(0); i++)
{
Mailbox inbox = imap.SelectMailbox(MailBox[i, 1]);
int[] ids = inbox.Search("UNSEEN");
if (ids.Length > 0)
{
ActiveUp.Net.Mail.Message msg = null;
for (var j = 0; j < ids.Length; j++)
{
msg = inbox.Fetch.MessageObject(ids[j]);
EmailStruct email = new EmailStruct();
email.SourceAddress = msg.From.Email;
email.Subject = msg.Subject;
email.Text = msg.BodyText.Text.ToString();
msg.Attachments.StoreToFolder(InternalConstant.AttachmentFolder);
email.MailBoxID = Convert.ToInt32(MailBox[i, 0]);
Emails.Add(email);
}
}
}
return true;
}
catch (Exception)
{
return false;
}
}
正如你在上面的代码中看到的那样,我完全在线程工作完成时有一个动作。实际上,我想告知完成线程工作。
但问题出在这里:大多数时候,当我想从收件箱中提取邮件时,我遇到了这个例外。
The Read method cannot be called when another read operation is pending
如果我删除了运行良好的线程池。 我使用threadPool只是为了忽略UI锁定,也知道线程已完成。
有什么更好的方法可以建议我吗? 谢谢你的帮助...
答案 0 :(得分:5)
你有什么更好的建议吗?
以下是我在WPF应用程序中以现代方式(不再是,如果你在2020年阅读)方法的方法:
private async void DoSomethingAsync()
{
try
{
DoanloadEmailsCommand.IsEnabled = false;
await Task.Run(() =>
{
// Do something here. For example, work with the database, download emails, etc.
Emails = DownloadEmails();
});
}
finally
{
DoanloadEmailsCommand.IsEnabled = true;
}
MessageBox.Show(string.Format("{0} emails have been downloaded.", Emails.Count));
}
传递给Task.Run()方法的lambda表达式中的代码将在另一个线程上执行
在创建和运行任务后,控制流将直接返回给调用者(在我们的情况下最终返回到UI消息循环,这将继续处理其他事件)。
任务完成后,会向应用程序的消息队列发送一些“唤醒”消息,当消息循环接收并处理此消息时,执行将在停止的位置继续执行。
在我们的例子中,当任务完成时,执行将在“await Task.Run()”调用()之后的下一行的主线程上继续执行。
因此命令对象将被启用(它将被绑定到一个按钮,让我们说“下载电子邮件”,这样按钮也会启用),并显示消息框,说明将下载多少封电子邮件。
正如您所看到的,代码非常干净且易于阅读和理解(一旦您了解了使用async / await关键字和Task类的基础知识)。
(也请阅读上面关于异常处理的评论)