windowsforms-14535-controls-and-libraries-chart-control-examples-creating-charts-appearance-customization-how-to-custom-draw-a-crosshair-cursor.md
This example demonstrates how to use the ChartControl.CustomDrawCrosshair event to modify the legend markers of bar series.
To access crosshair element groups, use the CustomDrawCrosshairEventArgs.CrosshairElementGroups property. Elements are separated into several groups when crosshair labels are displayed for each pane.
Use the following properties to access crosshair elements and customize them:
CrosshairElementGroup.HeaderElementGets the settings of crosshair group header elements to customize their appearance.CrosshairElementGroup.CrosshairElementsGets the settings of crosshair elements (crosshair value lines, crosshair value labels, crosshair labels) to customize their appearance.CrosshairElementBase.LabelElementReturns the Crosshair Cursor‘s label element to change its settings when using the ChartControl.CustomDrawCrosshair event to modify the Crosshair’s appearance.CrosshairElementBase.AxisLabelElementReturns the Crosshair Cursor‘s axis label element to change its settings when using the ChartControl.CustomDrawCrosshair event to modify the Crosshair’s appearance.CrosshairLabelElement.DXMarkerImageSpecifies the marker image of a crosshair cursor label when implementing custom draw in the crosshair cursor.
using CustomDrawCrosshairSample.Model;
using DevExpress.Drawing;
using DevExpress.XtraCharts;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
namespace CustomDrawCrosshairSample {
public partial class Form1 : DevExpress.XtraEditors.XtraForm {
Dictionary<string, DXImage> photoCache = new Dictionary<string, DXImage>();
Dictionary<string, DXBitmap> bitmapCache = new Dictionary<string, DXBitmap>();
#region #Constants
const int borderSize = 2;
const int scaledPhotoWidth = 32;
const int scaledPhotoHeight = 34;
// Width and height of scaled photo with border.
const int totalWidth = 36;
const int totalHeight = 38;
// 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();
}
private void Form1_Load(object sender, EventArgs e) {
using (var context = new NwindDbContext()) {
InitPhotoCache(context.Employees);
chart.DataSource = context.Orders.ToList();
}
chart.SeriesDataMember = "Employee.FullName";
chart.SeriesTemplate.ArgumentDataMember = "OrderDate";
chart.SeriesTemplate.ValueDataMembers.AddRange("Freight");
XYDiagram diagram = chart.Diagram as XYDiagram;
if (diagram != null) {
diagram.AxisX.DateTimeScaleOptions.AggregateFunction = AggregateFunction.Sum;
diagram.AxisX.DateTimeScaleOptions.MeasureUnit = DateTimeMeasureUnit.Year;
}
chart.CustomDrawCrosshair += OnCustomDrawCrosshair;
}
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));
}
}
}
#region #CustomDrawCrosshairHandler
private void OnCustomDrawCrosshair(object sender, CustomDrawCrosshairEventArgs e) {
foreach (CrosshairElementGroup group in e.CrosshairElementGroups) {
if (group.CrosshairElements[0] != null)
group.HeaderElement.Text = String.Format("Sales in {0:yyyy}", group.CrosshairElements[0].SeriesPoint.DateTimeArgument);
foreach (CrosshairElement element in group.CrosshairElements) {
DXBitmap image;
if (!bitmapCache.TryGetValue(element.Series.Name, out image)) {
image = new DXBitmap(totalWidth, totalHeight);
using (DXGraphics graphics = DXGraphics.FromImage(image)) {
using (DXSolidBrush brush = new DXSolidBrush(element.LabelElement.MarkerColor)) {
graphics.FillRectangle(brush, totalRect);
}
DXImage photo;
if (photoCache.TryGetValue(element.Series.Name, out photo))
graphics.DrawImage(photo, photoRect);
}
bitmapCache.Add(element.Series.Name, image);
}
element.LabelElement.DXMarkerImage = image;
element.LabelElement.MarkerSize = new Size(totalWidth, totalHeight);
}
}
}
#endregion
}
}
Imports CustomDrawCrosshairSample.Model
Imports DevExpress.Drawing
Imports DevExpress.XtraCharts
Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.IO
Imports System.Linq
Namespace CustomDrawCrosshairSample
Public Partial Class Form1
Inherits DevExpress.XtraEditors.XtraForm
Private photoCache As Dictionary(Of String, DXImage) = New Dictionary(Of String, DXImage)()
Private bitmapCache As Dictionary(Of String, DXBitmap) = New Dictionary(Of String, DXBitmap)()
#Region "#Constants"
Const borderSize As Integer = 2
Const scaledPhotoWidth As Integer = 32
Const scaledPhotoHeight As Integer = 34
' Width and height of scaled photo with border.
Const totalWidth As Integer = 36
Const totalHeight As Integer = 38
' Rects required to create a custom legend series marker.
Private Shared ReadOnly photoRect As Rectangle = New Rectangle(borderSize, borderSize, scaledPhotoWidth, scaledPhotoHeight)
Private Shared ReadOnly totalRect As Rectangle = New Rectangle(0, 0, totalWidth, totalHeight)
#End Region
Public Sub New()
InitializeComponent()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
Using context = New NwindDbContext()
InitPhotoCache(context.Employees)
chart.DataSource = context.Orders.ToList()
End Using
chart.SeriesDataMember = "Employee.FullName"
chart.SeriesTemplate.ArgumentDataMember = "OrderDate"
chart.SeriesTemplate.ValueDataMembers.AddRange("Freight")
Dim diagram As XYDiagram = TryCast(chart.Diagram, XYDiagram)
If diagram IsNot Nothing Then
diagram.AxisX.DateTimeScaleOptions.AggregateFunction = AggregateFunction.Sum
diagram.AxisX.DateTimeScaleOptions.MeasureUnit = DateTimeMeasureUnit.Year
End If
AddHandler chart.CustomDrawCrosshair, AddressOf OnCustomDrawCrosshair
End Sub
Private Sub InitPhotoCache(ByVal employees As IEnumerable(Of Employee))
photoCache.Clear()
For Each employee In employees
Using stream As MemoryStream = New MemoryStream(employee.Photo)
If Not photoCache.ContainsKey(employee.FullName) Then photoCache.Add(employee.FullName, DXImage.FromStream(stream))
End Using
Next
End Sub
#Region "#CustomDrawCrosshairHandler"
Private Sub OnCustomDrawCrosshair(ByVal sender As Object, ByVal e As CustomDrawCrosshairEventArgs)
For Each group As CrosshairElementGroup In e.CrosshairElementGroups
If group.CrosshairElements(0) IsNot Nothing Then group.HeaderElement.Text = String.Format("Sales in {0:yyyy}", group.CrosshairElements(0).SeriesPoint.DateTimeArgument)
For Each element As CrosshairElement In group.CrosshairElements
Dim image As DXBitmap
If Not bitmapCache.TryGetValue(element.Series.Name, image) Then
image = New DXBitmap(totalWidth, totalHeight)
Using graphics As DXGraphics = DXGraphics.FromImage(image)
Using brush As DXSolidBrush = New DXSolidBrush(element.LabelElement.MarkerColor)
graphics.FillRectangle(brush, totalRect)
End Using
Dim photo As DXImage
If photoCache.TryGetValue(element.Series.Name, photo) Then graphics.DrawImage(photo, photoRect)
End Using
bitmapCache.Add(element.Series.Name, image)
End If
element.LabelElement.DXMarkerImage = image
element.LabelElement.MarkerSize = New Size(totalWidth, totalHeight)
Next
Next
End Sub
#End Region
End Class
End Namespace