如何临时暂停实时数据图表的图形更新

时间:2018-09-28 20:35:51

标签: c# .net mschart

我希望“暂停”图表的系列更新以完成某些工作(例如,当我单击它时有一个按钮将暂停图表更新,然后单击“恢复”按钮时,它将更新系列中的所有暂停点。

我知道

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();

1 个答案:

答案 0 :(得分:2)

MsChart确实直接支持此操作,确实使用Series.SuspendUpdates()是一个好方法,但是您需要正确地做到这一点。 (但是,请参见下面的更新以了解缺点)

MSDN这样说:

  

Invalidate 方法之后,对 Invalidate 方法的调用将无效。   SuspendUpdates方法被调用。

     

如果多次调用SuspendUpdates方法,则需要   多次调用ResumeUpdates方法。

这可以解释为什么它对您不起作用:保持通话平衡至关重要。您需要自己跟踪它们,因为没有可以查询的计数器。但是,如果您过分ResumeUpdates调用,则不会发生任何不良情况,多余的调用将被忽略,下一个SuspendUpdates将再次暂停。

这是示例屏幕截图,请观看悬浮计数器。.

enter image description here

请注意,通常添加点会自动触发Invalidate。如果您正在做其他事情,例如绘制Paint事件等,则可能需要调用Chart.Invalidate()会阻止的SuspendUpdates,直到被相同数量的{{1 }} ..


或者,您也可以使用以下一种简单的解决方法:

  • 最直接的方法是通过构造函数创建ResumeUpdates,然后通过
    • DataPoints用作普通,或..
    • series.Add(theNewPoint)用于已暂停模式。

设置为暂停模式时,只需在清除之前将所有点添加到someList<DataPoint>.Add(theNewPoint)。不幸的是,没有series.Points,因此您将不得不使用points.AddRange循环。也许foreach可以帮助提高性能。

  • 想到的另一种解决方法可能合适也可能不合适:您可以使用chart.SuspendLayoutxAxis.Maximum。通过将它们设置为固定值,您可以在不显示它们的情况下在右边添加点。要显示整个点集,您可以将它们重置为xAxis.Minimum values。这可能对您有用,但也可能会干扰您的财产。

更新:如OP所述,当他更改double.NaN的{​​{1}}和/或Minimum时,数据将更新。在许多其他情况下也会显示相同的效果:

  • 呼叫Maximum
  • 更改图表的Axis
  • 更改任何轴属性,例如chart.AreasRecalculateAxesScale();Size
  • 更改Color的{​​{1}}
  • 还有更多..

所以我猜想,每当Width被操纵并被迫自行更新时,都需要更新的数据。

因此,由于更健壮解决方案,这可能会使第一种解决方法更好。