• WinForm组件之多线程组件


    本来已经写完了,但我以前的一个同事说看了两遍都没怎么看懂我要说什么,受刺激了,只好推倒重写。
    在WinForm开发中,耗时操作经常会使界面失去响应,比如查询数据、调用远端WebService等。为了不让界面失去响应,一般会采用多线程来处理或者是借助控件,比如BackgroundWorker,在Worker执行耗时操作时,界面上一般出于用户体验的考虑,还要加上等待提示,比如一个沙漏的图片或是类似“正在操作,请等待。。。。。。”的文字提示。
    我写了个组件,针对以上情况进行了简单的封装,力求做到最简化,易于使用,使得在调用时尽量不需要考虑Thread、跨线程访问UI控件、等待提示的处理等等。
    我把耗时操作分为了两种,一种是获取数据后绑定DataGridView,另一种是获取数据后进行其它处理,针对前者,在调用时只需要将获取数据的代码(以委托形式)和需要绑定的DataGridView控件一起传入组件即可,针对后者,需要将获取数据的代码(以委托形式)和获取数据后进行其它处理的代码(以委托形式)传入组件即可,需要说明的是,获取数据的代码应避免访问界面上的控件,获取数据后进行其它处理的代码由于是在主线程(UI线程)上跑所以可以自由访问界面控件。
    我把提示又分为了两种,一种是组件自带的,组件会为当前窗口动态生成一个Label,用于提示之用,另一种是用户自定义的,用户如果觉得自带的提示实在不雅观,可以自己在界面上做一个Panel,然后传入组件,组件会在Worker执行时将其显示并在执行完毕后将其隐藏。

    View Code
      1 using System;
    2 using System.Collections.Generic;
    3 using System.ComponentModel;
    4 using System.Data;
    5 using System.Drawing;
    6 //using System.Linq;
    7 using System.Text;
    8 using System.Windows.Forms;
    9
    10 using System.Threading;
    11
    12 namespace DReBorn.Suede.Tests
    13 {
    14 public partial class WorkerHelperTests : Form
    15 {
    16 //使用前先在窗口类中声明、实例化这个组件的变量,WorkerHelper表明Worker中获取的数据是DataTable形式,WorkerHelper<T>表明Worker中获取的数据是List<T>形式。
    17 private WorkerHelper worker = new WorkerHelper();
    18 private WorkerHelper<Product> workerGenerics = new WorkerHelper<Product>();
    19
    20 private DataTable GetData()
    21 {
    22 DataTable dt = new DataTable();
    23 dt.Columns.Add(new DataColumn("col1"));
    24 dt.Columns.Add(new DataColumn("col2"));
    25 dt.Columns.Add(new DataColumn("col3"));
    26
    27 for (int i = 1; i <= 100; i++)
    28 {
    29 DataRow dr = dt.NewRow();
    30 dr["col1"] = i.ToString() + "col1";
    31 dr["col2"] = i.ToString() + "col2";
    32 dr["col3"] = i.ToString() + "col3";
    33
    34 dt.Rows.Add(dr);
    35 }
    36
    37 return dt;
    38 }
    39
    40 private List<Product> GetDataGenerics()
    41 {
    42 List<Product> list = new List<Product>();
    43
    44 for (int i = 1; i <= 100; i++)
    45 {
    46 Product stu = new Product();
    47 stu.S1 = i.ToString() + "s1";
    48 stu.S2 = i.ToString() + "s2";
    49 stu.S3 = i.ToString() + "s3";
    50
    51 list.Add(stu);
    52 }
    53
    54 return list;
    55 }
    56
    57 public WorkerHelperTests()
    58 {
    59 InitializeComponent();
    60 dataGridView1.AutoGenerateColumns = false;
    61 }
    62
    63 private void button1_Click(object sender, EventArgs e)
    64 {
    65 //首先初始化(Init),这个主要是给传入的窗口加上提示控件。然后传入要在Worker中运行的逻辑和获取数据完毕后绑定的DataGridView。
    66 worker.Init(this);
    67 worker.Action(() => {
    68 DataTable dt = GetData();
    69 Thread.Sleep(1000 * 10);
    70 worker.DataSource = dt;
    71 }, dataGridView1);
    72 }
    73
    74 private void button2_Click(object sender, EventArgs e)
    75 {
    76 //这是另外一种调用形式,如果嫌自动生成的提示实在不美观,可以自己写个Panel,里面放上自己满意的内容,然后指定它来作为提示控件。
    77 worker.Init(this, panel1);
    78 worker.Action(() => {
    79 DataTable dt = GetData();
    80 Thread.Sleep(1000 * 10);
    81 worker.DataSource = dt;
    82 }, dataGridView1);
    83 }
    84
    85 private void button3_Click(object sender, EventArgs e)
    86 {
    87 //这种调用形式,主要是在获取数据后,不进行绑定,而要进行其它的操作,比如获取数据后导出为一份Excel文档等。
    88 worker.Action(() => {
    89 DataTable dt = GetData();
    90 Thread.Sleep(1000 * 10);
    91 worker.DataSource = dt;
    92 }, () => {
    93 MessageBox.Show(worker.DataSource.Rows.Count.ToString());
    94 });
    95 }
    96
    97 private void button6_Click(object sender, EventArgs e)
    98 {
    99 workerGenerics.Init(this);
    100 workerGenerics.Action(() => {
    101 Thread.Sleep(1000 * 10);
    102 workerGenerics.DataSource = GetDataGenerics();
    103 }, dataGridView2);
    104 }
    105
    106 private void button5_Click(object sender, EventArgs e)
    107 {
    108 workerGenerics.Init(this, panel2);
    109 workerGenerics.Action(() => {
    110 Thread.Sleep(1000 * 10);
    111 workerGenerics.DataSource = GetDataGenerics();
    112 }, dataGridView2);
    113 }
    114
    115 private void button4_Click(object sender, EventArgs e)
    116 {
    117 workerGenerics.Action(() => {
    118 Thread.Sleep(1000 * 10);
    119 workerGenerics.DataSource = GetDataGenerics();
    120 }, () => {
    121 MessageBox.Show(workerGenerics.DataSource[0].S1);
    122 });
    123 }
    124 }
    125
    126 public class Product
    127 {
    128 public string S1 { get; set; }
    129 public string S2 { get; set; }
    130 public string S3 { get; set; }
    131 }
    132 }

    以上为获取数据是DataTable形式的情况,至于泛型版本就不赘述了,感兴趣的童鞋可以看看源码,Very Simple。上截图。

    自动生成的提示控件


    自定义的Panel作为提示控件(粉色区域)


    获取数据后进行自定义操作(此例中为报告行数)。 

    源码

  • 相关阅读:
    先验概率与后验概率、贝叶斯区别与联系
    Linux查看登录用户记录信息
    Discuz常见小问题-如何关闭验证码
    word文档的图片怎么保存到CKEditor上
    word文档的图片怎么保存到umeditor上
    word文档的图片怎么保存到百度Web编辑器上
    word文档的图片怎么保存到百度编辑器上
    word文档的图片怎么保存到百度ueditor上
    word图文混排复制到CuteEditor图片不显示
    word图文混排复制到eWebEditor图片不显示
  • 原文地址:https://www.cnblogs.com/DReBorn/p/2405690.html
Copyright © 2020-2023  润新知