您好,我用backgroundworker写了一个后台读取access文件表内容到listview显示的东东,但是在载入数据到listview中时常会(时好时坏,似乎没有一定规律)出现backgroundworker正忙等错误信息,接着就中止执行了。我试了很多次,没有找到完善的解决办法,目前只能是在载入每条数据时,使用thread.sleep,并把间隔时间设的长一点,但这就会影响到载入的速度。所以我想把代码贴出,请您帮我看看有什么完善的解决方法。多谢。
代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using JamesZhang.MyFuncs.MD5;
using JamesZhang.MyFuncs.FilesSys;
using System.IO;namespace Resume
{
    public partial class ExportDataGL : Form
    {
        private string strSaveFolder = "";              //导出文件所在根目录
        private string strAccessFile = "";              //保存数据的Access文件
        private int intNum = 0;                         //载入进展
        private int intCount = 0;                       //被导出的数据总数
        private int ID = 0;                             //导出的记录编号
        private string strFullFileName = "";            //导出的文件完整名称,含扩展名
        private string strSourceUrl = "";
        private string strSubject = "";
        private string strResult = "";        public ExportDataGL(string strFolder)
        {
            InitializeComponent();            strSaveFolder = strFolder;            //导出文件目录
            lbDataFolder.Text = strSaveFolder;
            lbDataFolder.Update();            //修改信息列表最后一栏宽度
            lv_DataFiles.Columns[3].Width = 300;
            lv_DataFiles.Columns[4].Width = 300;            //(PP:定义需要在子线程中干的事情, 调用 RunWorkerAsync 时发生)
            backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);            //(PP:定义执行完毕后需要做的事情 )
            backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);            backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
        }
        /// 判断当前收录目录下是否已经存在了access文件。一个导出目录只能存在一个access文件
        private int CheckAccessFileExisted()
        {
            int intResult = 0;                  //0:表示不存在,1:存在            DirectoryInfo objDir = new DirectoryInfo(@strSaveFolder);
            //FileInfo objFiles = objDir.GetFiles();            foreach (FileInfo objFile in objDir.GetFiles())
            {
                if (objFile.Name.ToUpper().IndexOf(".MDB") > -1)
                {
                    strAccessFile = objFile.FullName;                    intResult = 1;
                    break;
                }
            }
            return intResult;
        }        //窗口装载时就显示已导出的数据列表
        private void ExportDataGL_Load(object sender, EventArgs e)
        {
            //导入数据时将按钮禁用
            btnDel.Enabled = false;            //得到指定的Access文件
            if (CheckAccessFileExisted() == 0)
            {
                MessageBox.Show("不存在相关的Access文件!");
                return;
            }            //判断是否有数据被导出
            DBAccess objDB = new DBAccess();            //得到被导出数据的总数
            intCount = objDB.ExportDataCount(strAccessFile);            if (intCount == 0)
            {
                MessageBox.Show("目前还没有相关数据被导出!");
                return;
            }            backgroundWorker1.RunWorkerAsync(100);
        }
        #region 后台装载
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            InvokeFun(worker, e);
        }        private void InvokeFun(BackgroundWorker worker, DoWorkEventArgs e)
        {
            string strFile = "";
            int i = 0;            //创建核实信息是否已经被加入到收录表中
            DBAccess objDB= new DBAccess();            //获取待导出数据集
            DataSet objDS = null;            objDS = objDB.GetOutDataRs(strAccessFile);            intNum = 0;            if (worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                JamesZhang.MyFuncs.FilesSys.MyFileSys objFS = new JamesZhang.MyFuncs.FilesSys.MyFileSys();                while (i  < intCount)
                {
                    ID = 0;
                    strSubject = "";
                    strFile = "";
                    strFullFileName = "";
                    strSourceUrl = "";
                    strResult = "";                    //得到当前正导出的记录编号
                    ID = Convert.ToInt32(objDS.Tables[0].Rows[i][0]);                    //得到标题
                    strSubject = objDS.Tables[0].Rows[i][1].ToString().Trim();                    //得到当前正在导出文件
                    strFile = objDS.Tables[0].Rows[i][2].ToString().Trim();                    //得到当前正在导出的文件名称
                    strFullFileName = objFS.GetFullFileName(strFile);                    //得到当前正在导出的文件源网址
                    strSourceUrl = objDS.Tables[0].Rows[i][3].ToString().Trim();                    //判断导出的网页文件是否存在
                    if (strFullFileName != "")
                    {
                        //导出后完整的文件名称
                        strFullFileName = strSaveFolder +"\\Htmls\\"+strFullFileName;                        //判断文件是否存在
                        if (objFS.CheckFileExisted(strFullFileName)=="Y")
                            //修改成功
                            strResult = "曾经导出";
                        else
                            strResult = "文件不存在";
                    }                    i++;                    //刷新相关参数
                    intNum++;                    worker.ReportProgress(0);                   Thread.Sleep(200);
                }
            }
        }        //刷新信息控件事件
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ////刷新listview控件
            ListViewItem listViewItem = new ListViewItem(new string[] {
            intNum.ToString(),
            strResult,
            ID.ToString()+"/"+strSubject,
            strFullFileName,
            strSourceUrl
            });
            lv_DataFiles.Items.Add(listViewItem);            if ((intNum % 2) == 1)
                //重新设定背景颜色
                lv_DataFiles.Items[intNum - 1].BackColor = Color.WhiteSmoke;            progressBar1.Value = (int)Math.Round((Convert.ToDecimal(intNum) / Convert.ToDecimal(intCount)) * 100, 0);            lbProDesc.Text = intNum.ToString() + "/" + intCount.ToString();
            lbProDesc.Update();
        }        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                MessageBox.Show("任务中止了!");
            }
            else
            {
                btnDel.Enabled = true;
                btnQuit.Enabled = true;
            }
        }
        #endregion
    }
}

