C#--BackgroundWorker简单使用--Chart展示数据库查询的数据

以下是学习笔记,感谢原作者的分享

https://blog.csdn.net/songkexin/article/details/6178540

https://www.jb51.net/article/138586.htm

  在 WinForms 中,有时要执行耗时的操作,在该操作未完成之前操作用户界面,会导致用户界面停止响应。解决的方法就是新开一个线程,把耗时的操作放到线程中执行,这样就可以在用户界面上进行其它操作。

新建线程可以用 Thread 类,可以实现多线程同时操作,简单的可以通过 BackgroundWorker 类实现。

  BackgroundWorker 类允许您在单独的专用线程上运行操作。 耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。 如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用

BackgroundWorker 类方便地解决问题。

常用方法:

1.RunWorkerAsync
开始执行后台操作。引发 DoWork 事件

2.CancelAsync
请求取消挂起的后台操作。
注意:这个方法是将 CancellationPending 属性设置为 true,并不会终止后台操作。在后台操作中要检查 CancellationPending 属性,来决定是否要继续执行耗时的操作。

3.ReportProgress
引发 ProgressChanged 事件。

常用属性:

1.CancellationPending
指示应用程序是否已请求取消后台操作。
只读属性,默认为 false,当执行了 CancelAsync 方法后,值为 true。

2.WorkerSupportsCancellation
指示是否支持异步取消。要执行 CancelAsync 方法,需要先设置该属性为 true。

3.WorkerReportsProgress
指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。

常用事件:

1.DoWork
调用 RunWorkerAsync 方法时发生。

2.RunWorkerCompleted
后台操作已完成、被取消或引发异常时发生。

3.ProgressChanged
调用 ReportProgress 方法时发生。

 

在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。


如果想在 DoWork 事件处理程序中和用户界面的控件通信,可在用 ReportProgress 方法。
ReportProgress(int percentProgress, object userState),可以传递一个对象。


ProgressChanged 事件可以从参数 ProgressChangedEventArgs 类的 UserState 属性得到这个信息对象。

简单的程序用 BackgroundWorker 比 Thread 方便,Thread 中和用户界面上的控件通信比较麻烦,需要用委托来调用控件的 Invoke 或 BeginInvoke 方法,没有 BackgroundWorker 方便。

有2点需要注意的:

   1、由于DoWork事件内部的代码运行在非UI线程之上,确保在 DoWork 事件处理程序中不操作任何用户界面对象。 而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。

   2、BackgroundWorker 事件不跨 AppDomain 边界进行封送处理。 请不要使用 BackgroundWorker 组件在多个 AppDomain 中执行多线程操作。

实例应用:查询数据库的数据用Chart展示

【1】BackgroundWorker使用步骤【1】:声明一个BackgroundWorker

        //BackgroundWorker使用步骤【1】:声明一个BackgroundWorker
        BackgroundWorker backgroundWorker = new BackgroundWorker();

  

【2】BackgroundWorker使用步骤【2】:绑定事件

  窗体加载的时候

            //BackgroundWorker使用步骤【2】:绑定事件
            backgroundWorker.DoWork += BackgroundWorkerDowork;
            backgroundWorker.RunWorkerCompleted += BackgroundWorkerRunWorkerCompleted;

  

【3】BackgroundWorker使用步骤【3】:Dowork事件(调用 RunWorkerAsync 方法时发生。)

        //BackgroundWorker使用步骤【3】:Dowork事件(调用 RunWorkerAsync 方法时发生。)
        private void BackgroundWorkerDowork(object sender, DoWorkEventArgs e)
        {
            //DoWork事件处理函数通过参数 e 的Argument属性获取参数
            List<DateTime> timelist = (List<DateTime>)e.Argument;//异步执行的参数,因为已经知道是List<DateTime>类型,所以强制转换
            DataTable dt = new DataTable();

            string sql = "select * from mydata where FDateTime >=" + "format('" + timelist[0].ToString() + "')" + "and FDateTime <=" + "format('" + timelist[1].ToString() + "')" + "and PsetName =" + "'" + psetNo + "'" + "order by ID";
            dt = this.myaccess.SelectToDataTable(sql);

            e.Result = dt;
        }

  

