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个显示的问题
}
最终效果:


浙公网安备 33010602011771号