做了一个xls文档比较工具(比较两个xls文档的数据差异),
主线程UI有一个主窗口和一个弹出窗口(显示线程任务进度条),
下面的代码是在主线程UI中启动2个异步线程(主要是读取xls文档),大致顺序是:构造弹出窗口,
启动异步线程一,
弹出模态窗口阻塞主线程UI,同时异步线程一中执行任务,并在执行任务时通过委托改变弹出模态窗口进度条,
线程一中任务执行完毕时通过委托关闭(close,dispose)模态窗口;
模态窗口关闭,主线程继续,
启动异步线程二,
弹出模态窗口阻塞主线程UI,同时异步线程二中执行任务,并在执行任务时通过委托改变弹出模态窗口进度条,
线程二中任务执行完毕时通过委托关闭(close,dispose)模态窗口;另外callback函数返回值的方式是:将EndInvoke中的值拷贝到主线程窗口类中的两个全局变量中我的问题是,两个异步线程有时候只能获得线程一的返回值,有时候则两个线程的返回值都可以获得,这是什么原因导致的?代码及完整工程已经上传到下面链接,如有需要请各位高手抽空看看,感激不尽!
http://download.csdn.net/source/2855724//主线程中执行异步线程的代码frm_Pgb = new Form_PrograssBar("正在解析物料清单文件 " + fileNameOfMaterialList_1 + " ,请稍候......");dgIML_1 = new dgImportMaterialList(this.ImportMaterialList);
AsyncCallback callback1 = new AsyncCallback(this.AsyncCallbackEndInvoke_1);
dgIML_1.BeginInvoke(openFileDialog1.FileNames[0], frm_Pgb, callback1, null);frm_Pgb.ShowDialog();
//----导致错误的代码
if (frm_Pgb != null)
{
frm_Pgb.Close();
frm_Pgb.Dispose();
}
//----frm_Pgb = new Form_PrograssBar("正在解析物料清单文件 " + fileNameOfMaterialList_2 + " ,请稍候......");dgIML_2 = new dgImportMaterialList(this.ImportMaterialList);
AsyncCallback callback2 = new AsyncCallback(this.AsyncCallbackEndInvoke_2);
dgIML_2.BeginInvoke(openFileDialog1.FileNames[1], frm_Pgb, callback2, null);frm_Pgb.ShowDialog();
//----导致错误的代码
if (frm_Pgb != null)
{
frm_Pgb.Close();
frm_Pgb.Dispose();
}
//----
//异步线程callback函数
public void AsyncCallbackEndInvoke_1(IAsyncResult ar)
{
cacheMaterialList_1.Clear(); //Get return value in callback method
IList<MaterialInfo> miList = dgIML_1.EndInvoke(ar); foreach (MaterialInfo mi in miList)
cacheMaterialList_1.Add(mi);
}public void AsyncCallbackEndInvoke_2(IAsyncResult ar)
{
cacheMaterialList_2.Clear(); //Get return value in callback method
IList<MaterialInfo> miList = dgIML_2.EndInvoke(ar); foreach (MaterialInfo mi in miList)
cacheMaterialList_2.Add(mi);
}//异步线程核心代码,主线程中启动异步线程时调用的委托方法是对该代码的封装public IList<MaterialInfo> ImportMaterialList()
{
int nRow = 7;
string tempMaterial = null; ;
string tempQuantity = null;
string tempSite = null; IList<MaterialInfo> miList = new List<MaterialInfo>(); //0.Prepare muti-thread prograssBar control objs
dgPrograssBarIncrease dgPI = new dgPrograssBarIncrease(pfrm.PrograssBarIncrease);
dgPrograssBarMax dgPM=new dgPrograssBarMax(pfrm.PrograssBarMax);
dgFormClose dgFC = new dgFormClose(pfrm.FormClose); try
{
//1.Check if the material list imported is correct,TBD.
if (((Range) xlSheet.Cells[7 , 1]).Value2.ToString().Trim() != "序号")
{
return null;
}
//2.Caculate the amount of available rows in xlSheet
while (((Range) xlSheet.UsedRange[nRow + 1 , 1]).Value2 != null)
{
nRow++;
} pfrm.progressBar1.Invoke(dgPM, new object[] { nRow });
//3.Read data in xlSheet
for (int i = 8 ; i < nRow ; i++)
{
if (((Range) xlSheet.Cells[i , 2]).Value2 != null)
tempMaterial = ((Range) xlSheet.Cells[i , 2]).Value2.ToString().Trim();
if (((Range) xlSheet.Cells[i , 8]).Value2 != null)
tempQuantity = ((Range) xlSheet.Cells[i , 8]).Value2.ToString().Trim();
if (((Range) xlSheet.Cells[i , 12]).Value2 != null)
tempSite = ((Range) xlSheet.Cells[i , 12]).Value2.ToString().Trim(); miList.Add(new MaterialInfo(tempMaterial , tempQuantity , tempSite)); pfrm.progressBar1.Invoke(dgPI, null);
}
}
catch (Exception ex)
{
throw ex;
} pfrm.Invoke(dgFC, null); return miList;
}

