Descrizione :
Esempio pratico di associazione dati e loro rappresentazione con il controllo Chart.
+ Articolo :
Anzitutto, dal momento che di "controlli chart" in giro ce ne sono davvero tanti, voglio precisare che l'argomento in esame riguarda esclusivamente il controllo incluso in Visual Studio ( in questo caso : 2010 ), e per l'esattezza quello in Forms :
System.Windows.Forms.DataVisualization.Charting.Chart().
Ho creato questo articolo per un duplice scopo :
1. Mostrare una tecnica valida per collegare un Chart con le sue varie Serie, ad una unica fonte dati, come un DataTable.
2. Illustrare 4 diversi modi per evidenziare ciascun dato, una volta che è rappresentato graficamente nel Chart.
Oltre a questo, si noterà come diversi controlli, come le ComboBox per la scelta di ciascun Punto-Dati, vengano automaticamente messe in relazione all'atto della loro associazione con una fonte dati comune.
Per replicare l'articolo occorre una semplice Form "FormMain", con i seguenti controlli essenziali :
--> Chart : chart1
--> ComboBox : cmb_x
--> ComboBox : cmb_serie2
--> ComboBox : cmb_serie3
Le Label sono a scopo descrittivo.
Un'immagine rende bene l'idea della struttura desiderata e del funzionamento ottenuto :
--> Codice completo FormMain :
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace DatiControlloChart
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Font fontLab = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Regular);
private DataTable DT = new DataTable("TabellaDati");
private string percorsoBmp = Application.StartupPath + "\\";
private string nomeBmp = "arrow.bmp";
private int RandomInteger(int min, int max, int seed)
{
return (new Random(seed)).Next(min, max);
}
private void Form1_Load(object sender, EventArgs e)
{
//Formattazione DataTable Tabella Dati per contenere due serie
//Asse X comune alle Serie Dati
DT.Columns.Add("X", typeof(System.Int32));
DT.PrimaryKey = new DataColumn[] {DT.Columns["X"]};
//Asse Y Serie1
DT.Columns.Add("YSerie1", typeof(System.Single));
//Asse Y Serie2
DT.Columns.Add("YSerie2", typeof(System.Int32));
//Asse Y Serie3
DT.Columns.Add("YSerie3", typeof(System.Int32));
//Asse Y Serie4
DT.Columns.Add("YSerie4", typeof(System.Int32));
//Creazione Dati ( Pseudo-Random )
for (int i = 1; i <= 20; i++)
{
DT.Rows.Add( new object[] { i, RandomInteger(10, 25, Convert.ToInt32((Math.Pow(i, 2)))) * 1.2,
RandomInteger(25, 50, Convert.ToInt32((Math.Pow(i, 3)))),
RandomInteger(50, 75, Convert.ToInt32((Math.Pow(i, 4)))),
RandomInteger(75, 100, Convert.ToInt32((Math.Pow(i, 5))))});
}
//Creazione Serie
chart1.Series.Clear();
chart1.DataSource = DT;
//Serie1
Series serie1 = new Series("Serie1");
serie1.ChartType = SeriesChartType.Column;
serie1.Color = Color.Goldenrod;
serie1.BorderWidth = 1;
serie1.BorderColor = Color.Black;
serie1.XValueMember = DT.Columns["X"].ToString();
serie1.YValueMembers = DT.Columns["YSerie1"].ToString();
chart1.Series.Add(serie1);
serie1.ToolTip = serie1.Name + " [ #VALX{F0} | #VALY{F2} ]";
//Serie2
Series serie2 = new Series("Serie2");
serie2.ChartType = SeriesChartType.Line;
serie2.Color = Color.Red;
serie2.BorderWidth = 2;
serie2.MarkerSize = 12;
serie2.MarkerBorderColor = Color.Black;
serie2.MarkerBorderWidth = 2;
serie2.MarkerStyle = MarkerStyle.Diamond;
serie2.XValueMember = DT.Columns["X"].ToString();
serie2.YValueMembers = DT.Columns["YSerie2"].ToString();
chart1.Series.Add(serie2);
//Serie3
Series serie3 = new Series("Serie3");
serie3.ChartType = SeriesChartType.Line;
serie3.Color = Color.SlateBlue;
serie3.BorderWidth = 2;
serie3.MarkerSize = 10;
serie3.MarkerBorderColor = Color.Blue;
serie3.MarkerBorderWidth = 2;
serie3.MarkerStyle = MarkerStyle.Circle;
serie3.XValueMember = DT.Columns["X"].ToString();
serie3.YValueMembers = DT.Columns["YSerie3"].ToString();
chart1.Series.Add(serie3);
//Serie4
Series serie4 = new Series("Serie4");
serie4.ChartType = SeriesChartType.Line;
serie4.Color = Color.Green;
serie4.BorderWidth = 2;
serie4.MarkerSize = 8;
serie4.MarkerBorderColor = Color.DarkGreen;
serie4.MarkerBorderWidth = 2;
serie4.MarkerStyle = MarkerStyle.Square;
serie4.XValueMember = DT.Columns["X"].ToString();
serie4.YValueMembers = DT.Columns["YSerie4"].ToString();
chart1.Series.Add(serie4);
cmb_x.DropDownStyle = ComboBoxStyle.DropDownList;
cmb_x.DataSource = DT;
cmb_x.ValueMember = DT.Columns["X"].ToString();
cmb_x.DisplayMember = DT.Columns["X"].ToString();
cmb_serie2.DropDownStyle = ComboBoxStyle.DropDownList;
cmb_serie2.DataSource = DT;
cmb_serie2.ValueMember = DT.Columns["X"].ToString();
cmb_serie2.DisplayMember = DT.Columns["YSerie2"].ToString();
cmb_serie3.DropDownStyle = ComboBoxStyle.DropDownList;
cmb_serie3.DataSource = DT;
cmb_serie3.ValueMember = DT.Columns["X"].ToString();
cmb_serie3.DisplayMember = DT.Columns["YSerie3"].ToString();
}
private void cmb_serie2_SelectedIndexChanged(object sender, EventArgs e)
{
var s2 = chart1.Series["Serie2"];
if (s2.Points.Count == 0)
{
return;
}
for (int i = 0; i < s2.Points.Count; i++)
{
s2.Points[i].Label = string.Empty;
s2.Points[i].MarkerStyle = MarkerStyle.Diamond;
}
var pts2 = chart1.Series["Serie2"].Points[cmb_serie2.SelectedIndex];
pts2.Font = fontLab;
pts2.Label = "Serie2 - " + "X = " + cmb_serie2.SelectedValue + " | Y = " + cmb_serie2.Text;
pts2.LabelBackColor = Color.Gold;
pts2.LabelBorderColor = Color.Black;
pts2.LabelBorderWidth = 1;
pts2.LabelForeColor = Color.Black;
pts2.MarkerStyle = MarkerStyle.Star10;
}
private void cmb_serie3_SelectedIndexChanged(object sender, EventArgs e)
{
var s3 = chart1.Series["Serie3"];
if (s3.Points.Count == 0)
{
return;
}
for (int i = 0; i < s3.Points.Count; i++)
{
s3.Points[i].MarkerImage = string.Empty;
}
var pts3 = chart1.Series["Serie3"].Points[cmb_serie3.SelectedIndex];
pts3.MarkerImage = percorsoBmp + nomeBmp;
pts3.MarkerImageTransparentColor = Color.White;
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
HitTestResult HTR = chart1.HitTest(e.X, e.Y);
//Controllo sul fatto che sia un DataPoint valido
if (!(HTR.ChartElementType == ChartElementType.DataPoint))
{
return;
}
//Controllo sul fatto che sia la Serie desiderata ( Serie4 )
if (!(HTR.Series.Name == "Serie4"))
{
return;
}
var s4 = chart1.Series["Serie4"];
for (int i = 0; i < s4.Points.Count; i++)
{
s4.Points[i].Label = string.Empty;
s4.Points[i].MarkerStyle = MarkerStyle.Square;
}
var pts4 = chart1.Series["Serie4"].Points[HTR.PointIndex];
pts4.Font = fontLab;
pts4.Label = "Serie4 - " + "X = " + pts4.XValue + " | Y = " + pts4.YValues[0];
pts4.LabelBackColor = Color.YellowGreen;
pts4.LabelBorderColor = Color.Black;
pts4.LabelBorderWidth = 1;
pts4.LabelForeColor = Color.Black;
pts4.MarkerStyle = MarkerStyle.Star10;
}
}
}
NOTE :
--> Il Chart, le Serie e anche le ComboBox puntano al medesimo DataTable, chiaramente ciascuno al suo o suoi campi di pertinenza.
--> Serie1 : evidenzia il dato al passaggio del Mouse come semplice ToolTip.
--> Serie2 : evidenzia il dato ( scelto in cmb_serie2 ) con una Label. A mio avviso la scelta più completa e flessibile.
--> Serie3 : evidenzia il dato ( scelto in cmb_serie3 ) con una bitmap caricata da disco. In questo caso sarà necessario predisporre un'immagine che abbia al suo centro il Marker, e uno o più indicatori esterni. La figura seguente mostra come ho creato la mia "arrow.bmp" in 3 semplici passi, aiutandomi semplicemente con le Forme di Word 2007 :
--> Serie4 : evidenzia il dato al passaggio del Mouse con una Label. Comportamento molto simile al ToolTip della Serie1, ma molto più flessibile nella gestione.
--> Come già accennato, una selezione su ciascuna delle 3 ComboBox si propaga alle altre in automatico e senza che sia necessario estendere gli Handles nelle routine di evento, o scrivere alcun codice aggiuntivo, perchè ciò accade solo grazie alle associazioni fatte in precedenza con i Campi del DataTable.
+ Fine Articolo.



16:39
MarcoGG

Posted in:
0 commenti:
Posta un commento