Back to Devexpress

ChartControl.CustomDrawSeriesPoint Event

windowsforms-devexpress-dot-xtracharts-dot-chartcontrol-e15e4bfd.md

latest31.4 KB
Original Source

ChartControl.CustomDrawSeriesPoint Event

Occurs before a series point is drawn when the chart’s contents is being drawn.

Namespace : DevExpress.XtraCharts

Assembly : DevExpress.XtraCharts.v25.2.UI.dll

NuGet Package : DevExpress.Win.Charts

Declaration

csharp
public event CustomDrawSeriesPointEventHandler CustomDrawSeriesPoint
vb
Public Event CustomDrawSeriesPoint As CustomDrawSeriesPointEventHandler

Event Data

The CustomDrawSeriesPoint event's data class is CustomDrawSeriesPointEventArgs. The following properties provide information specific to this event:

PropertyDescription
DisposeLegendFontGets or sets the value specifying whether the e.DXLegendFont should be disposed when drawing is finished. Inherited from CustomDrawSeriesEventArgsBase.
DisposeLegendMarkerImageGets or sets the value specifying whether e.DXLegendMarkerImage should be disposed when drawing is finished. Inherited from CustomDrawSeriesEventArgsBase.
DXLegendFontGets or sets the text font of the legend item of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
DXLegendMarkerImageGets or sets the image of the legend item marker of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LabelTextGets or sets the text of a label for the point currently being painted.
LegendDrawOptionsReturns the draw settings of the legend item of the series that is currently being drawn. Inherited from CustomDrawSeriesEventArgsBase.
LegendFontGets or sets the text font of the legend item of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendMarkerImageGets or sets the image of the legend item marker of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendMarkerImageSizeModeGets or sets the image size mode of the legend item marker of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendMarkerSizeGets or sets the size of the legend item marker of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendMarkerVisibleGets or sets the visibility of the legend item marker of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendTextGets or sets the text of the legend item of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendTextColorGets or sets the text color of the legend item of the series or series point that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
LegendTextVisibleGets or sets the text visibility of the legend item of the series whose points are currently being drawn. Inherited from CustomDrawSeriesEventArgsBase.
PercentValueReturns the portion of the series point’s value within the total value of a series group to which the series point belongs.
SecondLabelTextGets or sets the text of a second label for the point currently being painted for specific series views.
SelectionStateSpecifies the selection state mode for the series whose points are currently being painted.
SeriesReturns the series that is currently being painted. Inherited from CustomDrawSeriesEventArgsBase.
SeriesDrawOptionsReturns the draw settings of the series that is currently being drawn. Inherited from CustomDrawSeriesEventArgsBase.
SeriesPointGets the series point currently being painted.
TotalLabelTextObsolete. Gets or sets the text of a series group’s total label.
TotalValueReturns the total value of a series group to which the series point belongs.

Remarks

The CustomDrawSeriesPoint event is raised before every series point is painted. The event parameter’s CustomDrawSeriesEventArgsBase.Series property provides the series which enables the series view and other specific series options to be determined. The CustomDrawSeriesPointEventArgs.SeriesPoint property provides the series point which enables all the data that corresponds to the series point being painted.

And the CustomDrawSeriesEventArgsBase.SeriesDrawOptions property provides drawing options specific to each series. Note that the return value of this property should be typecast to the corresponding type (e.g., BarDrawOptions).

Note

For the WebChartControl you should handle its WebChartControl.CustomDrawSeriesPoint event to do this.

The ChartControl.CustomDrawSeries and CustomDrawSeriesPoint events are always raised in the following order.

  • The CustomDrawSeries event for the first series in the chart’s ChartControl.Series collection. The first series in the series collection is a Series which the SeriesCollection.IndexOf method returns 0 for.
  • The CustomDrawSeriesPoint event for all the series points of the first series.
  • The CustomDrawSeries event for the second series in the chart’s ChartControl.Series collection.
  • The CustomDrawSeriesPoint event for all series points of the second series.
  • …and so on for all the other series and their points.

