C# WinForm ChartControl 有时实时显示零

C# WinForm ChartControl sometimes shows zero in real time

我有一个应用程序从 PLC 读取值并使用这些值每秒绘制图表,每 45 秒将日期记录到 MySQL 数据库。到目前为止它工作正常,但当我对其进行测试时,我意识到它有时会读取错误的值,即 0。例如,PLC 值始终为 45,但我一次又一次地看到我的图表绘制 0 值。我的图表每 1000 毫秒绘制一次,我试图将其增加到 2000 但它仍然是一样的。当我尝试打开另一个应用程序(例如 windows 资源管理器)时,我意识到会发生这种情况。我有 13 个值要在 13 个不同的图表控件上读取和绘制。以下是我用来获取值和绘制仅用于一个 PLC 值和图表控件的图表的代码。我

数据点Class:

public class DataPoint
        {
            public DateTime Argument { get; set; }
            public double Value { get; set; }
            public DataPoint(DateTime argument, double value)
            {
                Argument = argument;
                Value = value;
            }
        }

表单加载事件

            System.Drawing.Font myfont = new System.Drawing.Font("Microsoft Sans Serif", 20);
            System.Drawing.Font baslikFont = new System.Drawing.Font("Microsoft YaHei", 20,System.Drawing.FontStyle.Bold);
            
            //tb1
            tb1.Titles.Add(new ChartTitle { Text = basliklar[1],Font=baslikFont,TextColor=System.Drawing.Color.DeepSkyBlue });
            Series s1 = new Series();
            s1.ChangeView(ViewType.Spline);
            s1.DataSource = dp1;
            s1.DataSourceSorted = true;
            s1.ArgumentDataMember = "Argument";
            s1.ValueDataMembers.AddRange("Value");
            tb1.Series.Add(s1);
            LineSeriesView sv1 = (LineSeriesView)s1.View;
            sv1.LastPoint.LabelDisplayMode = SidePointDisplayMode.DiagramEdge;
            sv1.LastPoint.Label.TextPattern = "{V:f2}";
            sv1.LastPoint.Label.Font = myfont;

            XYDiagram dg1 = (XYDiagram)tb1.Diagram;
            dg1.AxisX.DateTimeScaleOptions.ScaleMode = ScaleMode.Continuous;
            dg1.AxisX.Label.ResolveOverlappingOptions.AllowRotate = false;
            dg1.AxisX.Label.ResolveOverlappingOptions.AllowStagger = false;
            dg1.AxisX.WholeRange.SideMarginsValue = 0;
            dg1.AxisY.ConstantLines.Add(new ConstantLine("Alt limit", altlimit[1]));
            dg1.AxisY.ConstantLines.Add(new ConstantLine("Üst limit", ustlimit[1]));
            dg1.AxisY.ConstantLines[0].Color = System.Drawing.Color.Red;
            dg1.AxisY.ConstantLines[1].Color = System.Drawing.Color.Red;
            dg1.DependentAxesYRange = DefaultBoolean.True;
            dg1.AxisY.WholeRange.AlwaysShowZeroLevel = false;

            timer = new System.Threading.Timer(_ => Timer_Tick(), null, 0, 1000);
            timer2 = new System.Threading.Timer(_ => Timer1_Tick(), null, 45000, 45000);

从 PLC 读取设置值

        try
            {
                atolyevals = atolye.ReadHoldingRegisters(2001, 32);
                if (a_s != null)
                {
                    a_s = null;
                    lineAdd(simdi() + " Atölye PLC bağlantısı sağlandı","g");
                }
            }
        catch
       {
          //Error checking methods
        }

       //Adding new point to the Chart Control
        dp1.Add(new DataPoint(DateTime.Now, gazatolyevals[0]));
                if (dp1.Count > ViewportPointCount)
                    dp1.RemoveAt(0); //if out of viewport remove the first entrance

您使用的 System.Threading.Timer 我认为会触发您的阅读代码。问题是这个计时器 运行s 在后台线程上,而你正在从这个线程更新 UI。这是不允许的,可能会导致各种问题。 UI-对象只能从 UI 线程更改。

解决方案是使用类似 winforms 计时器的东西来 运行 UI 线程上的读取代码,或者 post UI-更新部分到主线程,使用例如 Control.BeginInvoke.