【4】BackgroundWorker使用步骤【4】:RunWorkerCompleted事件(当DoWork事件处理完成之后,将会触发该事件)

        //BackgroundWorker使用步骤【4】:RunWorkerCompleted事件(当DoWork事件处理完成之后,将会触发该事件)
        private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            DataTable dt = (DataTable) e.Result;//e.Result 获取异步操作结果的值,即DoWork事件中,Result设置的值
            dtSearchData = dt;

            #region 拧紧趋势曲线显示


            #region 测试1:没有解决X轴时间不连续,X轴刻度不均分的问题

            //this.chart3.DataSource = dt;
            //this.chart3.Series["CPK"].XValueMember = "FDateTime";//这个FDateTime是时间格式,X轴刻度不是均分的
            ////this.chart1.Series["实时趋势"].XValueMember = "FAngle";//这个FAngle不是时间格式的,X轴刻度是等间距的
            //this.chart3.Series["CPK"].YValueMembers = "FTorque";

            #endregion

            #region 测试2:没有解决X轴时间不连续,X轴刻度不均分的问题

            //for (int i = 0; i < dt.Rows.Count; i++)
            //{
            //    chart3.Series[0].Points.AddXY(dt.Rows[i]["FDateTime"], dt.Rows[i]["FTorque"]);
            //}

            #endregion

            #region 测试3:解决X轴时间不连续,X轴刻度不均分的问题

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                chart1.Series[0].Points.AddXY(dt.Rows[i]["FDateTime"].ToString(), dt.Rows[i]["FTorque"].ToString());
            }

            #endregion

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                chart2.Series[0].Points.AddXY(dt.Rows[i]["FDateTime"].ToString(), dt.Rows[i]["FTorque"].ToString());
            }
            #endregion

            #region CPK计算显示

            List<float> floatList = new List<float>();

            for (int i = 1; i < dt.Rows.Count; i++)
            {
                string strTorque = dt.Rows[i]["FTorque"].ToString(); //没有包含中文字符
                if (!StringHelper.HasChinese(strTorque)) //如果没有中文
                {
                    floatList.Add(Convert.ToSingle(strTorque));
                }
            }

            float[] floatArray = new float[floatList.Count];
            floatArray = floatList.ToArray();

            try
            {
                this.txt_torqueMax.Text = dt.Rows[0]["FTorqueMax"].ToString();//如果dt没收数据,这里会报错
                this.txt_torqueMin.Text = dt.Rows[0]["FTorqueMin"].ToString();
            }
            catch (Exception)
            {
                MessageBox.Show("当前程序号没有数据");
            }

            try
            {
                UpperLimit = Convert.ToSingle(this.txt_torqueMax.Text.ToString());
                LowerLimit = Convert.ToSingle(this.txt_torqueMin.Text.ToString());
            }
            catch 
            {
                
                return;
            }

            float f = new CpkHepler().getCPK(floatArray, UpperLimit, LowerLimit);
            this.lbl_cpk1.Text = f.ToString();

            #endregion

        }

  

【5】BackgroundWorker使用步骤【5】:启动worker异步操作

  按钮点击事件

        //查询按钮 开始查询
        private void btn_query_Click(object sender, EventArgs e)
        {
            psetNo = this.cmb_psetNo.Text.Trim();
            this.cmb_trendType.SelectedIndex = 1;//
            this.timer1.Enabled = false;//停止timer1的实时更新
            this.btn_Update.Text = "开始更新";

            DateTime t1 = Convert.ToDateTime(this.dtp_start.Text);
            DateTime t2 = Convert.ToDateTime(this.dtp_end.Text);
            if (t1 > t2)
            {
                MessageBox.Show("开始时间必须大于结束时间", "查询提示");
                return;
            }

            TimeSpan ts = t2 - t1;
            if (ts.TotalHours > 6)
            {
                MessageBox.Show("查询范围太多", "查询提示");
                return;
            }
            List<DateTime> time = new List<DateTime>(){t1,t2};

            //BackgroundWorker使用步骤【5】:启动worker异步操作
            if (!backgroundWorker.IsBusy)//如果BackgroundWorker使用步骤不在异步运行
            {
                backgroundWorker.RunWorkerAsync(time);//RunWorkerAsync方法让worker开始工作,调用DoWork方法
            }
        }

  