Examples

Implement Custom Drawing for a Series Point

This example demonstrates how to implement custom drawing in charts when drawing the series points of charts. To do this you should handle the ChartControl.CustomDrawSeriesPoint event, and then you can change some of the drawing parameters using its event args.

csharp
using DevExpress.XtraCharts;
// ...

private void chartControl1_CustomDrawSeriesPoint(object sender, 
CustomDrawSeriesPointEventArgs e) {
   // These changes will be applied to Bar Series only.
   BarDrawOptions drawOptions = e.SeriesDrawOptions as BarDrawOptions;
   if (drawOptions == null)
      return;

   // Get the fill options for the series point.
   drawOptions.FillStyle.FillMode = FillMode.Gradient;
   RectangleGradientFillOptions options = 
   drawOptions.FillStyle.Options as RectangleGradientFillOptions;
   if (options == null)
      return;

   // Get the value at the current series point.
   double val = e.SeriesPoint[0];

   // If the value is less than 2.5, then fill the bar with green colors.
   if (val < 2.5) {
      options.Color2 = Color.FromArgb(154, 196, 84);
      drawOptions.Color = Color.FromArgb(81, 137, 3);
      drawOptions.Border.Color = Color.FromArgb(100, 39, 91, 1);
   } 
   // ... if the value is less than 5.5, then fill the bar with yellow colors.
   else if (val < 5.5) {
      options.Color2 = Color.FromArgb(254, 233, 124);
      drawOptions.Color = Color.FromArgb(249, 170, 15);
      drawOptions.Border.Color = Color.FromArgb(60, 165, 73, 5);
   }
   // ... if the value is greater, then fill the bar with red colors.
   else {
      options.Color2 = Color.FromArgb(242, 143, 112);
      drawOptions.Color = Color.FromArgb(199, 57 ,12);
      drawOptions.Border.Color = Color.FromArgb(100, 155, 26, 0);
   }
}
vb
Imports DevExpress.XtraCharts
' ...

Private Sub OnCustomDrawSeriesPoint(ByVal sender As Object, _ 
ByVal e As CustomDrawSeriesPointEventArgs) _
Handles chartControl1.CustomDrawSeriesPoint

   ' These changes will be applied to Bar Series only.
   Dim drawOptions = CType(e.SeriesDrawOptions, BarDrawOptions)
   If drawOptions Is Nothing Then
      Return
   End If

   ' Get the fill options for the series point.
   drawOptions.FillStyle.FillMode = FillMode.Gradient
   Dim options = CType(drawOptions.FillStyle.Options, RectangleGradientFillOptions)
   If options Is Nothing Then
      Return
   End If

   ' Get the value at the current series point.
   Dim val As Double = e.SeriesPoint(0)

   ' If the value is less than 2.5, then fill the bar with green colors.
   If val < 2.5 Then
      options.Color2 = Color.FromArgb(154, 196, 84)
      drawOptions.Color = Color.FromArgb(81, 137, 3)
      drawOptions.Border.Color = Color.FromArgb(100, 39, 91, 1)
      ' ... if the value is less than 5.5, then fill the bar with yellow colors.
   Else
      If val < 5.5 Then
         options.Color2 = Color.FromArgb(254, 233, 124)
         drawOptions.Color = Color.FromArgb(249, 170, 15)
         drawOptions.Border.Color = Color.FromArgb(60, 165, 73, 5)
         ' ... if the value is greater, then fill the bar with red colors.
      Else
         options.Color2 = Color.FromArgb(242, 143, 112)
         drawOptions.Color = Color.FromArgb(199, 57, 12)
         drawOptions.Border.Color = Color.FromArgb(100, 155, 26, 0)
      End If
   End If
End Sub

Draw a Custom Legend Marker for a Series Point

