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 的熟练度提高以后看这些代码可能会感觉很小白。

 

如果有错误之处,请博友们指正,以防误导新人,同时也能提醒我。

posted @ 2015-08-13 16:01  Langu  阅读(763)  评论(0编辑  收藏  举报