一个关于多线程的问题 我要在WinForm里实现这样一个功能:点击一个按钮,程序创建一个新后台线程,处理一个需要一定时间的任务(比如:发电子邮件或者复制文件等),此时,主窗体不能没有响应。处理完后,返回操作结果,主窗体显示处理结果。在处理时,主窗体能显示处理进度更好。最好能提供示例代码。本人菜鸟,望赐教。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 本帖最后由 bdmh 于 2012-08-01 16:23:00 编辑 private void button1_Click(object sender, EventArgs e) { new Thread(() => { for(int i=0;i<10000;i++) { Invoke((MethodInvoker)(() => { progressBar1.Value = i; })); } }).Start(); } 拷贝文件的例子类代码:using System;using System.IO;using System.Runtime.InteropServices;using System.Threading;namespace WindowsFormsApplication1{ /// <summary> /// 继续滥用委托 /// </summary> /// <param name="sourceFile"></param> /// <param name="targetFile"></param> public delegate void CopyProgressHandler(String sourceFile, String targetFile); /// <summary> /// 拷贝文件夹类 /// </summary> public class CopyDirectory { /// <summary> /// 继续滥用事件 /// </summary> public event CopyProgressHandler CopyProgress; #region Win32 API private const int MAX_PATH = 260; private const int MAX_ALTERNATE = 14; [StructLayout(LayoutKind.Sequential)] private struct FILETIME { public uint dwLowDateTime; public uint dwHighDateTime; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WIN32_FIND_DATA { public FileAttributes dwFileAttributes; public FILETIME ftCreationTime; public FILETIME ftLastAccessTime; public FILETIME ftLastWriteTime; public uint nFileSizeHigh; //changed all to uint from int, otherwise you run into unexpected overflow public uint nFileSizeLow; //| http://www.pinvoke.net/default.aspx/Structures/WIN32_FIND_DATA.html public uint dwReserved0; //| public uint dwReserved1; //v [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)] public string cAlternate; } [DllImport("kernel32", CharSet = CharSet.Unicode)] private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32", CharSet = CharSet.Unicode)] private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FindClose(IntPtr hFindFile); #endregion /// <summary> /// 拷贝 /// </summary> /// <param name="sourceDirectory">源文件</param> /// <param name="targetDirectory">目标文件夹</param> public void Copy(String sourceDirectory, String targetDirectory) { IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); WIN32_FIND_DATA findData; IntPtr findHandle; findHandle = FindFirstFile(sourceDirectory + "*.*", out findData); if (findHandle != INVALID_HANDLE_VALUE) { do { if ((findData.dwFileAttributes & FileAttributes.Directory) != 0) { if (findData.cFileName != "." && findData.cFileName != "..") { Copy(String.Format("{0}{1}{2}", sourceDirectory, findData.cFileName, "\\"), targetDirectory); } } else { String strFile = sourceDirectory + findData.cFileName; if (File.Exists(strFile)) { try { FileInfo fileInfo = new FileInfo(strFile); String strCopyTargetFile = String.Format("{0}{1}", targetDirectory, fileInfo.Name); if (CopyProgress != null) { // 触发事件,通知界面 CopyProgress(strFile, strCopyTargetFile); } // 拷贝文件 File.Copy(strFile, strCopyTargetFile); } catch { } } } } while (FindNextFile(findHandle, out findData)); FindClose(findHandle); } } }}窗体代码:using System;using System.IO;using System.Runtime.InteropServices;using System.Threading;namespace WindowsFormsApplication1{ /// <summary> /// 继续滥用委托 /// </summary> /// <param name="sourceFile"></param> /// <param name="targetFile"></param> public delegate void CopyProgressHandler(String sourceFile, String targetFile); /// <summary> /// 拷贝文件夹类 /// </summary> public class CopyDirectory { /// <summary> /// 继续滥用事件 /// </summary> public event CopyProgressHandler CopyProgress; #region Win32 API private const int MAX_PATH = 260; private const int MAX_ALTERNATE = 14; [StructLayout(LayoutKind.Sequential)] private struct FILETIME { public uint dwLowDateTime; public uint dwHighDateTime; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WIN32_FIND_DATA { public FileAttributes dwFileAttributes; public FILETIME ftCreationTime; public FILETIME ftLastAccessTime; public FILETIME ftLastWriteTime; public uint nFileSizeHigh; //changed all to uint from int, otherwise you run into unexpected overflow public uint nFileSizeLow; //| http://www.pinvoke.net/default.aspx/Structures/WIN32_FIND_DATA.html public uint dwReserved0; //| public uint dwReserved1; //v [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)] public string cAlternate; } [DllImport("kernel32", CharSet = CharSet.Unicode)] private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32", CharSet = CharSet.Unicode)] private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FindClose(IntPtr hFindFile); #endregion /// <summary> /// 拷贝 /// </summary> /// <param name="sourceDirectory">源文件</param> /// <param name="targetDirectory">目标文件夹</param> public void Copy(String sourceDirectory, String targetDirectory) { IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); WIN32_FIND_DATA findData; IntPtr findHandle; findHandle = FindFirstFile(sourceDirectory + "*.*", out findData); if (findHandle != INVALID_HANDLE_VALUE) { do { if ((findData.dwFileAttributes & FileAttributes.Directory) != 0) { if (findData.cFileName != "." && findData.cFileName != "..") { Copy(String.Format("{0}{1}{2}", sourceDirectory, findData.cFileName, "\\"), targetDirectory); } } else { String strFile = sourceDirectory + findData.cFileName; if (File.Exists(strFile)) { try { FileInfo fileInfo = new FileInfo(strFile); String strCopyTargetFile = String.Format("{0}{1}", targetDirectory, fileInfo.Name); if (CopyProgress != null) { // 触发事件,通知界面 CopyProgress(strFile, strCopyTargetFile); } // 拷贝文件 File.Copy(strFile, strCopyTargetFile); } catch { } } } } while (FindNextFile(findHandle, out findData)); FindClose(findHandle); } } }} 不要这样喂不要这样喂Directory.GetFiles太垃圾了竟然不是异步的文件一多就有可能卡死界面有木有?有木有? 可能上面的问题表述不够清楚,我再重新说下 private void SendEmail() { try { client.Send(msg); tSSlblStatus.Text = "发送完成"; MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { tSSlblStatus.Text = "发送失败"; MessageBox.Show(ex.Message, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } tSSlblStatus.Text = ""; txtReceive.Enabled = true; //这几句设置Enable的语句会出错 txtTitle.Enabled = true; txtNeirong.Enabled = true; btSend.Enabled = true; btSettings.Enabled = true; cByxj.Enabled = true; } private void btSend_Click(object sender, EventArgs e) { tSSlblStatus.Text = "准备发送..."; txtReceive.Enabled = false; txtTitle.Enabled = false; txtNeirong.Enabled = false; btSend.Enabled = false; btSettings.Enabled = false; cByxj.Enabled = false;... Thread thread = new Thread(new ThreadStart(SendEmail)); tSSlblStatus.Text = "正在发送邮件..."; thread.Start(); }这是我编的发送电子邮件的例子。线程结束前,需要将发送成功,或者失败的信息传送给主窗体,将MessageBox显示和改变控件Text、Enable的代码移到主窗体中,最好能将这些代码放进一个新的方法中,当主窗体收到线程的消息时执行这个方法。 public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; }加上CheckForIllegalCrossThreadCalls = false就行了 1:利用lambda表达式做闭包2:在上面闭包的基础上传递一个委托进去 线程返回时回调 或者用Task什么的来做 这个支持异步回调的 using System;using System.Threading;namespace Test{ class Program { private static void Foo(Object obj) { if(obj != null) { ThreadData threadData = obj as ThreadData; if (threadData != null) { Console.WriteLine(String.Format("ThreadName={0},RunTime={1}", threadData.ThreadName, threadData.RunTime)); } } } static void Main() { ThreadData threadData = new ThreadData(); threadData.ThreadName = "TestThread"; threadData.RunTime = System.DateTime.Now; Thread t = new Thread(new ParameterizedThreadStart(Foo)); t.IsBackground = true; t.Start(threadData); Console.ReadKey(); } } class ThreadData { public String ThreadName; public DateTime RunTime; }} 我不想用Control.CheckForIllegalCrossThreadCalls = false;的方法不想在子线程中控制主窗体的控件。MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);MessageBox.Show(ex.Message, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);tSSlblStatus.Text = "";txtReceive.Enabled = true;txtTitle.Enabled = true;txtNeirong.Enabled = true;btSend.Enabled = true;btSettings.Enabled = true;cByxj.Enabled = true;我希望把这些语句放到主窗体中。因此必须在子线程运行完成后传送一个参数给主窗体,由主窗体执行这些语句。怎样才能实现? 程序现在改成这样,没有问题了,传递参数和回调已经实现。就是传回参数时,用的是全局变量,闭包还是没搞懂。 public class ResultShow { public bool Success; public string ErrMessage; public ResultShow() { Success = false; ErrMessage = ""; } public ResultShow(bool suc) { Success = suc; if (suc) ErrMessage = ""; else ErrMessage = "Unknown Error"; } public ResultShow(bool suc, string errm) { Success = suc; if (suc) ErrMessage = ""; else ErrMessage = errm; } } public static ResultShow r1 = new ResultShow(); public delegate void MyInvoke(); private void SendEmail(object msg) { try { client.Send((MailMessage)msg); r1.Success = true; } catch (Exception ex) { r1.Success = false; r1.ErrMessage = ex.Message; } MyInvoke mi = new MyInvoke(SendEnd); this.BeginInvoke(mi); } private void SendEnd() { if (r1.Success) { tSSlblStatus.Text = "发送完成"; MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { tSSlblStatus.Text = "发送失败"; MessageBox.Show(r1.ErrMessage, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } tSSlblStatus.Text = ""; txtReceive.Enabled = true; txtTitle.Enabled = true; txtNeirong.Enabled = true; btSend.Enabled = true; btSettings.Enabled = true; cByxj.Enabled = true; } private void btSend_Click(object sender, EventArgs e) { tSSlblStatus.Text = "准备发送..."; txtReceive.Enabled = false; txtTitle.Enabled = false; txtNeirong.Enabled = false; btSend.Enabled = false; btSettings.Enabled = false; cByxj.Enabled = false; string mailContent = txtNeirong.Text; MailMessage msg = new System.Net.Mail.MailMessage();... Thread thread = new Thread(new ParameterizedThreadStart(SendEmail)); thread.IsBackground = true; tSSlblStatus.Text = "正在发送邮件..."; thread.Start(msg); } 怎么才能过滤到json中的回车符 系统升级困惑 窗体上包含多个datagridview,何时赋值 咨询一个winform控件 这个错误是什么意思...急啊... 请教一下关于MDI窗体背景的问题 将d:\temp\1\下面所有的txt文件加s怎么变 c# webbrowser 异常导致程序退出 需要WCF服务作为数据访问器来操作MYSql数据库、请问怎样来解决很多客户端同时访问WCF服务的并发问题? 谁解决了这个问题,送他几百分都可以!微软专家MVP请注意这个问题,可能是.net的bug 怎么做类似百度那个文本框一样的东西 c#怎么控制其他窗体上的控件啊?
{
new Thread(() =>
{
for(int i=0;i<10000;i++)
{
Invoke((MethodInvoker)(() => { progressBar1.Value = i; }));
}
}).Start();
}
类代码:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;namespace WindowsFormsApplication1
{
/// <summary>
/// 继续滥用委托
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="targetFile"></param>
public delegate void CopyProgressHandler(String sourceFile, String targetFile); /// <summary>
/// 拷贝文件夹类
/// </summary>
public class CopyDirectory
{
/// <summary>
/// 继续滥用事件
/// </summary>
public event CopyProgressHandler CopyProgress; #region Win32 API private const int MAX_PATH = 260;
private const int MAX_ALTERNATE = 14; [StructLayout(LayoutKind.Sequential)]
private struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
}; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh; //changed all to uint from int, otherwise you run into unexpected overflow
public uint nFileSizeLow; //| http://www.pinvoke.net/default.aspx/Structures/WIN32_FIND_DATA.html
public uint dwReserved0; //|
public uint dwReserved1; //v
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
public string cAlternate;
} [DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FindClose(IntPtr hFindFile); #endregion /// <summary>
/// 拷贝
/// </summary>
/// <param name="sourceDirectory">源文件</param>
/// <param name="targetDirectory">目标文件夹</param>
public void Copy(String sourceDirectory, String targetDirectory)
{
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
WIN32_FIND_DATA findData; IntPtr findHandle; findHandle = FindFirstFile(sourceDirectory + "*.*", out findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
do
{
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
{
if (findData.cFileName != "." && findData.cFileName != "..")
{
Copy(String.Format("{0}{1}{2}", sourceDirectory, findData.cFileName, "\\"), targetDirectory);
}
}
else
{
String strFile = sourceDirectory + findData.cFileName;
if (File.Exists(strFile))
{
try
{
FileInfo fileInfo = new FileInfo(strFile);
String strCopyTargetFile = String.Format("{0}{1}", targetDirectory, fileInfo.Name);
if (CopyProgress != null)
{
// 触发事件,通知界面
CopyProgress(strFile, strCopyTargetFile);
}
// 拷贝文件
File.Copy(strFile, strCopyTargetFile);
}
catch
{
}
}
}
}
while (FindNextFile(findHandle, out findData));
FindClose(findHandle);
}
}
}
}
窗体代码:using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;namespace WindowsFormsApplication1
{
/// <summary>
/// 继续滥用委托
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="targetFile"></param>
public delegate void CopyProgressHandler(String sourceFile, String targetFile); /// <summary>
/// 拷贝文件夹类
/// </summary>
public class CopyDirectory
{
/// <summary>
/// 继续滥用事件
/// </summary>
public event CopyProgressHandler CopyProgress; #region Win32 API private const int MAX_PATH = 260;
private const int MAX_ALTERNATE = 14; [StructLayout(LayoutKind.Sequential)]
private struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
}; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh; //changed all to uint from int, otherwise you run into unexpected overflow
public uint nFileSizeLow; //| http://www.pinvoke.net/default.aspx/Structures/WIN32_FIND_DATA.html
public uint dwReserved0; //|
public uint dwReserved1; //v
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
public string cAlternate;
} [DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FindClose(IntPtr hFindFile); #endregion /// <summary>
/// 拷贝
/// </summary>
/// <param name="sourceDirectory">源文件</param>
/// <param name="targetDirectory">目标文件夹</param>
public void Copy(String sourceDirectory, String targetDirectory)
{
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
WIN32_FIND_DATA findData; IntPtr findHandle; findHandle = FindFirstFile(sourceDirectory + "*.*", out findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
do
{
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
{
if (findData.cFileName != "." && findData.cFileName != "..")
{
Copy(String.Format("{0}{1}{2}", sourceDirectory, findData.cFileName, "\\"), targetDirectory);
}
}
else
{
String strFile = sourceDirectory + findData.cFileName;
if (File.Exists(strFile))
{
try
{
FileInfo fileInfo = new FileInfo(strFile);
String strCopyTargetFile = String.Format("{0}{1}", targetDirectory, fileInfo.Name);
if (CopyProgress != null)
{
// 触发事件,通知界面
CopyProgress(strFile, strCopyTargetFile);
}
// 拷贝文件
File.Copy(strFile, strCopyTargetFile);
}
catch
{
}
}
}
}
while (FindNextFile(findHandle, out findData));
FindClose(findHandle);
}
}
}
}
不要这样喂
不要这样喂
Directory.GetFiles太垃圾了
竟然不是异步的
文件一多
就有可能卡死界面
有木有?
有木有?
private void SendEmail()
{
try
{
client.Send(msg);
tSSlblStatus.Text = "发送完成";
MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
tSSlblStatus.Text = "发送失败";
MessageBox.Show(ex.Message, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
tSSlblStatus.Text = "";
txtReceive.Enabled = true; //这几句设置Enable的语句会出错
txtTitle.Enabled = true;
txtNeirong.Enabled = true;
btSend.Enabled = true;
btSettings.Enabled = true;
cByxj.Enabled = true;
} private void btSend_Click(object sender, EventArgs e)
{
tSSlblStatus.Text = "准备发送...";
txtReceive.Enabled = false;
txtTitle.Enabled = false;
txtNeirong.Enabled = false;
btSend.Enabled = false;
btSettings.Enabled = false;
cByxj.Enabled = false;
...
Thread thread = new Thread(new ThreadStart(SendEmail));
tSSlblStatus.Text = "正在发送邮件...";
thread.Start();
}这是我编的发送电子邮件的例子。线程结束前,需要将发送成功,或者失败的信息传送给主窗体,将MessageBox显示和改变控件Text、Enable的代码移到主窗体中,最好能将这些代码放进一个新的方法中,当主窗体收到线程的消息时执行这个方法。
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}加上CheckForIllegalCrossThreadCalls = false就行了
2:在上面闭包的基础上传递一个委托进去 线程返回时回调 或者用Task什么的来做 这个支持异步回调的
using System.Threading;namespace Test
{
class Program
{ private static void Foo(Object obj)
{
if(obj != null)
{
ThreadData threadData = obj as ThreadData;
if (threadData != null)
{
Console.WriteLine(String.Format("ThreadName={0},RunTime={1}", threadData.ThreadName, threadData.RunTime));
}
}
} static void Main()
{
ThreadData threadData = new ThreadData();
threadData.ThreadName = "TestThread";
threadData.RunTime = System.DateTime.Now; Thread t = new Thread(new ParameterizedThreadStart(Foo));
t.IsBackground = true;
t.Start(threadData); Console.ReadKey();
}
} class ThreadData
{
public String ThreadName;
public DateTime RunTime;
}
}
不想在子线程中控制主窗体的控件。
MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
MessageBox.Show(ex.Message, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
tSSlblStatus.Text = "";
txtReceive.Enabled = true;
txtTitle.Enabled = true;
txtNeirong.Enabled = true;
btSend.Enabled = true;
btSettings.Enabled = true;
cByxj.Enabled = true;我希望把这些语句放到主窗体中。
因此必须在子线程运行完成后传送一个参数给主窗体,由主窗体执行这些语句。
怎样才能实现?
public class ResultShow
{
public bool Success;
public string ErrMessage;
public ResultShow()
{
Success = false;
ErrMessage = "";
}
public ResultShow(bool suc)
{
Success = suc;
if (suc)
ErrMessage = "";
else
ErrMessage = "Unknown Error";
}
public ResultShow(bool suc, string errm)
{
Success = suc;
if (suc)
ErrMessage = "";
else
ErrMessage = errm;
}
} public static ResultShow r1 = new ResultShow();
public delegate void MyInvoke(); private void SendEmail(object msg)
{
try
{
client.Send((MailMessage)msg);
r1.Success = true;
}
catch (Exception ex)
{
r1.Success = false;
r1.ErrMessage = ex.Message;
}
MyInvoke mi = new MyInvoke(SendEnd);
this.BeginInvoke(mi);
} private void SendEnd()
{
if (r1.Success)
{
tSSlblStatus.Text = "发送完成";
MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
tSSlblStatus.Text = "发送失败";
MessageBox.Show(r1.ErrMessage, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
tSSlblStatus.Text = "";
txtReceive.Enabled = true;
txtTitle.Enabled = true;
txtNeirong.Enabled = true;
btSend.Enabled = true;
btSettings.Enabled = true;
cByxj.Enabled = true;
} private void btSend_Click(object sender, EventArgs e)
{
tSSlblStatus.Text = "准备发送...";
txtReceive.Enabled = false;
txtTitle.Enabled = false;
txtNeirong.Enabled = false;
btSend.Enabled = false;
btSettings.Enabled = false;
cByxj.Enabled = false;
string mailContent = txtNeirong.Text; MailMessage msg = new System.Net.Mail.MailMessage();
...
Thread thread = new Thread(new ParameterizedThreadStart(SendEmail));
thread.IsBackground = true;
tSSlblStatus.Text = "正在发送邮件...";
thread.Start(msg);
}