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.
我有一个应用程序从 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.