异步更新文本框

时间:2010-07-19 12:57:48

标签: c# .net

我正在创建一个电子邮件软件,可以向某些帐户发送电子邮件。我想在每次发送或发送新电子邮件时附加文本。但是文本框在发送所有电子邮件后显示我的报告。如果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);
    }
}

2 个答案:

答案 0 :(得分:5)

您实际想要做的是异步调用SendMail。在.NET 4.0中有几种方法可以做到这一点。我建议在Task循环中启动foreach对象,并为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 */ });

(语法可能稍微关闭;我没有编译它。)

答案 1 :(得分: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 );
        }
    }
}