c# - 如何暂时暂停实时数据图表的绘图更新
问题描述
我想要一个“暂停”图表的系列更新来做一些工作(就像我有一个按钮,当我点击它会暂停图表更新,然后当我点击恢复按钮时,它会更新所有暂停的系列点。
我知道
chart1.Series.SuspendUpdates();
但它似乎不适用于我。我使用 mschart 示例——实时数据(线程安全)。
这是完整的代码
public partial class RealTimeSample : Form
{
public RealTimeSample()
{
InitializeComponent();
}
private Thread addDataRunner;
private Random rand = new Random();
public delegate void AddDataDelegate();
public AddDataDelegate addDataDel;
private void RealTimeSample_Load(object sender, System.EventArgs e)
{
// create the Adding Data Thread but do not start until start button clicked
ThreadStart addDataThreadStart = new ThreadStart(AddDataThreadLoop);
addDataRunner = new Thread(addDataThreadStart);
// create a delegate for adding data
addDataDel += new AddDataDelegate(AddData);
}
/// Main loop for the thread that adds data to the chart.
/// The main purpose of this function is to Invoke AddData
/// function every 1000ms (1 second).
private void AddDataThreadLoop()
{
while (true)
{
chart1.Invoke(addDataDel);
Thread.Sleep(1000);
}
}
public void AddData()
{
DateTime timeStamp = DateTime.Now;
foreach (Series ptSeries in chart1.Series)
{
AddNewPoint(timeStamp, ptSeries);
}
}
/// The AddNewPoint function is called for each series in the chart when
/// new points need to be added. The new point will be placed at specified
/// X axis (Date/Time) position with a Y value in a range +/- 1 from the previous
/// data point's Y value, and not smaller than zero.
public void AddNewPoint(DateTime timeStamp, System.Windows.Forms.DataVisualization.Charting.Series ptSeries)
{
double newVal = 0;
if (ptSeries.Points.Count > 0)
{
newVal = ptSeries.Points[ptSeries.Points.Count - 1].YValues[0] + ((rand.NextDouble() * 2) - 1);
}
if (newVal < 0)
newVal = 0;
// Add new data point to its series.
chart1.Series.SuspendUpdates();
ptSeries.Points.AddXY(timeStamp.ToOADate(), rand.Next(10, 20));
chart1.Series.SuspendUpdates();
// remove all points from the source series older than 1.5 minutes.
double removeBefore = timeStamp.AddSeconds((double)(90) * (-1)).ToOADate();
//remove oldest values to maintain a constant number of data points
while (ptSeries.Points[0].XValue < removeBefore)
{
ptSeries.Points.RemoveAt(0);
}
chart1.ChartAreas[0].AxisX.Minimum = ptSeries.Points[0].XValue;
chart1.ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(ptSeries.Points[0].XValue).AddMinutes(2).ToOADate();
}
/// Clean up any resources being used.
protected override void Dispose(bool disposing)
{
if ((addDataRunner.ThreadState & ThreadState.Suspended) == ThreadState.Suspended)
{
addDataRunner.Resume();
}
addDataRunner.Abort();
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
private void startTrending_Click_1(object sender, EventArgs e)
{
// Disable all controls on the form
startTrending.Enabled = false;
// and only Enable the Stop button
stopTrending.Enabled = true;
// Predefine the viewing area of the chart
var minValue = DateTime.Now;
var maxValue = minValue.AddSeconds(120);
chart1.ChartAreas[0].AxisX.Minimum = minValue.ToOADate();
chart1.ChartAreas[0].AxisX.Maximum = maxValue.ToOADate();
// Reset number of series in the chart.
chart1.Series.Clear();
// create a line chart series
Series newSeries = new Series("Series1");
newSeries.ChartType = SeriesChartType.Line;
newSeries.BorderWidth = 2;
newSeries.Color = Color.OrangeRed;
newSeries.XValueType = ChartValueType.DateTime;
chart1.Series.Add(newSeries);
// start worker threads.
if (addDataRunner.IsAlive == true)
{
addDataRunner.Resume();
}
else
{
addDataRunner.Start();
}
}
private void stopTrending_Click_1(object sender, EventArgs e)
{
if (addDataRunner.IsAlive == true)
{
addDataRunner.Suspend();
}
// Enable all controls on the form
startTrending.Enabled = true;
// and only Disable the Stop button
stopTrending.Enabled = false;
}
}
编辑:
我发现只要您为 Axis 设置了 minmum 或 maximum 属性,即使您使用过,图表也会保持显示
chart1.Series.SuspendUpdates();
我打电话后必须删除这些线SuspendUpdates()
,现在我可以看到图表系列暂停
chart1.ChartAreas[0].AxisX.Minimum = ptSeries.Points[0].XValue;
chart1.ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(ptSeries.Points[0].XValue).AddMinutes(2).ToOADate();
解决方案
MsChart确实直接支持这一点,确实使用Series.SuspendUpdates()
是一个好方法,但你需要做对。(但是,请参阅下面的更新以了解缺点)
MSDN是这样说的:
在调用 SuspendUpdates 方法后,对Invalidate方法的调用将不起作用。
如果多次调用 SuspendUpdates 方法,则需要调用 ResumeUpdates 方法的次数相同。
这可以解释为什么它对您不起作用:保持通话平衡至关重要。您需要自己跟踪它们,因为没有可以查询的计数器。但是,如果您超出ResumeUpdates
呼叫,则不会发生任何不好的事情,额外的呼叫将被忽略,下一个呼叫SuspendUpdates
将再次暂停。
这是一个示例截图,请注意暂停计数器..!
请注意,通常添加点会自动触发Invalidate
. 如果您正在做其他事情,例如参加Paint
活动等。您可能需要调用Chart.Invalidate()
,这SuspendUpdates
将阻止,直到被相同数量的ResumeUpdates
..取消
或者,您也可以使用以下简单的解决方法之一:
- 最直接的方法是
DataPoints
通过构造函数创建,然后- 用于正常
series.Add(theNewPoint)
,或.. - 用于
someList<DataPoint>.Add(theNewPoint)
暂停模式。
- 用于正常
当设置为暂停模式时,只需将所有点添加到series.Points
清除它之前。不幸的是没有points.AddRange
,所以你将不得不使用一个foreach
循环。也许chart.SuspendLayout
可以帮助提高性能。
- 想到的另一种解决方法可能适合也可能不适合:您可以使用
xAxis.Maximum
and maybexAxis.Minimum values
。通过将它们设置为固定值,您将允许在右侧添加点而不显示它们。要显示整组点,您可以将它们重置为double.NaN
. 这可能对您有用,但也可能会干扰您拥有的东西。
更新:正如 OP 所指出的,当他更改和Minimum
/或Maximum
. Axis
在许多其他场合也会出现同样的效果:
- 打电话
chart.AreasRecalculateAxesScale();
- 改变图表的
Size
- 更改任何Axis 属性,例如
Color
或Width
.. - 改变
LegendText
一个Series
- 还有很多..
所以我想每当ChartArea
被操纵并强制更新自身时都需要更新的数据..
因此,这很可能使第一个解决方法变得更好,因为解决方案更强大。
推荐阅读
- javascript - React:我可以使用名为“index”的道具吗
- sql - 如何在sql查询中进行表名的动态分配?
- spring-boot - 管理应用程序未启动
- c++ - C++ 分段错误问题
- python - 如何使用 pysolr 检索子值
- java - 如何结合 Scene2d 和 Bullet?
- php - PHP GET ID 和从模式中选择的复选框以插入/更新到数据库
- windows - 如何在 Windows 命令提示符下对变量进行字符串替换?
- python - Python Selenium:无法通过 Xpath 定位元素
- python - 通过 python-qrcode 生成具有恒定大小的 SVG