This example demonstrates how to use the ChartControl.CustomDrawSeriesPoint event to modify the legend markers of nested donut series points.

View Example

Assign a custom legend marker to the e.DXLegendMarkerImage property. Set the e.DisposeLegendMarkerImage property to true to avoid memory leaks. To customize options used to draw the series point, cast e.SeriesDrawOptions to the DrawOptions class descendant that stores draw options of the required series view type.

cs
using CustomSeriesPointDrawingSample.Model;
using DevExpress.Drawing;
using DevExpress.XtraCharts;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace CustomSeriesPointDrawingSample {
    public partial class Form1 : Form {
        object trackedPointArgument;
        Dictionary<string, DXImage> photoCache = new Dictionary<string, DXImage>();

        #region #Constants
        const int borderSize = 5;
        const int scaledPhotoWidth = 48;
        const int scaledPhotoHeight = 51;
        // Width and height of scaled photo with border.
        const int totalWidth = 58;
        const int totalHeight = 61;

        // Rects required to create a custom legend series marker.
        static readonly Rectangle photoRect = new Rectangle(
                borderSize, borderSize,
                scaledPhotoWidth, scaledPhotoHeight);
        static readonly Rectangle totalRect = new Rectangle(
                0, 0,
                totalWidth, totalHeight);
        #endregion

        public Form1() {
            InitializeComponent();
        }

        #region #ChartPreparation
        private void Form1_Load(object sender, EventArgs e) {
            chart.CustomDrawSeriesPoint += OnCustomDrawSeriesPoint;
            chart.BoundDataChanged += OnBoundDataChanged;
            chart.ObjectHotTracked += OnObjectHotTracked;

            using (var context = new NwindDbContext()) {
                chart.DataSource = PrepareDataSource(context.Orders);
                InitPhotoCache(context.Employees);
            }
            chart.SeriesDataMember = "Year";
            chart.SeriesTemplate.ArgumentDataMember = "Employee";
            chart.SeriesTemplate.ValueDataMembers.AddRange("Value");

            chart.SeriesTemplate.ToolTipPointPattern = "{S}: {A} ({VP:P})";
            chart.SeriesTemplate.SeriesPointsSorting = SortingMode.Ascending;
        }
        #endregion

        #region #AutogeneratedSeriesModifying
        private void OnBoundDataChanged(object sender, EventArgs e) {
            if (chart.Series.Count <= 1) return;
            for (int i = 1; i < chart.Series.Count; ++i)
                chart.Series[i].ShowInLegend = false;
        }
        #endregion

        #region #CustomPointDrawing
        private void OnCustomDrawSeriesPoint(object sender, CustomDrawSeriesPointEventArgs e) {
            // Design a series marker image.
            DXBitmap image = new DXBitmap(totalWidth, totalHeight);
            bool isSelected = trackedPointArgument != null && e.SeriesPoint.Argument.Equals(trackedPointArgument);

            using (DXGraphics graphics = DXGraphics.FromImage(image)) {
                using (var fillBrush = isSelected ? (DXBrush)new DXHatchBrush(DXHatchStyle.DarkDownwardDiagonal,
                                                                          e.LegendDrawOptions.Color,
                                                                          e.LegendDrawOptions.ActualColor2)
                                                  : (DXBrush)new DXSolidBrush(e.LegendDrawOptions.Color)) {
                    graphics.FillRectangle(fillBrush, totalRect);
                }
                DXImage photo;
                if (photoCache.TryGetValue(e.SeriesPoint.Argument, out photo))
                    graphics.DrawImage(photo, photoRect);
            }

            e.DXLegendMarkerImage = image;
            e.DisposeLegendMarkerImage = true;

            PieDrawOptions options = e.SeriesDrawOptions as PieDrawOptions;
            if (isSelected && options != null) {
                options.FillStyle.FillMode = DevExpress.XtraCharts.FillMode.Hatch;
                ((HatchFillOptions)options.FillStyle.Options).HatchStyle = HatchStyle.DarkDownwardDiagonal;
            }
        }
        #endregion

        private void OnObjectHotTracked(object sender, HotTrackEventArgs e) {
            trackedPointArgument = e.HitInfo.InSeriesPoint ? e.HitInfo.SeriesPoint.Argument : null;
            chart.Invalidate();
        }

        void InitPhotoCache(IEnumerable<Employee> employees) {
            photoCache.Clear();
            foreach (var employee in employees) {
                using (MemoryStream stream = new MemoryStream(employee.Photo)) {
                    if (!photoCache.ContainsKey(employee.FullName))
                        photoCache.Add(employee.FullName, DXImage.FromStream(stream));
                }
            }
        }

        List<SalesPoint> PrepareDataSource(IEnumerable<Order> orders) {
            var query = from o in orders
                        group o by new {
                            Year = o.OrderDate.Year,
                            Employee = o.Employee.FirstName + " " + o.Employee.LastName
                        }
                        into g
                        select new {
                            Employee = g.Key.Employee,
                            Year = g.Key.Year,
                            Values = g.Select(o => o.Freight.HasValue ? o.Freight.Value : 0)
                        };

            List<SalesPoint> points = new List<SalesPoint>();
            foreach (var item in query) {
                points.Add(new SalesPoint {
                    Employee = item.Employee,
                    Year = item.Year,
                    Value = item.Values.Aggregate((d1, d2) => d1 + d2)
                });
            }
            return points;
        }
    }
}

