2010-07-19 91 views
2

我正在創建向某些帳戶發送電子郵件的電子郵件軟件。每次發送新郵件或失敗時,我都要追加文本。但是,發送所有電子郵件後,文本框會顯示我的報告。如果toList非常大,如30多封電子郵件,則應用程序屏幕變白,在發送完所有電子郵件後,GUI將返回更新的OutPutTextBox。這裏是SendButton_Click方法異步更新文本框

foreach (String to in toList) 
      { 
       bool hasSent = SendMail(from, "password", to, SubjectTextBox.Text, BodyTextBox.Text); 

       if (hasSent) 
       { 
        OutPutTextBox.appendText("Sent to: " + to); 
       } 
       else 
       { 
        OutPutTextBox.appendText("Failed to: " + to); 
       } 
      } 

回答

5

你真正想要做的是調用SendMail異步裏面的代碼。有幾種方法可以在.NET 4.0中執行此操作。我建議您在foreach循環開始Task對象,計劃任務繼續爲每一個到UI線程:

string subject = SubjectTextBox.Text; 
string body = BodyTextBox.Text; 
var ui = TaskScheduler.FromCurrentSynchronizationContext(); 
List<Task> mails = new List<Task>(); 
foreach (string to in toList) 
{ 
    string target = to; 
    var t = Task.Factory.StartNew(() => SendMail(from, "password", target, subject, body)) 
     .ContinueWith(task => 
     { 
     if (task.Result) 
     { 
      OutPutTextBox.appendText("Sent to: " + to); 
     } 
     else 
     { 
      OutPutTextBox.appendText("Failed to: " + to); 
     } 
     }, ui); 
    mails.Add(t); 
} 

Task.ContinueWhenAll(mails.ToArray(), _ => { /* do something */ }); 

(語法可能會稍微偏離,我沒有編譯)。

+0

任何代碼片段? – coure2011 2010-07-19 13:05:28

+0

查看更新的答案。 – 2010-07-19 13:06:33

+0

這個解決方案的幾個問題。首先將所有電子郵件發送到相同的地址。第二如何知道所有任務完成? – coure2011 2010-07-19 17:33:30

3

這似乎是工作(假定一個WinForm應用程序):

namespace WindowsFormsApplication5 
{ 
    using System; 
    using System.Threading; 
    using System.Windows.Forms; 

    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     TextBox OutPutTextBox = new TextBox(); 

     /// <summary> 
     /// Represents Send Mail information. 
     /// </summary> 
     class MailInfo 
     { 
      public string from; 
      public string password; 
      public string to; 
      public string subject; 
      public string body; 
     } 

     void ProcessToDoList(string[] toList) 
     { 
      foreach (var to in toList) 
      { 
       MailInfo info = new MailInfo(); 
       info.from = "xx"; //TODO. 
       info.password = "yy"; //TODO. 
       info.to = "zz"; //TODO. 
       info.subject = "aa"; //TODO. 
       info.body = "bb"; //TODO. 
       ThreadPool.QueueUserWorkItem(this.SendMail, info); 
      } 
     } 

     /// <summary> 
     /// Send mail. 
     /// NOTE: this occurs on a separate, non-UI thread. 
     /// </summary> 
     /// <param name="o">Send mail information.</param> 
     void SendMail(object o) 
     { 
      MailInfo info = (MailInfo)o; 
      bool hasSent = false; 

      //TODO: put your SendMail implementation here. Set hasSent field. 
      // 

      // Now test result and append text. 
      // 

      if (hasSent) 
      { 
       this.AppendText("Sent to: " + info.to); 
      } 
      else 
      { 
       this.AppendText("Failed to: " + info.to); 
      } 
     } 

     /// <summary> 
     /// Appends the specified text to the TextBox control. 
     /// NOTE: this can be called from any thread. 
     /// </summary> 
     /// <param name="text">The text to append.</param> 
     void AppendText(string text) 
     { 
      if (this.InvokeRequired) 
      { 
       this.BeginInvoke((Action)delegate { this.AppendText(text); }); 
       return; 
      } 

      OutPutTextBox.AppendText(text); 
     } 
    } 
}