我要在WinForm里实现这样一个功能:点击一个按钮,程序创建一个新后台线程,处理一个需要一定时间的任务(比如:发电子邮件或者复制文件等),此时,主窗体不能没有响应。处理完后,返回操作结果,主窗体显示处理结果。在处理时,主窗体能显示处理进度更好。
最好能提供示例代码。本人菜鸟,望赐教。

解决方案 »

  1.   

    本帖最后由 bdmh 于 2012-08-01 16:23:00 编辑
      

  2.   

    private void button1_Click(object sender, EventArgs e)
            {
                new Thread(() =>
                {
                    for(int i=0;i<10000;i++)
                    {
                        Invoke((MethodInvoker)(() => { progressBar1.Value = i; }));
                    }
                }).Start();
            }
      

  3.   

    拷贝文件的例子
    类代码:
    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);
                }
            }
        }
    }
      

  4.   


    不要这样喂
    不要这样喂
    Directory.GetFiles太垃圾了
    竟然不是异步的
    文件一多
    就有可能卡死界面
    有木有?
    有木有?
      

  5.   

    可能上面的问题表述不够清楚,我再重新说下
            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的代码移到主窗体中,最好能将这些代码放进一个新的方法中,当主窗体收到线程的消息时执行这个方法。
      

  6.   

            public Form1()
            {
                InitializeComponent();
                Control.CheckForIllegalCrossThreadCalls = false;
            }加上CheckForIllegalCrossThreadCalls = false就行了
      

  7.   

    1:利用lambda表达式做闭包
    2:在上面闭包的基础上传递一个委托进去 线程返回时回调 或者用Task什么的来做 这个支持异步回调的
      

  8.   

    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;
        }
    }
      

  9.   

    我不想用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;我希望把这些语句放到主窗体中。
    因此必须在子线程运行完成后传送一个参数给主窗体,由主窗体执行这些语句。
    怎样才能实现?
      

  10.   

    程序现在改成这样,没有问题了,传递参数和回调已经实现。就是传回参数时,用的是全局变量,闭包还是没搞懂。
            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);
            }