如何在C#时间轴图表中绘制垂直线并避免重复生成
C# Chart控件避免重复生成当前时间垂直线的解决方法
问题描述
我使用C# Chart控件展示每日潮汐随时间变化的数据,希望用垂直线标记当前时间。现有代码可实现该功能,但将VerticalLine()绑定到定时器后,随着时间推移会生成多条垂直线,请问如何避免这种情况?
原有实现代码:
private void VerticalLine() { double MyDate = DateTime.Now.ToOADate(); double maxDataPoint = chart.ChartAreas[0].AxisY.Maximum; double minDataPoint = chart.ChartAreas[0].AxisY.Minimum; LineAnnotation annotation = new LineAnnotation(); annotation.IsSizeAlwaysRelative = false; annotation.AxisX = chart.ChartAreas[0].AxisX; annotation.AxisY = chart.ChartAreas[0].AxisY; annotation.AnchorY = minDataPoint; annotation.Height = maxDataPoint - minDataPoint;; annotation.Width = 0; annotation.LineWidth = 1; annotation.StartCap = LineAnchorCapStyle.None; annotation.EndCap = LineAnchorCapStyle.None; annotation.AnchorX = MyDate; // <- your point annotation.LineColor = Color.Red; // <- your color chart.Annotations.Add(annotation); } private void timer_Tick(object sender, EventArgs e) { VerticalLine(); }
问题根源:每次定时器触发都会创建新的LineAnnotation实例并添加到chart.Annotations集合中,导致垂直线不断累积。
解决方案
方法一:复用同一个LineAnnotation对象
将LineAnnotation声明为类级别的成员变量,仅在首次调用时创建,后续触发定时器时只更新其位置和属性,避免重复创建对象。
修改后的代码:
// 声明为类成员变量,确保全局唯一 private LineAnnotation _currentTimeLine; private void VerticalLine() { double myDate = DateTime.Now.ToOADate(); double maxDataPoint = chart.ChartAreas[0].AxisY.Maximum; double minDataPoint = chart.ChartAreas[0].AxisY.Minimum; // 仅在首次调用时创建注释对象 if (_currentTimeLine == null) { _currentTimeLine = new LineAnnotation(); _currentTimeLine.IsSizeAlwaysRelative = false; _currentTimeLine.AxisX = chart.ChartAreas[0].AxisX; _currentTimeLine.AxisY = chart.ChartAreas[0].AxisY; _currentTimeLine.LineWidth = 1; _currentTimeLine.StartCap = LineAnchorCapStyle.None; _currentTimeLine.EndCap = LineAnchorCapStyle.None; _currentTimeLine.LineColor = Color.Red; chart.Annotations.Add(_currentTimeLine); } // 更新垂直线的位置和高度(适配Y轴范围变化) _currentTimeLine.AnchorY = minDataPoint; _currentTimeLine.Height = maxDataPoint - minDataPoint; _currentTimeLine.Width = 0; _currentTimeLine.AnchorX = myDate; } private void timer_Tick(object sender, EventArgs e) { VerticalLine(); }
方法二:每次更新前移除旧的垂直线
在创建新的垂直线之前,先从chart.Annotations集合中移除之前的时间标记线。可以通过名称标记或属性筛选来精准定位要移除的注释。
方式1:通过名称标记筛选
private void VerticalLine() { // 移除已有的时间标记线(通过名称精准匹配) var existingLine = chart.Annotations["CurrentTimeLine"]; if (existingLine != null) { chart.Annotations.Remove(existingLine); } double myDate = DateTime.Now.ToOADate(); double maxDataPoint = chart.ChartAreas[0].AxisY.Maximum; double minDataPoint = chart.ChartAreas[0].AxisY.Minimum; LineAnnotation annotation = new LineAnnotation(); annotation.Name = "CurrentTimeLine"; // 设置唯一名称,方便后续查找 annotation.IsSizeAlwaysRelative = false; annotation.AxisX = chart.ChartAreas[0].AxisX; annotation.AxisY = chart.ChartAreas[0].AxisY; annotation.AnchorY = minDataPoint; annotation.Height = maxDataPoint - minDataPoint; annotation.Width = 0; annotation.LineWidth = 1; annotation.StartCap = LineAnchorCapStyle.None; annotation.EndCap = LineAnchorCapStyle.None; annotation.AnchorX = myDate; annotation.LineColor = Color.Red; chart.Annotations.Add(annotation); } private void timer_Tick(object sender, EventArgs e) { VerticalLine(); }
方式2:通过属性筛选
如果没有设置名称,也可以通过注释类型和颜色等属性筛选:
private void VerticalLine() { // 移除已有的红色垂直线注释 var existingLine = chart.Annotations.OfType<LineAnnotation>() .FirstOrDefault(a => a.LineColor == Color.Red); if (existingLine != null) { chart.Annotations.Remove(existingLine); } // 后续创建新注释的代码和原有逻辑一致 double myDate = DateTime.Now.ToOADate(); double maxDataPoint = chart.ChartAreas[0].AxisY.Maximum; double minDataPoint = chart.ChartAreas[0].AxisY.Minimum; LineAnnotation annotation = new LineAnnotation(); annotation.IsSizeAlwaysRelative = false; annotation.AxisX = chart.ChartAreas[0].AxisX; annotation.AxisY = chart.ChartAreas[0].AxisY; annotation.AnchorY = minDataPoint; annotation.Height = maxDataPoint - minDataPoint; annotation.Width = 0; annotation.LineWidth = 1; annotation.StartCap = LineAnchorCapStyle.None; annotation.EndCap = LineAnchorCapStyle.None; annotation.AnchorX = myDate; annotation.LineColor = Color.Red; chart.Annotations.Add(annotation); } private void timer_Tick(object sender, EventArgs e) { VerticalLine(); }
内容的提问来源于stack exchange,提问作者Ulrich Rosin
相关产品推荐
相关产品推荐

