如何暂时暂停实时数据图表的绘制更新

2024-05-14

我想要“暂停”图表的系列更新来完成一些工作(就像我有一个按钮,当我单击它时,它将暂停图表更新,然后当我单击恢复按钮时,它将更新系列中的所有暂停点。

我知道关于

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;
    }        
}

EDIT:

我发现只要您设置轴的最小值或最大值属性,即使您使用了图表,图表也会保持显示

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 https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datavisualization.charting.chart?view=netframework-4.7.2确实直接支持这一点并且确实使用Series.SuspendUpdates()这是一个好方法,但你需要做对。 (但是请参阅下面的更新以了解缺点)

MSDN https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datavisualization.charting.chartelementcollection-1.suspendupdates?view=netframework-4.7.2#System_Windows_Forms_DataVisualization_Charting_ChartElementCollection_1_SuspendUpdates说:

致电无效方法执行后将不会有任何效果 调用 SuspendUpdates 方法。

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

这可以解释为什么它对您不起作用:保持通话balanced至关重要。您需要自己跟踪它们,因为没有可以查询的计数器。但如果你超过了ResumeUpdates调用,没有什么不好的事情发生,额外的调用被简单地忽略,下一个调用SuspendUpdates会再次暂停。

这是一个示例屏幕截图,请观看暂停计数器..!

请注意,通常添加点会自动触发Invalidate。如果你正在做其他事情,比如画画Paint活动等..您可能需要致电Chart.Invalidate(), which SuspendUpdates将阻止,直到被相同数量的取消ResumeUpdates..


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

  • The most straightforward will create the DataPoints via a constructor and then either
    • use series.Add(theNewPoint) for normal, or..
    • use someList<DataPoint>.Add(theNewPoint) for paused mode.

当设置为暂停模式时,只需将所有点添加到series.Points在清除它之前。不幸的是,这儿没有points.AddRange所以你必须使用foreach环形。或许chart.SuspendLayout可以帮助提高性能。

  • 我想到的其他解决方法可能合适也可能不合适:您可以使用xAxis.Maximum有可能xAxis.Minimum values。通过将它们设置为固定值,您将允许在右侧添加点而不显示它们。要显示整组点,您可以将它们重置为double.NaN。这可能对您有用,但也可能会干扰您所拥有的。

Update:正如OP所指出的,当他更改时数据会更新Minimum and/or Maximum of an Axis。同样的效果也会在许多其他场合出现:

  • Calling chart.AreasRecalculateAxesScale();
  • 改变图表的Size
  • 改变any轴属性如Color or Width..
  • 改变LegendText of a Series
  • 还有很多..

所以我想每当ChartArea被操纵并被迫自我更新..

因此,这很可能使第一个解决方法更好,因为更稳健解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何暂时暂停实时数据图表的绘制更新 的相关文章

随机推荐