I've implemented a User Control class to extend the functionality of the Chart class. This chart will have data added to it in real time. The User Control class creates a ChartArea, and adds it to the underlying chart. It also adds a Title, Legend and Series. My problem is when I add new data points to the chart series, the chart does not update to reflect this as it does in the vanilla Chart.
The User Control class contains a sub to add data to the underlying chart:
Chart1.Series(seriesName).Points.AddXY(xValue, yValue)
I've mocked up a data source and can verify there are indeed data points in the series. I've tried calling invalidate(), refresh(), and/or update() on Chart1, the ChartArea, the Series, and the User Control class itself. I also added data points to the Series as soon as it was created, which did not appear either.
I feel I'm missing something simple; why do these data points not appear?
Relevant code:
(dataChart is the Chart associated with the User Control)
Imports System.Windows.Forms.DataVisualization.Charting
Public Class ScrollChart
Private _legendName As String = "defaultLegend"
Private _chartSpan As Single = 10
Private _xAxisFormat As String = "#.0"
Private _yAxisFormat As String = "#.0"
Private _xMajorInterval As Single = 1
Private _xMinorInterval As Single = 0.5
'...Property getters and setters omitted
Public Sub New()
' This call is required by the designer.
InitializeComponent()
'Remove default chart objects
dataChart.Legends.Clear()
dataChart.Titles.Clear()
dataChart.Annotations.Clear()
dataChart.Series.Clear()
dataChart.ChartAreas.Clear()
End Sub
Public Sub createChartArea(ByVal areaName As String, ByVal areaTitle As String, ByVal xAxisTitle As String, ByVal yAxisTitle As String)
'Create new ChartArea
Dim newArea As ChartArea = New ChartArea(areaName)
'Add area title
Dim chartTitle As Title = New Title(areaTitle)
dataChart.Titles.Add(chartTitle)
'Add area legend
Dim areaLegend As Legend = New Legend(_legendName)
areaLegend.Docking = Docking.Bottom
dataChart.Legends.Add(areaLegend)
'Set X axis defaults for scrolling
newArea.AxisX.Minimum = 0
newArea.AxisX.Maximum = _chartSpan
newArea.AxisX.MajorGrid.Interval = _xMajorInterval
newArea.AxisX.MinorGrid.Enabled = True
newArea.AxisX.MinorGrid.Interval = _xMinorInterval
newArea.AxisX.LabelStyle.Format = _xAxisFormat
newArea.AxisX.IsStartedFromZero = False
newArea.AxisX.Title = xAxisTitle
'Set Y axis defaults for scrolling
newArea.AxisY.Minimum = 0
newArea.AxisY.Maximum = 1
newArea.AxisY.MinorGrid.Enabled = True
newArea.AxisY.LabelStyle.Format = _yAxisFormat
newArea.AxisY.IsStartedFromZero = False
newArea.AxisY.Title = yAxisTitle
'Add to chart
dataChart.ChartAreas.Add(newArea)
End Sub
Public Sub createChartSeries(ByVal areaName As String, ByVal seriesName As String, ByVal seriesTitle As String)
'Create new Series
Dim newSeries As Series = New Series(seriesName)
'Add series legend
newSeries.Legend = _legendName
newSeries.LegendText = seriesTitle
'Set defaults for scrolling
newSeries.ChartType = SeriesChartType.Line
newSeries.Color = Color.Red
newSeries.ChartArea = areaName
newSeries.MarkerColor = Color.Red
'Add to chart
dataChart.Series.Add(newSeries)
End Sub
Public Sub addData(ByVal seriesName As String, ByVal xValue As Single, ByVal yValue As Single)
'Add new data point
dataChart.Series(seriesName).Points.AddXY(xValue, yValue)
'Remove oldest point if series is larger than the given chart span
Dim newestX As Double = dataChart.Series(seriesName).Points.Last.XValue
Dim oldestX As Double = dataChart.Series(seriesName).Points.First.XValue
If ((newestX - oldestX) > _chartSpan) Then
dataChart.Series(seriesName).Points.RemoveAt(0)
End If
'Redraw axis
dataChart.ChartAreas(dataChart.Series(seriesName).ChartArea).RecalculateAxesScale()
End Sub
Private Sub ScrollChart_Resize(sender As Object, e As EventArgs) Handles Me.Resize
'Resize chart to control size
dataChart.Size = Size
End Sub
End Class
Class usage in the testing form:
Public Class Form1
Private dataSource As New MockDataSource(10, 0.5)
Private startTime As Date = Date.Now
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ScrollChart1.createChartArea("area1", "Test Data", "Time (Seconds)", "Value (Unitless)")
ScrollChart1.createChartSeries("area1", "series1", "Test Value")
End Sub
Private Sub pollTimer_Tick(sender As Object, e As EventArgs) Handles pollTimer.Tick
Dim currentElapsed As Single = CSng((Date.Now - startTime).TotalSeconds)
ScrollChart1.addData("series1", currentElapsed, dataSource.getRandomValue)
End Sub
End Class