C#winform中UI線程与工作線程的交互

C#winform中UI線程与工作線程的交互

1.使用多線程

void CalcPi(int digits)
{
 //...這里可寫任意代碼,但如果与UI界面交互將出錯.
}

void calcButton_Click(object sender,EventArgs e)
{
 //...這里還是在UI線程里,可以寫任意代碼
 //啟動一個新線程,用于處理費時的任務
 Thread piThread=new Thread(CalcPiThreadStart);
 piThread.Start((int)this.decimalPlacesNumericUpDown.Value);
}
void CalcPiThreadStart(object digits)
{
 //線程只能傳object類型的參數.
 CalcPi((int)digits);
}

2.在UI線程中調用其它線程

使用了多線程,卻還有兩個問題(1)線程只能傳object類型參數(2)在新的線程中,不能直接修改窗体中的內容.事實上,在与UI交互時,我們一般并不用多線程,而是使用自定義委托.盡管這也是多線程的原理.但操作起來方便的多.

--1.同步調用
void CalcPi(int digits)
{
 //...這里如果有与UI界面交互的代碼,則必須要使用回調方法
}

delegate void CalcPiDelegate(int digits);
void calcButton_Click(object sender,EventArgs e)
{
 //...
 //
 CalcPiDelegate calcPi=new CalcPiDelegate(CalcPi);
 //同步調用,与calcPi.Invoke作用相同
 calcPi((int)this.decimalPlacesNumericUpDown.Value);
}

--2.异步調用
void CalcPi(int digits)
{
 //...這里如果有与UI界面交互的代碼,則必須要使用回調方法
}

delegate void CalcPiDelegate(int digits);
void calcButton_Click(object sender,EventArgs e)
{
 //...
 //
 CalcPiDelegate calcPi=new CalcPiDelegate(CalcPi);
 //异步調用
 calcPi.BeginInvoke(
  (int)this.decimalPlacesNumericUpDown.Value,//將此參數傳給CalcPi方法
  EndCalcPi,//當CalcPi結束時調用該方法
  calcPi);//此參數傳給EndCalcPi方法,好像一定要与委托名稱相同

}
void EndCalcPi(IAsyncResult result)
{
 //獲得結果,處理异常和清除資源
 try
 {
  CalcPiDelegate calcPi=(CalcPiDelegate)result.AsyncState;
  calcPi.EndInvoke(result);//調用EndInvoke
 }
 catch(Exception ex)
 {
  //EndCalcPi在工作者線程中執行
  //...這里不能寫与UI交互的代碼,否則出錯
 }

}


3.在工作者線程中回調UI線程
不管是同步調用還是异步調用,如果在工作線程中需要顯示消息到UI上,如在工作線程中發生异常或需要報知進度等,這時我們還需要回調UI線程.回調也分同步回調与异步回調.
--1.同步回調
將CalcPi方法改為如下:

void ShowProgress(string pi,int totalDigits,int digitsSoFar)
{
 //确保當前處于UI線程
 Debug.Assert(this.InvokeRequired==false);
 
 //...這里一般寫与UI線程交互的代碼.以及一些簡短的數据處理.

}
delegate void ShowProgressDelegate(string pi,int totalDigits,int digitsSoFar);
void CalcPi(int digits)
{
 StringBuilder pi=new StringBuilder("3",digits+2);
 //准備顯示進度
 ShowProgressDelegate showProgress=new ShowProgressDelegate(ShowProgress);

 //當需要回顯消息時,就調用Control.Invoke
 //顯示初始進度,工作線程暫停,等顯示完畢后,再繼續工作線程.
 this.Invoke(showProgress,new object[]{pi.ToString(),digits,0});
 if(digits>0)
 {
  pi.Append(".");
  for(int i=0;i<digits;i+=9)
  {
   //...對數据的處理,這是一段耗時的代碼
   //顯示變化的進度,工作線程暫停,等顯示完畢后,再繼續工作線程.
   this.Invoke(showProgress,new object[]{pi.ToString(),digits,i+digitCount});
  }
 }
}

