尝试使用smtp发送电子邮件时程序冻结

时间:2017-09-16 19:13:00

标签: c# winforms email smtp freeze

我目前的程序存在问题,我正在尝试学习如何使用smtp发送电子邮件,我写了这段代码来执行此操作。当我尝试点击button1时程序冻结,没有任何反应。 PS:显然我在发布之前将电子邮件和密码更改为“email”和“password”。 PS2:我用葡萄牙语编写我的代码,所以你可能不理解的任何东西都只考虑变量或“x”。

以下代码:

// *** Assign this to a variable (self)
var self = this;

that.window = $("#PenguinPopup");
that.window.kendoWindow({
  width: "60%",
  title: false,
  visible: false,
  resizable: false,
  actions: [],
  draggable: false,
  modal: true,
  open: function() {
    $("html, body").css("overflow", "hidden");
    that.isVisible = true;
    $('.kPopUpTitle').html(values.title);

// *** use the self variable instead of this
    self.sky.tigerStart();

4 个答案:

答案 0 :(得分:0)

您正在GUI环境中运行。事件必须尽快返回,否则GUI将“锁定”。特别是磁盘和网络活动很容易长时间运行。您必须应用某种形式的多任务(并将长时间运行的操作移动到该备用任务中)以避免GUI锁定。

作为初学者,我建议使用BackgroundWorker进行多任务处理。异步...等待更先进。

编辑:这是我的WinForms + BackgroundWorker示例代码。它应该有助于您开始正确使用它。

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
	if (!bgwPrim.IsBusy)
	{
		//Prepare ProgressBar and Textbox
		int temp = (int)nudPrim.Value;
		pgbPrim.Maximum = temp;
		tbPrim.Text = "";

		//Start processing
		bgwPrim.RunWorkerAsync(temp);
	}
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
	if (bgwPrim.IsBusy)
	{
		bgwPrim.CancelAsync();
	}
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
	int highestToCheck = (int)e.Argument;
	//Get a reference to the BackgroundWorker running this code
	//for Progress Updates and Cancelation checking
	BackgroundWorker thisWorker = (BackgroundWorker)sender;

	//Create the list that stores the results and is returned by DoWork
	List<int> Primes = new List<int>();
	

	//Check all uneven numbers between 1 and whatever the user choose as upper limit
	for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
	{
		//Report progress
		thisWorker.ReportProgress(PrimeCandidate);
		bool isNoPrime = false;

		//Check if the Cancelation was requested during the last loop
		if (thisWorker.CancellationPending)
		{
			//Tell the Backgroundworker you are canceling and exit the for-loop
			e.Cancel = true;
			break;
		}

		//Determin if this is a Prime Number
		for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
		{
			if (PrimeCandidate % j == 0)
				isNoPrime = true;
		}

		if (!isNoPrime)
			Primes.Add(PrimeCandidate);
	}

	//Tell the progress bar you are finished
	thisWorker.ReportProgress(highestToCheck);

	//Save Return Value
	e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
	pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
	pgbPrim.Value = pgbPrim.Maximum;
	this.Refresh();

	if (!e.Cancelled && e.Error == null)
	{
		//Show the Result
		int[] Primes = (int[])e.Result;

		StringBuilder sbOutput = new StringBuilder();

		foreach (int Prim in Primes)
		{
			sbOutput.Append(Prim.ToString() + Environment.NewLine);
		}

		tbPrim.Text = sbOutput.ToString();
	}
	else 
	{
		tbPrim.Text = "Operation canceled by user or Exception";
	}
}
#endregion

答案 1 :(得分:0)

处理你的sql-query,连接到smtp-server并将邮件数据传输到服务器需要时间。由于您在UI-Thread中执行了所有这些操作,因此表单会冻结。

在表单中添加BackgroundWorker,添加.DoWork.RunWorkerCompleted的事件处理程序,并将SQL和SMTP内容添加到DoWork函数中。

在Button1上单击,使用.RunWorkerAsync启动BackgroundWorker。使用TextBox1和TextBox2内容将字符串数组传递给此函数。您需要这样做,因为您无法从DoWork函数访问这些元素。您可以选择使用.IsBusy检查工作人员是否已处于活动状态。启动工作程序后,您应该锁定UI或显示消息或类似的信息,以告诉用户后台进程正在运行。从Button1Click函数执行此操作。

然后修改.DoWork函数以提取传递的字符串数组。您可以通过访问传递的DoWorkEventArgs.Arguments并将它们转换为传递给RunWorkerAsync的类型 - 到字符串数组来实现。将TextBox访问权交换为数组值。

RunWorkerCompleted功能中,您必须解锁用户界面。

开始阅读有关BackgroundWorker的内容,您可以使用进度报告功能向用户通知进度,例如“收集sql数据,连接到smtp服务器,传输邮件数据,完成”......

答案 2 :(得分:0)

Luan Teixeira,

您应该查看Asynchronous Programming with Async and Await。这将解决您的问题。

要证明我在说什么。看看这段代码。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private async Task SendEmail()
    {

        if (textBox1.Text == "" || textBox2.Text == "")
        {
            MessageBox.Show("Preencha todos os campos", "Erro",
            MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            await Email.SendEmail();

            MessageBox.Show("Nice");
        }
    }
    private async void button1_Click(object sender, EventArgs e)
    {
        await SendEmail();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        this.Close();
    }
}

public class Email
{
    public async static Task SendEmail()
    {
        await Task.Delay(15000);
    }
}

您可以在textbox1和textbox2中编写内容,然后单击按钮。等待15秒(我正在模拟一个非常庞大的任务,可能需要15秒)。同时你可以看到用户界面没有冻结。你可以移动窗口。 15秒后,您将收到“好消息”。

那是因为在我的代码中,巨大的任务没有在GUI线程中运行。

希望它有所帮助 亲切的问候 丹尼尔

答案 3 :(得分:-1)

更改超时属性。因此,smtp.Timeout = 0;应该可以!