【6】BackgroundWorker使用步骤【6】:取消操作

  窗体关闭的时候

        private void btn_close_Click(object sender, EventArgs e)
        {
            //BackgroundWorker使用步骤【6】:取消操作
            if (backgroundWorker.WorkerSupportsCancellation == true)
            {
                backgroundWorker.CancelAsync();//请求取消挂起的后台操作。调用该方法将使BackgroundWorker.CancellationPending属性设置为True。
                //backgroundWorker.CancelAsync()并不会终止后台操作。在后台操作中要检查 CancellationPending 属性,来决定是否要继续执行耗时的操作。
            }
            this.Dispose();
        }

  

Chart控件初始化:

        private void InitChart()
        {
            chart1.Series.Clear();
            ChartHelper.AddSeries(chart1, "曲线图", SeriesChartType.Line, Color.FromArgb(100, 46, 199, 201), Color.White, true,true);
            ChartHelper.SetTitle(chart1, "工具1", new Font("微软雅黑", 12), Docking.Bottom, Color.FromArgb(46, 199, 201));
            ChartHelper.SetStyle(chart1, Color.Transparent, Color.White);
            ChartHelper.SetLegend(chart1, Docking.Top, StringAlignment.Center, Color.Transparent, Color.White);
            ChartHelper.SetXY(chart1, "时间", "扭矩.Nm", StringAlignment.Far, Color.White, Color.White, AxisArrowStyle.None);
            this.chart1.ChartAreas[0].AxisX.MajorGrid.Enabled = false;

            chart1.Series["曲线图"].BorderWidth = 3;
            chart1.ChartAreas[0].AxisX.Enabled = AxisEnabled.False;//不显示X轴坐标

            chart2.Series.Clear();
            ChartHelper.AddSeries(chart2, "曲线图", SeriesChartType.Line, Color.FromArgb(100, 46, 199, 201), Color.White, true,true);
            ChartHelper.SetTitle(chart2, "工具2", new Font("微软雅黑", 12), Docking.Bottom, Color.FromArgb(46, 199, 201));
            ChartHelper.SetStyle(chart2, Color.Transparent, Color.White);
            ChartHelper.SetLegend(chart2, Docking.Top, StringAlignment.Center, Color.Transparent, Color.White);
            ChartHelper.SetXY(chart2, "时间", "扭矩.Nm", StringAlignment.Far, Color.White, Color.White, AxisArrowStyle.None);
            this.chart2.ChartAreas[0].AxisX.MajorGrid.Enabled = false;

            chart2.Series["曲线图"].BorderWidth = 3;
            chart2.ChartAreas[0].AxisY.IsStartedFromZero = false;//Y轴自适应
            chart2.ChartAreas[0].AxisX.Interval = 1; //设置X轴坐标的间隔为1,解决了/X轴间隔1个显示的问题

            chart3.Series.Clear();
            ChartHelper.AddSeries(chart3, "CPK", SeriesChartType.Line, Color.Lime, Color.FromArgb(109, 89, 71), true, true);
            ChartHelper.SetStyle(chart3, Color.Transparent, Color.White);
            ChartHelper.SetLegend(chart3, Docking.Top, StringAlignment.Far, Color.Transparent, Color.FromArgb(100, 128, 206));
            ChartHelper.SetXY(chart3, "", "", StringAlignment.Far, Color.FromArgb(100, 128, 206),
                Color.FromArgb(100, 128, 206), AxisArrowStyle.None);

            this.chart3.ChartAreas[0].AxisX.MajorGrid.Enabled = false;

            this.chart3.ChartAreas[0].AxisY.IsStartedFromZero = false;//Y轴自适应
            chart3.ChartAreas[0].AxisX.Interval = 1; //设置X轴坐标的间隔为1,解决了/X轴间隔1个显示的问题
        }

  

最终效果:

原文地址:https://www.cnblogs.com/baozi789654/p/14587166.html