--2.异步回調
將CalcPi方法改為如下,其實這段代碼与同步回調的唯一區別就是用BeginInvoke代替了Invoke.异步回調与异步調用有一點不同,那就是,异步回調在Control.BeginInvoke之后不用調用Control.EndInvoke,這是完全安全的.
void ShowProgress(string pi,int totalDigits,int digitsSoFar)
{
 //确保當前處于UI線程
 Debug.Assert(this.InvokeRequired==false);
 
 //...這里一般寫与UI線程交互的代碼.以及一些簡短的數据處理.

}
delegate void ShowProgressDelegate(string pi,int totalDigits,int digitsSoFar);
void CalcPi(int digits)
{
 StringBuilder pi=new StringBuilder("3",digits+2);
 //准備顯示進度
 ShowProgressDelegate showProgress=new ShowProgressDelegate(ShowProgress);

 //當需要回顯消息時,就調用
 //通知UI線程去顯示初始進度,并立即返回工作線程.
 this.BeginInvoke(showProgress,new object[]{pi.ToString(),digits,0});
 if(digits>0)
 {
  pi.Append(".");
  for(int i=0;i<digits;i+=9)
  {
   //...對數据的處理,這是一段耗時的代碼
   //通知UI線程去顯示變化的進度,并立即返回工作線程.
   this.BeginInvoke(showProgress,new object[]{pi.ToString(),digits,i+digitCount});
  }
 }
}


4.總結
--1.同步調用与同步回調結合.
delegate void CalcPiDelegate(int digits);
void calcButton_Click(object sender,EventArgs e)
{
 //...
 //
 CalcPiDelegate calcPi=new CalcPiDelegate(CalcPi);
 //同步調用,与calcPi.Invoke作用相同
 calcPi((int)this.decimalPlacesNumericUpDown.Value);
}

void ShowProgress(string pi,int totalDigits,int digitsSoFar)
{
 //确保當前處于UI線程
 Debug.Assert(this.InvokeRequired==false);
 
 //...這里一般寫与UI線程交互的代碼.以及一些簡短的數据處理.

}
delegate void ShowProgressDelegate(string pi,int totalDigits,int digitsSoFar);
void CalcPi(int digits)
{
 StringBuilder pi=new StringBuilder("3",digits+2);
 //准備顯示進度
 ShowProgressDelegate showProgress=new ShowProgressDelegate(ShowProgress);

 //同步回調
 this.Invoke(showProgress,new object[]{pi.ToString(),digits,0});
 if(digits>0)
 {
  pi.Append(".");
  for(int i=0;i<digits;i+=9)
  {
   //...對數据的處理,這里是一段耗時的代碼
   //同步回調
   this.Invoke(showProgress,new object[]{pi.ToString(),digits,i+digitCount});
  }
 }
}

--2.异步調用与异步回調結合.

delegate void CalcPiDelegate(int digits);
void calcButton_Click(object sender,EventArgs e)
{
 //...
 //
 CalcPiDelegate calcPi=new CalcPiDelegate(CalcPi);
 //异步調用
 calcPi.BeginInvoke(
  (int)this.decimalPlacesNumericUpDown.Value,//將此參數傳給CalcPi方法
  EndCalcPi,//當CalcPi結束時調用該方法
  calcPi);//此參數傳給EndCalcPi方法,好像一定要与委托名稱相同

}
void EndCalcPi(IAsyncResult result)
{
 //獲得結果,處理异常和清除資源
 try
 {
  CalcPiDelegate calcPi=(CalcPiDelegate)result.AsyncState;
  calcPi.EndInvoke(result);//調用EndInvoke
 }
 catch(Exception ex)
 {
  //EndCalcPi在工作者線程中執行
  //...如果需要回調UI線程,可使用同步回調或异步回調.
 }

}

