c# - 如何临时暂停实时数据图表的绘制更新

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

编辑:

我想通了,只要您为轴设置最小值或最大值属性,图表就会保持显示,即使您已使用

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是这样说的:

A call to the Invalidate method will have no effect after the SuspendUpdates method is called.

If you call the SuspendUpdates method several times, you will need to call the ResumeUpdates method an equal number of times.

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

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

enter image description here

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


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

  • 最直接的将创建 DataPoints通过构造函数,然后要么
    • 使用series.Add(theNewPoint)对于正常,或者..
    • 使用someList<DataPoint>.Add(theNewPoint)用于暂停模式。

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

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

更新:正如 OP 所指出的,当他更改 Minimum 时数据会更新和/或 MaximumAxis .在许多其他场合也会出现同样的效果:

  • 调用 chart.AreasRecalculateAxesScale();
  • 更改图表的 Size
  • 更改任何 轴属性,如ColorWidth ..
  • 更改 LegendTextSeries
  • 还有很多..

所以我想每当 ChartArea 时都需要更新数据被操纵并被迫 self 更新..

因此,这可能会使第一个解决方法变得更好,因为它是更强大的解决方案。

关于c# - 如何临时暂停实时数据图表的绘制更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52562331/

相关文章:

c# - 如何计算 Nullable<T> 数据类型的大小

asp.net - MS 图表控件的替代品?

c# - 线路端点检测

c# - 如何在 C# 中转换为 XML 之前验证 JSON 字符串

c# - 反转对象或用减号将其标记为负数

.net - 实体数据模型无法遵循 web.config 中的 configSource 属性

c# - 如何在散点图中绘制超过 50,000 个值,从而节省计算机资源?

c# - 来自 .Net 图表的意外行为

c# - 使用 C# 将文件上传到 Google Drive

c# - 使用 ASP.NET Core 将文件上传到 Cloudinary