class SalesPoint {
    public string Employee { get; set; }
    public int Year { get; set; }
    public decimal Value { get; set; }
}
vb
Imports CustomSeriesPointDrawingSample.Model
Imports DevExpress.Drawing
Imports DevExpress.XtraCharts
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.IO
Imports System.Linq
Imports System.Windows.Forms

Namespace CustomSeriesPointDrawingSample

    Public Partial Class Form1
        Inherits System.Windows.Forms.Form

        Private trackedPointArgument As Object

        Private photoCache As System.Collections.Generic.Dictionary(Of String, DevExpress.Drawing.DXImage) = New System.Collections.Generic.Dictionary(Of String, DevExpress.Drawing.DXImage)()

#Region "#Constants"
        Const borderSize As Integer = 5

        Const scaledPhotoWidth As Integer = 48

        Const scaledPhotoHeight As Integer = 51

        ' Width and height of scaled photo with border.
        Const totalWidth As Integer = 58

        Const totalHeight As Integer = 61

        ' Rects required to create a custom legend series marker.
        Private Shared ReadOnly photoRect As System.Drawing.Rectangle = New System.Drawing.Rectangle(CustomSeriesPointDrawingSample.Form1.borderSize, CustomSeriesPointDrawingSample.Form1.borderSize, CustomSeriesPointDrawingSample.Form1.scaledPhotoWidth, CustomSeriesPointDrawingSample.Form1.scaledPhotoHeight)

        Private Shared ReadOnly totalRect As System.Drawing.Rectangle = New System.Drawing.Rectangle(0, 0, CustomSeriesPointDrawingSample.Form1.totalWidth, CustomSeriesPointDrawingSample.Form1.totalHeight)

#End Region
        Public Sub New()
            Me.InitializeComponent()
        End Sub

#Region "#ChartPreparation"
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)
            AddHandler Me.chart.CustomDrawSeriesPoint, AddressOf Me.OnCustomDrawSeriesPoint
            AddHandler Me.chart.BoundDataChanged, AddressOf Me.OnBoundDataChanged
            AddHandler Me.chart.ObjectHotTracked, AddressOf Me.OnObjectHotTracked
            Using context = New CustomSeriesPointDrawingSample.Model.NwindDbContext()
                Me.chart.DataSource = Me.PrepareDataSource(context.Orders)
                Me.InitPhotoCache(context.Employees)
            End Using

            Me.chart.SeriesDataMember = "Year"
            Me.chart.SeriesTemplate.ArgumentDataMember = "Employee"
            Me.chart.SeriesTemplate.ValueDataMembers.AddRange("Value")
            Me.chart.SeriesTemplate.ToolTipPointPattern = "{S}: {A} ({VP:P})"
            Me.chart.SeriesTemplate.SeriesPointsSorting = DevExpress.XtraCharts.SortingMode.Ascending
        End Sub