解决方案 »

  1.   

    多线程问题···可能死锁··
    建议自己写 不要用控件····Control.Invoke(代理,(object)参数);
    代理里面
    if(Control.InvokeRequest)
    {
         代理 dele=new 代理
          Control.Invoke(dele,(object)Paras);
    }
    else
    {
       //DO what you like
    }
      

  2.   

    A.建议你把Load事件里的内容放到Shown事件里试一下,因为没显示之前刷新树,感觉有点儿怪异。
    B.感觉你应该把worker.CancellationPending这个判断放到循环里面才好,否则,在循环结束前,是无法响应这个判断的。
    C.根据你说的进程休止一断时间效果会好一些的情况,时好时坏的原因,很可能出在ProgressChanged这个事件上,个人认为,这个事件里不适宜放复杂的处理,应该是越简单越好,可以尝试把创建ListViewNode放到后台进程中,把创建好的对象传递给ProgressChanged事件的方法,看看是否能够改善。
    没进行实际的尝试,只是一些建议。
      

  3.   

    你始终是将两个线程共用的东西以类成员的方式放置着,也没有加锁。这样两个线程自然会冲突。——BackgroundWorker不过是一个封装过的线程。正确的做法是DoWork中找到新的记录则通过ReportProgress(0,record)的方式将记录发给ProgressChanged。而ProgressChanged中利用e.UserState获取这个record,并且用这个record创建一个新的ListViewItem加入到ListView中。唯有如此,才可以消除线程间的冲突。虽然BackgroundWorker是封装过的线程,但是使用它一定要严格按照多线程的准则来做,否则出错就是家常便饭了。
      

  4.   

    你始终是将两个线程共用的东西以类成员的方式放置着,也没有加锁。这样两个线程自然会冲突。——BackgroundWorker不过是一个封装过的线程。正确的做法是DoWork中找到新的记录则通过ReportProgress(0,record)的方式将记录发给ProgressChanged。而ProgressChanged中利用e.UserState获取这个record,并且用这个record创建一个新的ListViewItem加入到ListView中。唯有如此,才可以消除线程间的冲突。虽然BackgroundWorker是封装过的线程,但是使用它一定要严格按照多线程的准则来做,否则出错就是家常便饭了。