Dispose pattern
When a chart has been created in code, and is no longer needed, chart.Dispose() should be called (first remove chart from collection it was added). It frees the chart and all its objects, such as series, markers and palette steps from the memory.
Extra care / ideal dispose pattern
While calling chart.Dispose() maybe sufficient for the most cases, user can improve GC (Garbage Collector - automated .NET memory handler) speed and avoid any uncertainties by applying The ideal dispose pattern as recommended by .NET/Microsoft.
Here is the complete list of steps user should take:
-
stop (or wait to finish) any background thread, which maybe streaming or pushing new data to the chart, before chart disposal.
-
Before chart is disposed unsubscribe from Events. Note this not only for Chart event like MouseClick, but also for any other events (e.g. axisX.RangeChanged, annotation.DraggedByUser, legend.MouseUp, series.MouseDown etc.)
-
Check that any class member, which references to chart (or it object) is properly updated or dispose. The example of such member is _pls = _chart.View3D.PointLineSeries[0] and it would be error dispose _pls, before removing it from chart/collection.
-
dispose and null chart.
Here is the example of dispose method of complex application (like ExampleEEGDataVisualizationShowcase from LightingChart Demo)
/// <summary>
/// Dispose charts.
/// </summary>
public void Dispose()
{
if (_backGroundWorker != null)
{
_running = false;
_backGroundWorker.Dispose();
_backGroundWorker = null;
}
if (_ChartList == null)
return;
// Remove first from UI.
ChartPlace3D.Children.Clear();
ChartPlaceEEG.Children.Clear();
ChartPlacePowerSpectrum.Children.Clear();
ChartHead2D0.Children.Clear();
ChartHead2D1.Children.Clear();
ChartHead2D2.Children.Clear();
ChartHead2D3.Children.Clear();
ChartHead2D4.Children.Clear();
// And dispose after removed from UI.
_ChartList[2].View3D.SurfaceMeshSeries3D[0].ContourPalette.Dispose();
for (int i = 0; i < _ChartList.Count; i++)
{
_ChartList[i].MouseClick -= Chart_MouseClick;
_ChartList[i].Dispose();
}
_ChartList = null;
_reader = null;
_spectrumCalculator.Dispose();
_spectrumCalculator = null;
_gads2D = null;
_sensorLocations = null;
_modelGeometryAdditionalData = null;
_dataPointSeries.Dispose();
_dataPointSeries = null;
_points = null;
_paletteStepColors = null;
_ThemeStepColors = null;
GC.Collect();
}
Disposing objects
If objects are created on the fly, and then the memory used by them needs to be freed before exiting the application or disposing the whole chart with chart.Dispose(), remove the object from the collection it has been added to, and then call Dispose() for the object.
For example, disposing a series from chart.ViewXY.PointLineSeries collection:
//Do cleanup... Remove and dispose 3 series
_chart.BeginUpdate();
List<PointLineSeries> listSeriesToBeRemoved = new List<PointLineSeries>();
listSeriesToBeRemoved.Add(_chart.ViewXY.PointLineSeries[1]);
listSeriesToBeRemoved.Add(_chart.ViewXY.PointLineSeries[3]);
listSeriesToBeRemoved.Add(_chart.ViewXY.PointLineSeries[4]);
foreach (PointLineSeries pls in listSeriesToBeRemoved)
{
_chart.ViewXY.PointLineSeries.Remove(pls);
pls.Dispose();
}
_chart.EndUpdate();
When LightingChart's objects are no longer needed, it is a good practice to dispose them to prevent memory leaking.
LightningChart’s collections also have specific methods for correctly disposing unused objects. Instead of calling generic list.Clear() method (e.g. ViewXY.SampleDataSeries.Clear()), RemoveAndDispose or DisposeAllAndClear can be used. For example, to remove all SampleDataSeries:
chart.ViewXY.SampleDataSeries.DisposeAllAndClear();
When binding properties
-
Unlike standard .NET objects that implement IDisposable, a DependencyProperty is a static metadata registration, not an instance-bound resource. It lives for the entire duration of the application lifecycle. [the creator/owner of an object manages its lifecycle]
-
User cannot unregister or dispose of the public static readonly DependencyProperty field itself, as it is a permanent part of the application's runtime metadata. However, clearing the instance value ensures that Object can be successfully reclaimed by the Garbage Collector.
-
User should break or clear the binding (and prevent memory leak), especially if the data object bound to that property or the host control itself needs to be collected by the Garbage Collector.
-
When dealing with heavy rendering resources, the order of cleanup is vital to avoid referencing disposed instances during property change cycles.
Combining Microsoft's guidance for a thorough cleanup routine looks like this (e.g. Axisx3d dependency property):
public void CloseAndUnbind()
{
// 1. Fetch the object to prepare it for native resource disposal
// GetValue reads the current resolved item before we sever connections
var heavyObject = this.GetValue(ViewModel.Axisx3dProperty) as IDisposable;
// 2. Clear the binding per Microsoft's data binding architecture
// This stops UI threads from evaluating changes or pushing updates
System.Windows.Data.BindingOperations.ClearBinding(this, ViewModel.Axisx3dProperty);
// 3. Wipes out local property cache references completely
this.ClearValue(ViewModel.Axisx3dProperty);
// 4. Safely call standard .NET IDisposable routine on your 3D asset
heavyObject?.Dispose();
}