#End Region
#Region "#AutogeneratedSeriesModifying"
        Private Sub OnBoundDataChanged(ByVal sender As Object, ByVal e As System.EventArgs)
            If Me.chart.Series.Count <= 1 Then Return
            Dim i As Integer = 1
            While i < Me.chart.Series.Count
                Me.chart.Series(CInt((i))).ShowInLegend = False
                Call System.Threading.Interlocked.Increment(i)
            End While
        End Sub

#End Region
#Region "#CustomPointDrawing"
        Private Sub OnCustomDrawSeriesPoint(ByVal sender As Object, ByVal e As DevExpress.XtraCharts.CustomDrawSeriesPointEventArgs)
            ' Design a series marker image.
            Dim image As DevExpress.Drawing.DXBitmap = New DevExpress.Drawing.DXBitmap(CustomSeriesPointDrawingSample.Form1.totalWidth, CustomSeriesPointDrawingSample.Form1.totalHeight)
            Dim isSelected As Boolean = Me.trackedPointArgument IsNot Nothing AndAlso e.SeriesPoint.Argument.Equals(Me.trackedPointArgument)
            Using graphics As DevExpress.Drawing.DXGraphics = DevExpress.Drawing.DXGraphics.FromImage(image)
                Using fillBrush = If(isSelected, CType(New DevExpress.Drawing.DXHatchBrush(DevExpress.Drawing.DXHatchStyle.DarkDownwardDiagonal, e.LegendDrawOptions.Color, e.LegendDrawOptions.ActualColor2), DevExpress.Drawing.DXBrush), CType(New DevExpress.Drawing.DXSolidBrush(e.LegendDrawOptions.Color), DevExpress.Drawing.DXBrush))
                    graphics.FillRectangle(fillBrush, CustomSeriesPointDrawingSample.Form1.totalRect)
                End Using

                Dim photo As DevExpress.Drawing.DXImage
                If Me.photoCache.TryGetValue(e.SeriesPoint.Argument, photo) Then graphics.DrawImage(photo, CustomSeriesPointDrawingSample.Form1.photoRect)
            End Using

            e.DXLegendMarkerImage = image
            e.DisposeLegendMarkerImage = True
            Dim options As DevExpress.XtraCharts.PieDrawOptions = TryCast(e.SeriesDrawOptions, DevExpress.XtraCharts.PieDrawOptions)
            If isSelected AndAlso options IsNot Nothing Then
                options.FillStyle.FillMode = DevExpress.XtraCharts.FillMode.Hatch
                CType(options.FillStyle.Options, DevExpress.XtraCharts.HatchFillOptions).HatchStyle = System.Drawing.Drawing2D.HatchStyle.DarkDownwardDiagonal
            End If
        End Sub