void ShowProgress(string pi,int totalDigits,int digitsSoFar)
{
 //确保當前處于UI線程
 Debug.Assert(this.InvokeRequired==false);
 
 //...這里一般寫与UI線程交互的代碼.以及一些簡短的數据處理.

}
delegate void ShowProgressDelegate(string pi,int totalDigits,int digitsSoFar);
void CalcPi(int digits)
{
 StringBuilder pi=new StringBuilder("3",digits+2);
 //准備顯示進度
 ShowProgressDelegate showProgress=new ShowProgressDelegate(ShowProgress);

 //當需要回顯消息時,就調用
 //通知UI線程去顯示初始進度,并立即返回工作線程.
 this.BeginInvoke(showProgress,new object[]{pi.ToString(),digits,0});
 if(digits>0)
 {
  pi.Append(".");
  for(int i=0;i<digits;i+=9)
  {
   //...對數据的處理,這是一段耗時的代碼
   //通知UI線程去顯示進度,并立即返回工作線程.
   this.BeginInvoke(showProgress,new object[]{pi.ToString(),digits,i+digitCount});
  }
 }
}

3.同步調用与异步回調結合

delegate void CalcPiDelegate(int digits);
void calcButton_Click(object sender,EventArgs e)
{
 //...
 //
 CalcPiDelegate calcPi=new CalcPiDelegate(CalcPi);
 //同步調用,与calcPi.Invoke作用相同
 calcPi((int)this.decimalPlacesNumericUpDown.Value);
}
void ShowProgress(string pi,int totalDigits,int digitsSoFar)
{
 //确保當前處于UI線程
 Debug.Assert(this.InvokeRequired==false);
 
 //...這里一般寫与UI線程交互的代碼.以及一些簡短的數据處理.

}

delegate void ShowProgressDelegate(string pi,int totalDigits,int digitsSoFar);
void CalcPi(int digits)
{
 StringBuilder pi=new StringBuilder("3",digits+2);
 //准備顯示進度
 ShowProgressDelegate showProgress=new ShowProgressDelegate(ShowProgress);

 //當需要回顯消息時,就調用
 //通知UI線程去顯示初始進度,并立即返回工作線程.
 this.BeginInvoke(showProgress,new object[]{pi.ToString(),digits,0});
 if(digits>0)
 {
  pi.Append(".");
  for(int i=0;i<digits;i+=9)
  {
   //...對數据的處理,這是一段耗時的代碼
   //通知UI線程去顯示進度,并立即返回工作線程.
   this.BeginInvoke(showProgress,new object[]{pi.ToString(),digits,i+digitCount});
  }
 }
}

--4.异步調用与同步回調結合
delegate void CalcPiDelegate(int digits);
void calcButton_Click(object sender,EventArgs e)
{
 //...
 //
 CalcPiDelegate calcPi=new CalcPiDelegate(CalcPi);
 //异步調用
 calcPi.BeginInvoke(
  (int)this.decimalPlacesNumericUpDown.Value,//將此參數傳給CalcPi方法
  EndCalcPi,//當CalcPi結束時調用該方法
  calcPi);//此參數傳給EndCalcPi方法,好像一定要与委托名稱相同

}
void EndCalcPi(IAsyncResult result)
{
 //獲得結果,處理异常和清除資源
 try
 {
  CalcPiDelegate calcPi=(CalcPiDelegate)result.AsyncState;
  calcPi.EndInvoke(result);//調用EndInvoke
 }
 catch(Exception ex)
 {
  //EndCalcPi在工作者線程中執行
  //...如果需要回調UI線程,可使用同步回調或异步回調.
 }

}

void ShowProgress(string pi,int totalDigits,int digitsSoFar)
{
 //确保當前處于UI線程
 Debug.Assert(this.InvokeRequired==false);
 
 //...這里一般寫与UI線程交互的代碼.以及一些簡短的數据處理.

}
delegate void ShowProgressDelegate(string pi,int totalDigits,int digitsSoFar);
void CalcPi(int digits)
{
 StringBuilder pi=new StringBuilder("3",digits+2);
 //准備顯示進度
 ShowProgressDelegate showProgress=new ShowProgressDelegate(ShowProgress);

 //同步回調
 this.Invoke(showProgress,new object[]{pi.ToString(),digits,0});
 if(digits>0)
 {
  pi.Append(".");
  for(int i=0;i<digits;i+=9)
  {
   //...對數据的處理,這是一段耗時的代碼
   //同步回調
   this.Invoke(showProgress,new object[]{pi.ToString(),digits,i+digitCount});
  }
 }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值