解决方案 »

  1.   

    看看,不知道对你有帮助否http://www.cnblogs.com/luminji/archive/2010/09/17/1829333.html
      

  2.   

    是不是ImportMaterialList()里边发生异常了?
      

  3.   

    应该不是异常的事,
    你应该加句这个
    dgIML_2.EndInvoke();frm_Pgb = new Form_PrograssBar("正在解析物料清单文件 " + fileNameOfMaterialList_2 + " ,请稍候......");dgIML_2 = new dgImportMaterialList(this.ImportMaterialList);
    AsyncCallback callback2 = new AsyncCallback(this.AsyncCallbackEndInvoke_2);
    dgIML_2.BeginInvoke(openFileDialog1.FileNames[1], frm_Pgb, callback2, null);frm_Pgb.ShowDialog();
    //----导致错误的代码
    if (frm_Pgb != null)
    {
        frm_Pgb.Close();
        frm_Pgb.Dispose();
    }
    dgIML_2.EndInvoke();//以确保执行完毕,并触发callBack;
    Thrad.Sleep(1000);
      

  4.   

    楼主看下这个例子,如果不加那个Thread.Sleep的话,有时只会出现两次“true”,而本想出现5次的,因为主线程结束的时候,异步线程还没有结束,所以加个Thread.Sleep,楼主那种情况,直接EndInvoke就行了。public class DelegateStudy
        {
            delegate bool sendMsgDelegate(string name, string msg);   //申明委托
            public bool sendMsg(string name, string msg)
            {
                lock (this)
                {                //Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                    return SendEmail("[email protected]", "xxxxxx", "[email protected]", name, msg, "smtp.163.com");
                }
            }        private static bool SendEmail(string p, string p_2, string p_3, string name, string msg, string p_6)
            {
                return true;
            }        public static void SendCallBack(IAsyncResult asynceresult)
            {
                sendMsgDelegate ss = (sendMsgDelegate) ((AsyncResult)asynceresult).AsyncDelegate;
                bool result = ss.EndInvoke(asynceresult);
                Console.WriteLine(result);
                
            }        [Test]
            public  void Test()
            {
                sendMsgDelegate ss = sendMsg;
                
                for (int i = 0; i < 5; i++)
                {
                    
                    ss.BeginInvoke("jack" + i, "Hello" + i, SendCallBack, null);
                    //Console.WriteLine("我是主方法里的");
                }            Thread.Sleep(1000); //以确保几个异步都执行完毕            //Thread.CurrentThread.Join();            Console.Write("都执行完了");
                //Console.ReadLine();
            }    }
      

  5.   


    兄弟谢谢你的回复我的EndInvoke写在callback方法AsyncCallbackEndInvoke里,在主楼贴的第二个代码段里希望楼下的高手能针对我的代码给点意见
      

  6.   

    这个不应该在callBack中调用EndInvoke吧,没见过这么写的
      

  7.   

    http://blogs.msdn.com/b/thottams/archive/2007/11/01/calling-delegates-using-begininvoke-invoke-dynamicinvoke-and-delegate.aspx
    楼主参考下这个链接里如何使用callback的.
      

  8.   


    你贴的例子里不就是这么写的。是我理解错误?
    10楼链接我看看,谢了
            public static void SendCallBack(IAsyncResult asynceresult)
            {
                sendMsgDelegate ss = (sendMsgDelegate) ((AsyncResult)asynceresult).AsyncDelegate;
                bool result = ss.EndInvoke(asynceresult);
                Console.WriteLine(result);
                
            }
      

  9.   

    在异步方法执行完了之后,执行
    摘一段MSDN的源话:
    在等待异步操作结果的同时可以进行其他工作的应用程序不应在操作完成之前阻止等待。可以使用下列方法之一来在等待异步操作完成的同时继续执行指令。可使用 AsyncCallback 委托来处理另一个线程中的异步操作的结果。本主题中演示了此方法。 可使用异步操作的 BeginOperationName 方法返回的 IAsyncResult 的 IsCompleted 属性来确定此操作是否已完成。有关演示此方法的示例,请参见轮询异步操作的状态。示例
    ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_fxadvance/html/9d97206c-8917-406c-8961-7d0909d84eeb.htm
      

  10.   


    恩,在每个ShowDialog后面加上Thread.Sleep(1000)后可以解决问题。但是这样的话异步调用线程岂不是变的很不可控?
    或者说如果频繁的使用异步调用线程,为了确保callback返回结果而每次都Sleep,这对程序的性能岂不是一种极大的损耗?难道没有一种完美的解决方案?
      

  11.   


    Boolean callbacked = false; //成员变量,当callback执行完后,设置为truefrm_Pgb.ShowDialog();
    //----导致错误的代码
    if (frm_Pgb != null)
    {
        frm_Pgb.Close();
        frm_Pgb.Dispose();
    }while(callbacked){} //等待;public void AsyncCallbackEndInvoke_2(IAsyncResult ar)
    {
        cacheMaterialList_2.Clear();    //Get return value in callback method
        IList<MaterialInfo> miList = dgIML_2.EndInvoke(ar);    foreach (MaterialInfo mi in miList)
            cacheMaterialList_2.Add(mi);    callbacked = true;
    }