#End Region
        Private Sub OnObjectHotTracked(ByVal sender As Object, ByVal e As DevExpress.XtraCharts.HotTrackEventArgs)
            Me.trackedPointArgument = If(e.HitInfo.InSeriesPoint, e.HitInfo.SeriesPoint.Argument, Nothing)
            Me.chart.Invalidate()
        End Sub

        Private Sub InitPhotoCache(ByVal employees As System.Collections.Generic.IEnumerable(Of CustomSeriesPointDrawingSample.Model.Employee))
            Me.photoCache.Clear()
            For Each employee In employees
                Using stream As System.IO.MemoryStream = New System.IO.MemoryStream(employee.Photo)
                    If Not Me.photoCache.ContainsKey(employee.FullName) Then Me.photoCache.Add(employee.FullName, DevExpress.Drawing.DXImage.FromStream(stream))
                End Using
            Next
        End Sub

        Private Function PrepareDataSource(ByVal orders As System.Collections.Generic.IEnumerable(Of CustomSeriesPointDrawingSample.Model.Order)) As List(Of SalesPoint)
            Dim query = From o In orders Group o By __groupByKey1__ = New With {.Year = o.OrderDate.Year, .Employee = o.Employee.FirstName & " " & o.Employee.LastName} Into g = Group Select New With {.Employee = __groupByKey1__.Employee, .Year = __groupByKey1__.Year, .Values = g.[Select](Function(o) If(o.Freight.HasValue, o.Freight.Value, 0))}
            Dim points As System.Collections.Generic.List(Of SalesPoint) = New System.Collections.Generic.List(Of SalesPoint)()
            For Each item In query
                points.Add(New SalesPoint With {.Employee = item.Employee, .Year = item.Year, .Value = item.Values.Aggregate(Function(d1, d2) d1 + d2)})
            Next

            Return points
        End Function
    End Class
End Namespace

Friend Class SalesPoint

    Public Property Employee As String

    Public Property Year As Integer

    Public Property Value As Decimal
End Class

Conditionally Hide Series Labels

This example hides all point labels except the last one.

View Example

The following code snippets (auto-collected from DevExpress Examples) contain references to the CustomDrawSeriesPoint event.

Note

The algorithm used to collect these code examples remains a work in progress. Accordingly, the links and snippets below may produce inaccurate results. If you encounter an issue with code examples below, please use the feedback form on this page to report the issue.

winforms-dashboard-custom-items/CS/TutorialsCustomItems/CustomItems/FunnelItemControlProvider.cs#L27

csharp
chart.SelectedItemsChanging += ChartSelectedItemsChanging;
    chart.CustomDrawSeriesPoint += CustomDrawSeriesPoint;
}

winforms-chart-draw-a-custom-legend-marker-for-a-series-point/CS/CustomSeriesPointDrawingSample/Form1.cs#L41

csharp
private void Form1_Load(object sender, EventArgs e) {
    chart.CustomDrawSeriesPoint += OnCustomDrawSeriesPoint;
    chart.BoundDataChanged += OnBoundDataChanged;

winforms-dashboard-custom-items-extension/CS/CustomItemExtension/CustomItems/Funnel/FunnelItemControlProvider.cs#L28

csharp
chart.SelectedItemsChanging += ChartSelectedItemsChanging;
    chart.CustomDrawSeriesPoint += CustomDrawSeriesPoint;
}

winforms-dashboard-custom-items/VB/TutorialsCustomItems/CustomItems/FunnelItemControlProvider.vb#L33

vb
AddHandler chart.SelectedItemsChanging, AddressOf ChartSelectedItemsChanging
    AddHandler chart.CustomDrawSeriesPoint, AddressOf CustomDrawSeriesPoint
End Sub

winforms-chart-draw-a-custom-legend-marker-for-a-series-point/VB/CustomSeriesPointDrawingSample/Form1.vb#L46

vb
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)
    AddHandler Me.chart.CustomDrawSeriesPoint, AddressOf Me.OnCustomDrawSeriesPoint
    AddHandler Me.chart.BoundDataChanged, AddressOf Me.OnBoundDataChanged

winforms-dashboard-custom-items-extension/VB/CustomItemExtension/CustomItems/Funnel/FunnelItemControlProvider.vb#L34

vb
AddHandler chart.SelectedItemsChanging, AddressOf ChartSelectedItemsChanging
    AddHandler chart.CustomDrawSeriesPoint, AddressOf CustomDrawSeriesPoint
End Sub

See Also

CustomDrawSeries

ChartControl Class

ChartControl Members

DevExpress.XtraCharts Namespace