主要是對一個過程需要的時間很長執行時會出現界面假死的情況
方法1:
Application.DoEvents(),這種方法當你拖動窗體時,界面不會假死。但在你拖動時代碼不再執行,也就是阻塞了,當你不再控制窗體時會繼續執行,其實這還是一個單線程
for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { textBox1.Text = i.ToString() + " " + j.ToString(); Application.DoEvents(); } }
方法2:多線程
2.1:取消控件跨線程檢測(不推薦有時會出現一些莫名奇妙的錯誤如控件不能加載等問題)
2.1.1取消窗體內控件的跨線程檢查(單個控件取消也可以)
public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false;//干掉檢測 不再檢測跨線程 }
2.1.2新建線程實現跨線程訪問
/// <summary> /// 新建線程並執行 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { ThreadStart thStart = new ThreadStart(Pro);//threadStart委托 Thread thread = new Thread(thStart); thread.Priority = ThreadPriority.Highest; thread.IsBackground = true; //關閉窗體繼續執行 thread.Start(); } public void Pro() { for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { textBox1.Text = j.ToString(); } } }
2.2:主線程中操作(推薦)
2.2.1 不用取消跨線程訪問
/// <summary> /// 新建線程並執行 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { ThreadStart thStart = new ThreadStart(Pro);//threadStart委托 Thread thread = new Thread(thStart); thread.Priority = ThreadPriority.Highest; thread.IsBackground = true; //關閉窗體繼續執行 thread.Start(); } public void Pro() { for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { if (textBox1.InvokeRequired)//不同線程訪問了 textBox1.Invoke(new Action<TextBox, string>(SetTxtValue), textBox1, j.ToString());//跨線程了 else//同線程直接賦值 textBox1.Text = j.ToString(); } } } private void SetTxtValue(TextBox txt, string value) { txt.Text = value; }
注:多個線程同時訪問一個方法時 需要鎖定
public static readonly object obj = new object(); public void Pro() { //lock(obj){}=Monitor.Enter(obj) Monitor.Exit(obj) lock (obj) { for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { if (textBox1.InvokeRequired)//不同線程訪問了 textBox1.Invoke(new Action<TextBox, string>(SetTxtValue),
textBox1, j.ToString());//跨線程了 else//同線程直接賦值 textBox1.Text = j.ToString(); } } } }
3.窗體與自定義類之間的多線程操作(適用數據量大查詢速度慢時 讓數據在新線程中查詢 防主線程卡死)
3.1自定義類中定義事件,並定義各事件執行的步驟方法
3.2窗體中實現類,並生成類各事件,在多線程中執行自定義類的步驟方法
3.3 代碼3.1

public class WeiTuo { public int count { get; set; } public event EventHandler StartEvent; public event EventHandler MidEvent; public event EventHandler EndEvent; public event EventHandler EEvent; public void ExecEvent() { try { using (SqlConnection con = new SqlConnection("server=.;uid=sa;pwd=123;database=oa")) { using (SqlDataAdapter adp = new SqlDataAdapter("select * from a", con)) { DataTable dt = new DataTable(); adp.Fill(dt); StartEvent(dt.Rows.Count, null); for (int i = 0; i < dt.Rows.Count; i++) { a ai = new a() { ID = (int)dt.Rows[i]["id"], Code = dt.Rows[i]["cCode"].ToString() } ; MidEvent(ai, null); } EndEvent(dt.Rows.Count, null); } } } catch (Exception e) { EEvent(e.Message, null); } } } public class a { public int ID { get; set; } public String Code { get; set; } = ""; }
3.4 代碼3.2

private void button6_Click(object sender, EventArgs e) { WeiTuo wt = new WeiTuo(); wt.StartEvent += Wt_StartEvent; wt.MidEvent += Wt_MidEvent; wt.EndEvent += Wt_EndEvent; wt.EEvent += Wt_EEvent; Thread th = new Thread(wt.ExecEvent); th.Start(); } //特殊委托 action private void Wt_StartEvent(object sender, EventArgs e) { Action<string> setLVItem = (s) => { listView1.Items.Add(s); }; this.Invoke(setLVItem, sender.ToString()); } //特殊委托 action private void Wt_MidEvent(object sender, EventArgs e) { Action<string> setLVItem = (s) => { listView1.Items.Add(s); }; this.Invoke(setLVItem, ((a)sender).Code); } #region 委托實現 private void Wt_EndEvent(object sender, EventArgs e) { this.Invoke(new setLVItem(setEndValue), "成功"); } delegate void setLVItem(string s); void setEndValue(string s) { MessageBox.Show(s); } #endregion private void Wt_EEvent(object sender, EventArgs e) { Action<string> ShowBox = (s) => { MessageBox.Show(s); }; this.Invoke(ShowBox, sender.ToString()); }
3.5 結果如下圖
task任務與thread大同小異
使用時 盡量少的讓控件跨線程 可通過ref 或 out 對參數傳出 檢測線程結束 再給控件賦值
也可用task的wait方法
4 異步回調

private void button1_Click(object sender, EventArgs e) { Func<int, int, int> Sum = (i, j) => { Thread.Sleep(3000); return i + j; }; listView1.Items.Add("開始"); IAsyncResult iar = Sum.BeginInvoke(1, 2, CallbackWhenDone, "我是測試"); listView1.Items.Add("over"); } private void CallbackWhenDone(IAsyncResult iar) { AsyncResult ar = (AsyncResult)iar; Func<int, int, int> f = (Func<int, int, int>)ar.AsyncDelegate; Action<ListView> a = (lv) => { lv.Items.Add(ar.AsyncState.ToString()); lv.Items.Add(f.EndInvoke(iar).ToString()); }; this.Invoke( a,listView1); }