winform 异步读取数据 小实例
这几天对突然对委托事件,异步编程产生了兴趣,大量阅读前辈们的代码后自己总结了一下。
主要是实现 DataTable的导入导出,当然可以模拟从数据库读取大量数据,这可能需要一定的时间,然后 再把数据导入到xml excel等。做了个小实例模拟了一下。特此帖出来以便日后查阅
先上效果图
然后贴上代码
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Diagnostics; 6 using System.Drawing; 7 using System.Linq; 8 using System.Runtime.Remoting.Messaging; 9 using System.Text; 10 using System.Threading; 11 using System.Windows.Forms; 12 13 namespace AsyncCallBack用法 14 { 15 public partial class FrmMain : Form 16 { 17 public FrmMain() 18 { 19 InitializeComponent(); 20 } 21 22 /// <summary> 23 /// 定义字段来存放读取到的数据 24 /// </summary> 25 DataTable dtInput = new DataTable(); 26 /// <summary> 27 /// 定义字段来存放写入的数据 28 /// </summary> 29 DataTable dtOutput = new DataTable(); 30 31 /// <summary> 32 /// 按钮单击事件 33 /// </summary> 34 /// <param name="sender"></param> 35 /// <param name="e"></param> 36 private void button1_Click(object sender, EventArgs e) 37 { 38 //先记录下时间 39 Stopwatch sw = Stopwatch.StartNew(); 40 //定义一个委托变量用来生成数据 41 Func<int, DataTable> func = GetTableData; 42 //异步开始 43 func.BeginInvoke(100, ImproveTable, null); 44 //记录时间 45 sw.Stop(); 46 //测试异步会不会卡UI界面 47 string times = sw.ElapsedMilliseconds.ToString(); 48 MessageBox.Show("点按钮到我弹出来总共用了"+times+"毫秒证明异步调用不会卡到主线程"); 49 } 50 51 /// <summary> 52 /// 这是回调函数 53 /// </summary> 54 /// <param name="iar"></param> 55 public void ImproveTable(IAsyncResult iar) 56 { 57 int i = 0; 58 if(iar!=null) 59 { 60 AsyncResult ar = iar as AsyncResult; 61 Func<int, DataTable> func = ar.AsyncDelegate as Func<int, DataTable>; 62 dtInput = func.EndInvoke(iar); 63 64 DataTable dtCopy = dtInput.Copy(); 65 dtOutput = dtInput.Clone(); 66 67 //防止跨线程访问控件,利用lambda表达式,也可以直接定义一个委托实例去完成他 68 if (progressBar.InvokeRequired) 69 { 70 progressBar.Invoke(new Action(() => { progressBar.Maximum = dtCopy.Rows.Count; })); 71 } 72 else 73 { 74 progressBar.Maximum = dtCopy.Rows.Count; 75 } 76 77 foreach (DataRow dr in dtCopy.Rows) 78 { 79 Thread.Sleep(100); 80 i++; 81 dtOutput.ImportRow(dr); 82 83 //防止跨线程访问控件, 84 if (progressBar.InvokeRequired) 85 { 86 progressBar.Invoke(new Action(() => { progressBar.Value = i; })); 87 } 88 else 89 { 90 progressBar.Value = i; 91 } 92 93 94 if (label1.InvokeRequired) 95 { 96 label1.Invoke(new Action(() => { label1.Text = ((i) != dtCopy.Rows.Count) ? "正在写入数据,写入行数" + i.ToString() + "..." : "数据写入完毕"; })); 97 } 98 else 99 { 100 label1.Text = ((i) != dtCopy.Rows.Count) ? "正在写入数据,写入行数" + i.ToString() + "..." : "数据写入完毕"; 101 } 102 } 103 } 104 MessageBox.Show(String.Format("我复制到了{0}行数据,我睡了{1}秒",dtOutput.Rows.Count.ToString(),(i/2).ToString())); 105 } 106 107 /// <summary> 108 /// 生成数据的方法 109 /// </summary> 110 /// <param name="rows"></param> 111 /// <returns></returns> 112 public DataTable GetTableData(int rows) 113 { 114 115 string strColumns = "ID,Name,Gender"; 116 string[] strCol = strColumns.Split(new char[] { ',' }); 117 118 DataTable dt = new DataTable(); 119 120 for (int i = 0; i < strCol.Length; i++) 121 { 122 dt.Columns.Add(strCol[i]); 123 } 124 125 //防止跨线程访问控件, 126 if(progressBar.InvokeRequired) 127 { 128 progressBar.Invoke(new Action(()=>{progressBar.Maximum=rows;})); 129 } 130 else 131 { 132 progressBar.Maximum = rows; 133 } 134 135 Random r = new Random(); 136 for (int i = 0; i < rows; i++) 137 { 138 Thread.Sleep(100); 139 140 141 string id = r.Next(0, 100).ToString() + "ID"; 142 string name = r.Next(200, 300).ToString() + "Name"; 143 string gender = r.Next(4000, 111111).ToString() + "Gender"; 144 145 dt.Rows.Add(new string[] { id, name, gender }); 146 147 //防止跨线程访问控件, 148 if (progressBar.InvokeRequired) 149 { 150 progressBar.Invoke(new Action(() => { progressBar.Value = i+1; })); 151 } 152 else 153 { 154 progressBar.Value = i+1 ; 155 } 156 157 158 if (label1.InvokeRequired) 159 { 160 label1.Invoke(new Action(() => { label1.Text = ((i+1)!= rows) ? "正在读取数据读取行数" + i.ToString() + "..." : "数据读取完毕"; })); 161 } 162 else 163 { 164 label1.Text = ((i+1) != rows) ? "正在读取数据读取行数" + i.ToString() + "..." : "数据读取完毕"; 165 } 166 } 167 return dt; 168 } 169 } 170 }
关于代码的分析有时间再写。
代码里面主要用到了BeginInvoke EndInvoke 关于 EndInvoke放在回调函数里面的代码是从博友那里学的。
关于用lambda表达式更新ProgressBar控件的方法也是从博友那里学的。
个人感觉写比冗余,等以后对.net 的熟练度提高以后看这些代码可能会感觉很小白。
如果有错误之处,请博友们指正,以防误导新人,同时也能提醒我。
-----------------------------唯有自身强大,才能不惧外物。
http://www.cnblogs.com/lclblog/