我有问题。 因此,我构建了一个应用程序,该应用程序以图表和datagridview的形式显示数据。他们都反应灵敏。这意味着它们将重新缩放并随数据一起移动。我猜这需要一些计算能力。
同时我有定时器,导致所有定时器都以f = 4Hz周期性运行。
现在:当我运行该应用程序并打开定期读数时,该应用程序在调整大小时会挂起。我该如何预防?
我已经尝试使用backgroundworker,但是在访问在“其他线程”(如VS所说)中声明(也使用)的datagridview和chart时,就会出现问题。
所以。如何预防? 也许我应该以其他方式利用背景工作者?
我与后台工作人员的尝试
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Control.CheckForIllegalCrossThreadCalls = false;
if (!GetConnectionStatus())
{
stop_ticking();
if (MessageBox.Show("Device not connected", "Connection status", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry)
messaging();
else
return;
}
// TEMP READ
Read_temp(tlist);
float[] t = new float[3];
float[] r = new float[3];
float[] av = new float[1];
float[] st = new float[1];
// TEMP IMPORT
tlist.Give_current_temp(t, r, av, st);
string time_stamp = tlist.Give_current_time();
rows_nr++;
// ADDING TO GRID
dataGridView1.Invoke(new Action(() => { dataGridView1.Rows.Add(new object[] { rows_nr, time_stamp, av[0], st[0], (t[0]).ToString(), (r[0]).ToString(), (t[1]).ToString(), (r[1]).ToString(), (t[2]).ToString(), (r[2]).ToString() }); }));
//dataGridView1.Rows.Add(new object[] { rows_nr, time_stamp, av[0], st[0], (t[0]).ToString(), (r[0]).ToString(), (t[1]).ToString(), (r[1]).ToString(), (t[2]).ToString(), (r[2]).ToString() });
dataGridView1.Invoke(new Action(() => { dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1; }));
//dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1;
// ADDING TO CHART
for (int i = 0; i < 3; i++)
chart1.Invoke(new Action(() => { chart1.Series[series_names[i]].Points.AddXY((rows_nr), (t[i])); }));
//chart1.Series[series_names[i]].Points.AddXY((rows_nr), (t[i]));
chart1.Invoke(new Action(() => { chart1.Series["average"].Points.AddXY((rows_nr), (av[0])); }));
//chart1.Series["average"].Points.AddXY((rows_nr), (av[0]));
//chart1.Series["std1"].Points.AddXY((rows_nr), (av[0] + Math.Abs(st[0])));
//chart1.Series["std2"].Points.AddXY((rows_nr), (av[0] - Math.Abs(st[0])));
// MOVING CHART
if (chart1.Series[series_names[0]].Points.Count > nr_of_noints_graph)
{
for (int i = 0; i < 3; i++)
chart1.Series[series_names[i]].Points.RemoveAt(0);
chart1.Series["average"].Points.RemoveAt(0);
//chart1.Series["std1"].Points.RemoveAt(0);
//chart1.Series["std2"].Points.RemoveAt(0);
chart1.ChartAreas[0].AxisX.Minimum = rows_nr - (nr_of_noints_graph - 1);
chart1.ChartAreas[0].AxisX.Maximum = rows_nr;
dataGridView1.Rows.RemoveAt(0);
}
chart1.Invoke(new Action(() => { chart1.ChartAreas[0].RecalculateAxesScale(); }));
//chart1.ChartAreas[0].RecalculateAxesScale();
}
答案 0 :(得分:1)
请查看后台工作人员样本。你这样做是不对的。后台工作程序DoWork不应调用UI控件,并且应在非UI线程中执行,它应执行耗时的计算并调用worker.ReportProgress()。虽然ReportProgress方法可以访问UI控件,但是此方法中的代码在UI线程中执行。 在添加/删除点时,某些图表控件比较笨拙。可能因为挂住而挂起。减少更新的频率(例如1秒1秒钟),然后查看其是否挂起。
在秒表中包装操作,并使用System.Diagnostics.Debug.WriteLine跟踪执行流程和操作时间。
移动图表部件不起作用,因为它在没有调用UI线程的情况下访问了非ui线程中的UI元素。
如果不是背景工作者,我会这样写:
// MOVING CHART
chart1.Invoke(new Action(()=>
{
if (chart1.Series[series_names[0]].Points.Count > nr_of_noints_graph)
{
for (int i = 0; i < 3; i++)
chart1.Series[series_names[i]].Points.RemoveAt(0);
chart1.Series["average"].Points.RemoveAt(0);
chart1.ChartAreas[0].AxisX.Minimum = rows_nr - (nr_of_noints_graph - 1);
chart1.ChartAreas[0].AxisX.Maximum = rows_nr;
}
}
));
我也不会将每个操作包装在单独的调用中。
对于您的问题,没有足够的信息来检测出问题所在,请提供最小的可运行样本以证明问题所在。
答案 1 :(得分:0)
如 @Access Denied 所述,您应该改善GUI和后台工作线程之间的分离。您可以在后台线程上执行// TEMP READ
和// TEMP IMPORT
操作,并在所有数据准备就绪后通过.Invoke
方法对GUI线程进行调用。阅读"How to: Make Thread-Safe Calls to Windows Forms Controls"文章以了解更多信息。
在DataGridView
中添加/更新数据时,请使用.BeginUpdate
/ .EndUpdate
方法来防止控件更新,直到刷新所有数据。
其他方法是使用Virtual mode。如果网格中有很多项目,这将特别有用。
答案 2 :(得分:0)
在使用后台线程时,您不得创建,更新甚至访问任何UI元素。
您需要将检索数据的工作(较慢的部分)与更新图表的工作(非常快)分开。
这实际上归结为这样:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (!GetConnectionStatus())
{
stop_ticking();
return;
}
// TEMP READ
Read_temp(tlist);
float[] t = new float[3];
float[] r = new float[3];
float[] av = new float[1];
float[] st = new float[1];
// TEMP IMPORT
tlist.Give_current_temp(t, r, av, st);
string time_stamp = tlist.Give_current_time();
rows_nr++;
chart1.Invoke(new Action(() =>
{
// ADDING TO GRID
dataGridView1.Rows.Add(new object[] { rows_nr, time_stamp, av[0], st[0], (t[0]).ToString(), (r[0]).ToString(), (t[1]).ToString(), (r[1]).ToString(), (t[2]).ToString(), (r[2]).ToString() });
dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1;
// ADDING TO CHART
for (int i = 0; i < 3; i++)
{
chart1.Series[series_names[i]].Points.AddXY((rows_nr), (t[i]));
}
chart1.Series["average"].Points.AddXY((rows_nr), (av[0]));
// MOVING CHART
if (chart1.Series[series_names[0]].Points.Count > nr_of_noints_graph)
{
for (int i = 0; i < 3; i++)
{
chart1.Series[series_names[i]].Points.RemoveAt(0);
}
chart1.Series["average"].Points.RemoveAt(0);
chart1.ChartAreas[0].AxisX.Minimum = rows_nr - (nr_of_noints_graph - 1);
chart1.ChartAreas[0].AxisX.Maximum = rows_nr;
dataGridView1.Rows.RemoveAt(0);
}
chart1.ChartAreas[0].RecalculateAxesScale();
}));
}
如果必须显示一个MessageBox,则还需要调用它。