Files
Pat Tullmann 0cb742dafb binfmt-detector-cli: rewrite to support PE32+ binaries (#38)
Rewrite with hard-coded offsets into the PE file format to discern
if a binary is PE32 or PE32+, and then to determine if it contains
a "CLR Data Directory" entry that looks valid.

Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native
binaries, and a random assortment of garbage files.

Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
2023-10-16 20:16:47 +02:00

4362 lines
128 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//-------------------------------------------------------------
// <copyright company=Microsoft Corporation>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: Chart.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
//
// Classes: ChartImage, ChartPicture, ChartPaintEventArgs
//
// Purpose: This file contains classes, which are used for Image
// creation and chart painting. This file has also a
// class, which is used for Paint events arguments.
//
// Reviewed: GS - August 2, 2002
// AG - August 8, 2002
// AG - Microsoft 16, 2007
//
//===================================================================
#region Used Namespaces
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Design;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Resources;
using System.Reflection;
using System.IO;
using System.Data;
using System.Collections;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Xml;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics;
using System.Security;
using System.Runtime.InteropServices;
using System.Collections.Generic;
#if Microsoft_CONTROL
using System.Windows.Forms.DataVisualization.Charting.Data;
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
using System.Windows.Forms.DataVisualization.Charting.Utilities;
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
using System.Windows.Forms.DataVisualization.Charting;
#else
using System.Web;
using System.Web.UI;
using System.Net;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.ChartTypes;
using System.Web.UI.DataVisualization.Charting.Utilities;
using System.Web.UI.DataVisualization.Charting.Borders3D;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
#region Enumerations
#if !Microsoft_CONTROL
/// <summary>
/// An enumeration of supported image types
/// </summary>
public enum ChartImageType
{
/// <summary>
/// BMP image format
/// </summary>
Bmp,
/// <summary>
/// Jpeg image format
/// </summary>
Jpeg,
/// <summary>
/// Png image format
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Png")]
Png,
/// <summary>
/// Enhanced Meta File (Emf) image format.
/// </summary>
Emf,
};
#endif
#endregion
/// <summary>
/// ChartImage class adds image type and data binding functionality to
/// the base ChartPicture class.
/// </summary>
internal class ChartImage : ChartPicture
{
#region Fields
// Private data members, which store properties values
private int _compression = 0;
// Chart data source object
private object _dataSource = null;
// Indicates that control was bound to the data source
internal bool boundToDataSource = false;
#if !Microsoft_CONTROL
private ChartImageType imageType = ChartImageType.Png;
#endif
#endregion
#region Constructor
/// <summary>
/// Chart internal constructor.
/// </summary>
/// <param name="container">Service container</param>
internal ChartImage(IServiceContainer container)
: base(container)
{
}
#endregion // Constructor
#region Properties
/// <summary>
/// Gets or sets the data source for the Chart object.
/// </summary>
[
SRCategory("CategoryAttributeData"),
Bindable(true),
SRDescription("DescriptionAttributeDataSource"),
DefaultValue(null),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden)
]
public object DataSource
{
get
{
return _dataSource;
}
set
{
if(_dataSource != value)
{
_dataSource = value;
this.boundToDataSource = false;
}
}
}
#if !Microsoft_CONTROL
/// <summary>
/// Image type (Jpeg, BMP, Png)
/// </summary>
[
SRCategory("CategoryAttributeImage"),
Bindable(true),
DefaultValue(ChartImageType.Png),
SRDescription("DescriptionAttributeImageType"),
PersistenceMode(PersistenceMode.Attribute)
]
public ChartImageType ImageType
{
get
{
return imageType;
}
set
{
imageType = value;
}
}
#endif
/// <summary>
/// Image compression value
/// </summary>
[
SRCategory("CategoryAttributeImage"),
Bindable(true),
DefaultValue(0),
SRDescription("DescriptionAttributeChartImage_Compression"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public int Compression
{
get
{
return _compression;
}
set
{
if(value < 0 || value > 100)
{
throw (new ArgumentOutOfRangeException("value", SR.ExceptionChartCompressionInvalid));
}
_compression = value;
}
}
#endregion
#region Methods
#region Image Manipulation
/// <summary>
/// Saves image into the metafile stream.
/// </summary>
/// <param name="imageStream">Image stream.</param>
/// <param name="emfType">Image stream.</param>
[SecuritySafeCritical]
public void SaveIntoMetafile(Stream imageStream, EmfType emfType)
{
// Check arguments
if (imageStream == null)
throw new ArgumentNullException("imageStream");
// Create temporary Graphics object for metafile
using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
{
using (Graphics newGraphics = Graphics.FromImage(bitmap))
{
IntPtr hdc = IntPtr.Zero;
try
{
System.Security.Permissions.SecurityPermission securityPermission = new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode);
securityPermission.Demand();
hdc = newGraphics.GetHdc();
// Create metafile object to record.
using (Metafile metaFile = new Metafile(
imageStream,
hdc,
new Rectangle(0, 0, this.Width, this.Height),
MetafileFrameUnit.Pixel,
emfType))
{
// Create graphics object to record metaFile.
using (Graphics metaGraphics = Graphics.FromImage(metaFile))
{
// Note: Fix for issue #3674. Some 3D borders shadows may be drawn outside
// of image boundaries. This causes issues when generated EMF file
// is placed in IE. Image looks shifted down and hot areas do not align.
if (this.BorderSkin.SkinStyle != BorderSkinStyle.None)
{
metaGraphics.Clip = new Region(new Rectangle(0, 0, this.Width, this.Height));
}
// Draw chart in the metafile
this.ChartGraph.IsMetafile = true;
this.Paint(metaGraphics, false);
this.ChartGraph.IsMetafile = false;
}
}
}
finally
{
if (hdc != IntPtr.Zero)
{
newGraphics.ReleaseHdc(hdc);
}
}
}
}
}
public Bitmap GetImage()
{
return this.GetImage(96);
}
/// <summary>
/// Create Image and draw chart picture
/// </summary>
public Bitmap GetImage(float resolution)
{
// Create a new bitmap
Bitmap image = null;
while (image == null)
{
bool failed = true;
try
{
image = new Bitmap(Math.Max(1,Width), Math.Max(1,Height));
image.SetResolution(resolution, resolution);
failed = false;
}
catch (ArgumentException)
{
failed = true;
}
catch (OverflowException)
{
failed = true;
}
catch (InvalidOperationException)
{
failed = true;
}
catch (ExternalException)
{
failed = true;
}
if (failed)
{
// if failed to create the image, decrease the size and the resolution of the chart
image = null;
float newResolution = Math.Max(resolution / 2, 96);
Width = (int)Math.Ceiling(Width * newResolution / resolution);
Height = (int)Math.Ceiling(Height * newResolution / resolution);
resolution = newResolution;
}
}
// Creates a new Graphics object from the
// specified Image object.
Graphics offScreen = Graphics.FromImage( image );
Color backGroundColor;
if (this.BackColor != Color.Empty)
backGroundColor = this.BackColor;
else
backGroundColor = Color.White;
// Get the page color if border skin is visible.
if (GetBorderSkinVisibility() &&
this.BorderSkin.PageColor != Color.Empty)
{
backGroundColor = this.BorderSkin.PageColor;
}
// draw a rctangle first with the size of the control, this prevent strange behavior when printing in the reporting services,
// without this rectangle, the printed picture is blurry
Pen pen = new Pen(backGroundColor);
offScreen.DrawRectangle(pen, 0, 0, Width, Height);
pen.Dispose();
// Paint the chart
Paint( offScreen , false);
// Dispose Graphic object
offScreen.Dispose();
// Return reference to the image
return image;
}
#endregion // Image Manipulation
#region Data Binding
/// <summary>
/// Checks if the type of the data source is valid.
/// </summary>
/// <param name="dataSource">Data source object to test.</param>
/// <returns>True if valid data source object.</returns>
static internal bool IsValidDataSource(object dataSource)
{
if( null != dataSource &&
(
dataSource is IEnumerable ||
dataSource is DataSet ||
dataSource is DataView ||
dataSource is DataTable ||
dataSource is System.Data.OleDb.OleDbCommand ||
dataSource is System.Data.SqlClient.SqlCommand ||
dataSource is System.Data.OleDb.OleDbDataAdapter ||
dataSource is System.Data.SqlClient.SqlDataAdapter ||
// ADDED: for VS2005 compatibility, DT Nov 25, 2005
dataSource.GetType().GetInterface("IDataSource") != null
// END ADDED
)
)
{
return true;
}
return false;
}
/// <summary>
/// Gets an list of the data source member names.
/// </summary>
/// <param name="dataSource">Data source object to get the members for.</param>
/// <param name="usedForYValue">Indicates that member will be used for Y values.</param>
/// <returns>List of member names.</returns>
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
Justification = "Too large of a code change to justify making this change")]
static internal ArrayList GetDataSourceMemberNames(object dataSource, bool usedForYValue)
{
ArrayList names = new ArrayList();
if (dataSource != null)
{
// ADDED: for VS2005 compatibility, DT Nov 25, 2004
if (dataSource.GetType().GetInterface("IDataSource") != null)
{
try
{
MethodInfo m = dataSource.GetType().GetMethod("Select");
if (m != null)
{
if (m.GetParameters().Length == 1)
{
// SQL derived datasource
Type selectArgsType = dataSource.GetType().Assembly.GetType("System.Web.UI.DataSourceSelectArguments", true);
ConstructorInfo ci = selectArgsType.GetConstructor(new Type[] { });
dataSource = m.Invoke(dataSource, new object[] { ci.Invoke(new object[] { }) });
}
else
{
// object data source
dataSource = m.Invoke(dataSource, new object[] { });
}
}
}
catch (TargetException)
{
}
catch (TargetInvocationException)
{
}
}
// END ADDED
// Check all DataTable based data souces
DataTable dataTable = null;
if (dataSource is DataTable)
{
dataTable = (DataTable)dataSource;
}
else if (dataSource is DataView)
{
dataTable = ((DataView)dataSource).Table;
}
else if (dataSource is DataSet && ((DataSet)dataSource).Tables.Count > 0)
{
dataTable = ((DataSet)dataSource).Tables[0];
}
else if (dataSource is System.Data.OleDb.OleDbDataAdapter)
{
dataTable = new DataTable();
dataTable.Locale = CultureInfo.CurrentCulture;
dataTable = ((System.Data.OleDb.OleDbDataAdapter)dataSource).FillSchema(dataTable, SchemaType.Mapped);
}
else if (dataSource is System.Data.SqlClient.SqlDataAdapter)
{
dataTable = new DataTable();
dataTable.Locale = CultureInfo.CurrentCulture;
dataTable = ((System.Data.SqlClient.SqlDataAdapter)dataSource).FillSchema(dataTable, SchemaType.Mapped);
}
else if (dataSource is System.Data.OleDb.OleDbDataReader)
{
// Add table columns names
for (int fieldIndex = 0; fieldIndex < ((System.Data.OleDb.OleDbDataReader)dataSource).FieldCount; fieldIndex++)
{
if (!usedForYValue || ((System.Data.OleDb.OleDbDataReader)dataSource).GetFieldType(fieldIndex) != typeof(string))
{
names.Add(((System.Data.OleDb.OleDbDataReader)dataSource).GetName(fieldIndex));
}
}
}
else if (dataSource is System.Data.SqlClient.SqlDataReader)
{
// Add table columns names
for (int fieldIndex = 0; fieldIndex < ((System.Data.SqlClient.SqlDataReader)dataSource).FieldCount; fieldIndex++)
{
if (!usedForYValue || ((System.Data.SqlClient.SqlDataReader)dataSource).GetFieldType(fieldIndex) != typeof(string))
{
names.Add(((System.Data.SqlClient.SqlDataReader)dataSource).GetName(fieldIndex));
}
}
}
else if (dataSource is System.Data.OleDb.OleDbCommand)
{
System.Data.OleDb.OleDbCommand command = (System.Data.OleDb.OleDbCommand)dataSource;
if (command.Connection != null)
{
command.Connection.Open();
System.Data.OleDb.OleDbDataReader dataReader = command.ExecuteReader();
if (dataReader.Read())
{
for (int fieldIndex = 0; fieldIndex < dataReader.FieldCount; fieldIndex++)
{
if (!usedForYValue || dataReader.GetFieldType(fieldIndex) != typeof(string))
{
names.Add(dataReader.GetName(fieldIndex));
}
}
}
dataReader.Close();
command.Connection.Close();
}
}
else if (dataSource is System.Data.SqlClient.SqlCommand)
{
System.Data.SqlClient.SqlCommand command = (System.Data.SqlClient.SqlCommand)dataSource;
if (command.Connection != null)
{
command.Connection.Open();
System.Data.SqlClient.SqlDataReader dataReader = command.ExecuteReader();
if (dataReader.Read())
{
for (int fieldIndex = 0; fieldIndex < dataReader.FieldCount; fieldIndex++)
{
if (!usedForYValue || dataReader.GetFieldType(fieldIndex) != typeof(string))
{
names.Add(dataReader.GetName(fieldIndex));
}
}
}
dataReader.Close();
command.Connection.Close();
}
}
// Check if DataTable was set
if (dataTable != null)
{
// Add table columns names
foreach (DataColumn column in dataTable.Columns)
{
if (!usedForYValue || column.DataType != typeof(string))
{
names.Add(column.ColumnName);
}
}
}
else if (names.Count == 0 && dataSource is ITypedList)
{
foreach (PropertyDescriptor pd in ((ITypedList)dataSource).GetItemProperties(null))
{
if (!usedForYValue || pd.PropertyType != typeof(string))
{
names.Add(pd.Name);
}
}
}
else if (names.Count == 0 && dataSource is IEnumerable)
{
// .Net 2.0 ObjectDataSource processing
IEnumerator e = ((IEnumerable)dataSource).GetEnumerator();
e.Reset();
e.MoveNext();
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(e.Current))
{
if (!usedForYValue || pd.PropertyType != typeof(string))
{
names.Add(pd.Name);
}
}
}
// Check if list still empty
if (names.Count == 0)
{
// Add first column or any data member name
names.Add("0");
}
}
return names;
}
/// <summary>
/// Data binds control to the data source
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
Justification="Too large of a code change to justify making this change")]
internal void DataBind()
{
// Set bound flag
this.boundToDataSource = true;
object dataSource = this.DataSource;
if (dataSource != null)
{
// Convert data adapters to command object
if (dataSource is System.Data.OleDb.OleDbDataAdapter)
{
dataSource = ((System.Data.OleDb.OleDbDataAdapter)dataSource).SelectCommand;
}
else if (dataSource is System.Data.SqlClient.SqlDataAdapter)
{
dataSource = ((System.Data.SqlClient.SqlDataAdapter)dataSource).SelectCommand;
}
// Convert data source to recognizable source for the series
if (dataSource is DataSet && ((DataSet)dataSource).Tables.Count > 0)
{
dataSource = ((DataSet)dataSource).DefaultViewManager.CreateDataView(((DataSet)dataSource).Tables[0]);
}
else if (dataSource is DataTable)
{
dataSource = new DataView((DataTable)dataSource);
}
else if (dataSource is System.Data.OleDb.OleDbCommand)
{
System.Data.OleDb.OleDbCommand command = (System.Data.OleDb.OleDbCommand)dataSource;
command.Connection.Open();
System.Data.OleDb.OleDbDataReader dataReader = command.ExecuteReader();
this.DataBind(dataReader, null);
dataReader.Close();
command.Connection.Close();
return;
}
else if (dataSource is System.Data.SqlClient.SqlCommand)
{
System.Data.SqlClient.SqlCommand command = (System.Data.SqlClient.SqlCommand)dataSource;
command.Connection.Open();
System.Data.SqlClient.SqlDataReader dataReader = command.ExecuteReader();
this.DataBind(dataReader, null);
dataReader.Close();
command.Connection.Close();
return;
}
else if (dataSource is IList)
{
dataSource = dataSource as IList;
}
else if (dataSource is IListSource )
{
if (((IListSource)dataSource).ContainsListCollection && ((IListSource)dataSource).GetList().Count > 0)
{
dataSource = ((IListSource)dataSource).GetList()[0] as IEnumerable;
}
else
{
dataSource = ((IListSource)dataSource).GetList();
}
}
else
{
dataSource = dataSource as IEnumerable;
}
// Data bind
DataBind(dataSource as IEnumerable, null);
}
}
/// <summary>
/// Data binds control to the data source
/// </summary>
/// <param name="dataSource">Data source to bind to.</param>
/// <param name="seriesList">List of series to bind.</param>
internal void DataBind(IEnumerable dataSource, ArrayList seriesList)
{
// Data bind series
if(dataSource != null && this.Common != null)
{
//************************************************************
//** If list of series is not provided - bind all of them.
//************************************************************
if(seriesList == null)
{
seriesList = new ArrayList();
foreach(Series series in this.Common.Chart.Series)
{
// note: added for design time data binding
if (this.Common.Chart.IsDesignMode())
{
if (series.YValueMembers.Length > 0)
{
seriesList.Add(series);
}
}
else
{
seriesList.Add(series);
}
}
}
//************************************************************
//** Clear all data points in data bound series
//************************************************************
foreach(Series series in seriesList)
{
if(series.XValueMember.Length > 0 || series.YValueMembers.Length > 0)
{
series.Points.Clear();
}
}
//************************************************************
//** Get and reset data enumerator.
//************************************************************
IEnumerator enumerator = dataSource.GetEnumerator();
if(enumerator.GetType() != typeof(System.Data.Common.DbEnumerator) )
{
try
{
enumerator.Reset();
}
// Some enumerators may not support Resetting
catch (InvalidOperationException)
{
}
catch (NotImplementedException)
{
}
catch (NotSupportedException)
{
}
}
//************************************************************
//** Loop through the enumerator.
//************************************************************
bool valueExsists = true;
bool autoDetectType = true;
do
{
// Move to the next item
valueExsists = enumerator.MoveNext();
// Loop through all series
foreach(Series series in seriesList)
{
if(series.XValueMember.Length > 0 || series.YValueMembers.Length > 0)
{
//************************************************************
//** Check and convert fields names.
//************************************************************
// Convert comma separated field names string to array of names
string[] yFieldNames = null;
if(series.YValueMembers.Length > 0)
{
yFieldNames = series.YValueMembers.Replace(",,", "\n").Split(',');
for(int index = 0; index < yFieldNames.Length; index++)
{
yFieldNames[index] = yFieldNames[index].Replace("\n", ",").Trim();
}
}
// Double check that a string object is not provided for data binding
if(dataSource is string)
{
throw (new ArgumentException(SR.ExceptionDataBindYValuesToString, "dataSource"));
}
// Check number of fields
if(yFieldNames == null || yFieldNames.GetLength(0) > series.YValuesPerPoint)
{
throw(new ArgumentOutOfRangeException("dataSource", SR.ExceptionDataPointYValuesCountMismatch(series.YValuesPerPoint.ToString(System.Globalization.CultureInfo.InvariantCulture) ) ) );
}
//************************************************************
//** Create new data point.
//************************************************************
if(valueExsists)
{
// Auto detect values type
if(autoDetectType)
{
autoDetectType = false;
// Make sure Y field is not empty
string yField = yFieldNames[0];
int fieldIndex = 1;
while(yField.Length == 0 && fieldIndex < yFieldNames.Length)
{
yField = yFieldNames[fieldIndex++];
}
DataPointCollection.AutoDetectValuesType(series, enumerator, series.XValueMember.Trim(), enumerator, yField);
}
// Create new point
DataPoint newDataPoint = new DataPoint(series);
bool emptyValues = false;
bool xValueIsNull = false;
//************************************************************
//** Get new point X and Y values.
//************************************************************
object[] yValuesObj = new object[yFieldNames.Length];
object xValueObj = null;
// Set X to the value provided or use sequence numbers starting with 1
if(series.XValueMember.Length > 0)
{
xValueObj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, series.XValueMember.Trim());
if(xValueObj is System.DBNull || xValueObj == null)
{
xValueIsNull = true;
emptyValues = true;
xValueObj = 0.0;
}
}
if(yFieldNames.Length == 0)
{
yValuesObj[0] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, null);
if(yValuesObj[0] is System.DBNull || yValuesObj[0] == null)
{
emptyValues = true;
yValuesObj[0] = 0.0;
}
}
else
{
for(int i = 0; i < yFieldNames.Length; i++)
{
if(yFieldNames[i].Length > 0)
{
yValuesObj[i] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, yFieldNames[i]);
if(yValuesObj[i] is System.DBNull || yValuesObj[i] == null)
{
emptyValues = true;
yValuesObj[i] = 0.0;
}
}
else
{
yValuesObj[i] = (((Series)seriesList[0]).IsYValueDateTime()) ? DateTime.Now.Date.ToOADate() : 0.0;
}
}
}
// Add data point if X value is not Null
if(!xValueIsNull)
{
if(emptyValues)
{
if(xValueObj != null)
{
newDataPoint.SetValueXY(xValueObj, yValuesObj);
}
else
{
newDataPoint.SetValueXY(0, yValuesObj);
}
series.Points.DataPointInit(ref newDataPoint);
newDataPoint.IsEmpty = true;
series.Points.Add(newDataPoint);
}
else
{
if(xValueObj != null)
{
newDataPoint.SetValueXY(xValueObj, yValuesObj);
}
else
{
newDataPoint.SetValueXY(0, yValuesObj);
}
series.Points.DataPointInit(ref newDataPoint);
series.Points.Add(newDataPoint);
}
}
if (this.Common.Chart.IsDesignMode())
{
series["TempDesignData"] = "true";
}
}
}
}
} while(valueExsists);
}
}
/// <summary>
/// Aligns data points using their axis labels.
/// </summary>
/// <param name="sortAxisLabels">Indicates if points should be sorted by axis labels.</param>
/// <param name="sortingOrder">Sorting pointSortOrder.</param>
internal void AlignDataPointsByAxisLabel(bool sortAxisLabels, PointSortOrder sortingOrder)
{
// Find series which are attached to the same X axis in the same chart area
foreach(ChartArea chartArea in this.ChartAreas)
{
// Check if chart area is visible
if(chartArea.Visible)
{
// Create series list for primary and secondary X axis
ArrayList chartAreaSeriesPrimary = new ArrayList();
ArrayList chartAreaSeriesSecondary = new ArrayList();
foreach(Series series in this.Common.Chart.Series)
{
// Check if series belongs to the chart area
if (series.ChartArea == chartArea.Name)
{
if(series.XSubAxisName.Length == 0)
{
if(series.XAxisType == AxisType.Primary)
{
chartAreaSeriesPrimary.Add(series);
}
else
{
chartAreaSeriesSecondary.Add(series);
}
}
}
}
// Align series
AlignDataPointsByAxisLabel(chartAreaSeriesPrimary, sortAxisLabels, sortingOrder);
AlignDataPointsByAxisLabel(chartAreaSeriesSecondary, sortAxisLabels, sortingOrder);
}
}
}
/// <summary>
/// Aligns data points using their axis labels.
/// </summary>
/// <param name="seriesList">List of series to align.</param>
/// <param name="sortAxisLabels">Indicates if points should be sorted by axis labels.</param>
/// <param name="sortingOrder">Sorting order.</param>
internal void AlignDataPointsByAxisLabel(
ArrayList seriesList,
bool sortAxisLabels,
PointSortOrder sortingOrder)
{
// List is empty
if(seriesList.Count == 0)
{
return;
}
// Collect information about all points in all series
bool indexedX = true;
bool uniqueAxisLabels = true;
ArrayList axisLabels = new ArrayList();
foreach(Series series in seriesList)
{
ArrayList seriesAxisLabels = new ArrayList();
foreach(DataPoint point in series.Points)
{
// Check if series has indexed X values
if(!series.IsXValueIndexed && point.XValue != 0.0)
{
indexedX = false;
break;
}
// Add axis label to the list and make sure it's non-empty and unique
if(point.AxisLabel.Length == 0)
{
uniqueAxisLabels = false;
break;
}
else if(seriesAxisLabels.Contains(point.AxisLabel))
{
uniqueAxisLabels = false;
break;
}
else if(!axisLabels.Contains(point.AxisLabel))
{
axisLabels.Add(point.AxisLabel);
}
seriesAxisLabels.Add(point.AxisLabel);
}
}
// Sort axis labels
if(sortAxisLabels)
{
axisLabels.Sort();
if(sortingOrder == PointSortOrder.Descending)
{
axisLabels.Reverse();
}
}
// All series must be indexed
if(!indexedX)
{
throw (new InvalidOperationException(SR.ExceptionChartDataPointsAlignmentFaild));
}
// AxisLabel can't be empty or duplicated
if(!uniqueAxisLabels)
{
throw (new InvalidOperationException(SR.ExceptionChartDataPointsAlignmentFaildAxisLabelsInvalid));
}
// Assign unique X values for data points in all series with same axis LabelStyle
if(indexedX && uniqueAxisLabels)
{
foreach(Series series in seriesList)
{
foreach(DataPoint point in series.Points)
{
point.XValue = axisLabels.IndexOf(point.AxisLabel) + 1;
}
// Sort points by X value
series.Sort(PointSortOrder.Ascending, "X");
}
// Make sure ther are no missing points
foreach(Series series in seriesList)
{
series.IsXValueIndexed = true;
for(int index = 0; index < axisLabels.Count; index++)
{
if(index >= series.Points.Count ||
series.Points[index].XValue != index + 1)
{
DataPoint newPoint = new DataPoint(series);
newPoint.AxisLabel = (string)axisLabels[index];
newPoint.XValue = index + 1;
newPoint.YValues[0] = 0.0;
newPoint.IsEmpty = true;
series.Points.Insert(index, newPoint);
}
}
}
}
}
/// <summary>
/// Data bind chart to the table. Series will be automatically added to the chart depending on
/// the number of unique values in the seriesGroupByField column of the data source.
/// Data source can be the Ole(SQL)DataReader, DataView, DataSet, DataTable or DataRow.
/// </summary>
/// <param name="dataSource">Data source.</param>
/// <param name="seriesGroupByField">Name of the field used to group data into series.</param>
/// <param name="xField">Name of the field for X values.</param>
/// <param name="yFields">Comma separated name(s) of the field(s) for Y value(s).</param>
/// <param name="otherFields">Other point properties binding rule in format: PointProperty=Field[{Format}] [,PointProperty=Field[{Format}]]. For example: "Tooltip=Price{C1},Url=WebSiteName".</param>
/// <param name="sort">Indicates that series should be sorted by group field.</param>
/// <param name="sortingOrder">Series sorting order by group field.</param>
internal void DataBindCrossTab(
IEnumerable dataSource,
string seriesGroupByField,
string xField,
string yFields,
string otherFields,
bool sort,
PointSortOrder sortingOrder)
{
// Check arguments
if (dataSource == null)
throw (new ArgumentNullException("dataSource", SR.ExceptionDataPointInsertionNoDataSource));
if (dataSource is string)
throw (new ArgumentException(SR.ExceptionDataBindSeriesToString, "dataSource"));
if (String.IsNullOrEmpty(yFields))
throw (new ArgumentException(SR.ExceptionChartDataPointsInsertionFailedYValuesEmpty, "yFields"));
if (String.IsNullOrEmpty(seriesGroupByField))
throw (new ArgumentException(SR.ExceptionDataBindSeriesGroupByParameterIsEmpty, "seriesGroupByField"));
// List of series and group by field values
ArrayList seriesList = new ArrayList();
ArrayList groupByValueList = new ArrayList();
// Convert comma separated Y values field names string to array of names
string[] yFieldNames = null;
if(yFields != null)
{
yFieldNames = yFields.Replace(",,", "\n").Split(',');
for(int index = 0; index < yFieldNames.Length; index++)
{
yFieldNames[index] = yFieldNames[index].Replace("\n", ",");
}
}
// Convert other fields/properties names to two arrays of names
string[] otherAttributeNames = null;
string[] otherFieldNames = null;
string[] otherValueFormat = null;
DataPointCollection.ParsePointFieldsParameter(
otherFields,
ref otherAttributeNames,
ref otherFieldNames,
ref otherValueFormat);
// Get and reset enumerator
IEnumerator enumerator = DataPointCollection.GetDataSourceEnumerator(dataSource);
if(enumerator.GetType() != typeof(System.Data.Common.DbEnumerator))
{
try
{
enumerator.Reset();
}
// Some enumerators may not support Resetting
catch (NotSupportedException)
{
}
catch (NotImplementedException)
{
}
catch (InvalidOperationException)
{
}
}
// Add data points
bool valueExsist = true;
object[] yValuesObj = new object[yFieldNames.Length];
object xValueObj = null;
bool autoDetectType = true;
do
{
// Move to the next objects in the enumerations
if(valueExsist)
{
valueExsist = enumerator.MoveNext();
}
// Create and initialize data point
if(valueExsist)
{
// Get value of the group by field
object groupObj = DataPointCollection.ConvertEnumerationItem(
enumerator.Current,
seriesGroupByField);
// Check series group by field and create new series if required
Series series = null;
int seriesIndex = groupByValueList.IndexOf(groupObj);
if(seriesIndex >= 0)
{
// Select existing series from the list
series = (Series)seriesList[seriesIndex];
}
else
{
// Create new series
series = new Series();
series.YValuesPerPoint = yFieldNames.GetLength(0);
// If not the first series in the list copy some properties
if(seriesList.Count > 0)
{
series.XValueType = ((Series)seriesList[0]).XValueType;
series.autoXValueType = ((Series)seriesList[0]).autoXValueType;
series.YValueType = ((Series)seriesList[0]).YValueType;
series.autoYValueType = ((Series)seriesList[0]).autoYValueType;
}
// Try to set series name based on grouping vlaue
string groupObjStr = groupObj as string;
if(groupObjStr != null)
{
series.Name = groupObjStr;
}
else
{
series.Name = seriesGroupByField + " - " + groupObj.ToString();
}
// Add series and group value into the lists
groupByValueList.Add(groupObj);
seriesList.Add(series);
}
// Auto detect valu(s) type
if(autoDetectType)
{
autoDetectType = false;
DataPointCollection.AutoDetectValuesType(series, enumerator, xField, enumerator, yFieldNames[0]);
}
// Create new data point
DataPoint newDataPoint = new DataPoint(series);
bool emptyValues = false;
// Set X to the value provided
if(xField.Length > 0)
{
xValueObj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, xField);
if( DataPointCollection.IsEmptyValue(xValueObj) )
{
emptyValues = true;
xValueObj = 0.0;
}
}
// Set Y values
if(yFieldNames.Length == 0)
{
yValuesObj[0] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, null);
if( DataPointCollection.IsEmptyValue(yValuesObj[0]) )
{
emptyValues = true;
yValuesObj[0] = 0.0;
}
}
else
{
for(int i = 0; i < yFieldNames.Length; i++)
{
yValuesObj[i] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, yFieldNames[i]);
if( DataPointCollection.IsEmptyValue(yValuesObj[i] ) )
{
emptyValues = true;
yValuesObj[i] = 0.0;
}
}
}
// Set other values
if(otherAttributeNames != null &&
otherAttributeNames.Length > 0)
{
for(int i = 0; i < otherFieldNames.Length; i++)
{
// Get object by field name
object obj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, otherFieldNames[i]);
if( !DataPointCollection.IsEmptyValue( obj ) )
{
newDataPoint.SetPointCustomProperty(
obj,
otherAttributeNames[i],
otherValueFormat[i]);
}
}
}
// IsEmpty value was detected
if(emptyValues)
{
if(xValueObj != null)
{
newDataPoint.SetValueXY(xValueObj, yValuesObj);
}
else
{
newDataPoint.SetValueXY(0, yValuesObj);
}
DataPointCollection.DataPointInit(series, ref newDataPoint);
newDataPoint.IsEmpty = true;
series.Points.Add(newDataPoint);
}
else
{
if(xValueObj != null)
{
newDataPoint.SetValueXY(xValueObj, yValuesObj);
}
else
{
newDataPoint.SetValueXY(0, yValuesObj);
}
DataPointCollection.DataPointInit(series, ref newDataPoint);
series.Points.Add(newDataPoint);
}
}
} while(valueExsist);
// Sort series usig values of group by field
if(sort)
{
// Duplicate current list
ArrayList oldList = (ArrayList)groupByValueList.Clone();
// Sort list
groupByValueList.Sort();
if(sortingOrder == PointSortOrder.Descending)
{
groupByValueList.Reverse();
}
// Change order of series in collection
ArrayList sortedSeriesList = new ArrayList();
foreach(object obj in groupByValueList)
{
sortedSeriesList.Add(seriesList[oldList.IndexOf(obj)]);
}
seriesList = sortedSeriesList;
}
// Add all series from the list into the series collection
foreach(Series series in seriesList)
{
this.Common.Chart.Series.Add(series);
}
}
/// <summary>
/// Automatically creates and binds series to specified data table.
/// Each column of the table becomes a Y value in a separate series.
/// Series X value field may also be provided.
/// </summary>
/// <param name="dataSource">Data source.</param>
/// <param name="xField">Name of the field for series X values.</param>
internal void DataBindTable(
IEnumerable dataSource,
string xField)
{
// Check arguments
if (dataSource == null)
throw new ArgumentNullException("dataSource");
// Get list of member names from the data source
ArrayList dataSourceFields = GetDataSourceMemberNames(dataSource, true);
// Remove X value field if it's there
if (xField != null && xField.Length > 0)
{
int index = -1;
for (int i = 0; i < dataSourceFields.Count; i++)
{
if ( String.Equals((string)dataSourceFields[i], xField, StringComparison.OrdinalIgnoreCase ) )
{
index = i;
break;
}
}
if (index >= 0)
{
dataSourceFields.RemoveAt(index);
}
else
{
// Check if field name passed as index
bool parseSucceed = int.TryParse(xField, NumberStyles.Any, CultureInfo.InvariantCulture, out index);
if (parseSucceed && index >= 0 && index < dataSourceFields.Count)
{
dataSourceFields.RemoveAt(index);
}
}
}
// Get number of series
int seriesNumber = dataSourceFields.Count;
if (seriesNumber > 0)
{
// Create as many series as fields in the data source
ArrayList seriesList = new ArrayList();
int index = 0;
foreach (string fieldName in dataSourceFields)
{
Series series = new Series(fieldName);
// Set binding properties
series.YValueMembers = fieldName;
series.XValueMember = xField;
// Add to list
seriesList.Add(series);
++index;
}
// Data bind series
this.DataBind(dataSource, seriesList);
// Add all series from the list into the series collection
foreach (Series series in seriesList)
{
// Clear binding properties
series.YValueMembers = String.Empty;
series.XValueMember = String.Empty;
// Add series into the list
this.Common.Chart.Series.Add(series);
}
}
}
#endregion // Data Binding
#endregion
}
/// <summary>
/// ChartPicture class represents chart content like legends, titles,
/// chart areas and series. It provides methods for positioning and
/// drawing all chart elements.
/// </summary>
internal class ChartPicture : ChartElement, IServiceProvider
{
#region Fields
/// <summary>
/// Indicates that chart exceptions should be suppressed.
/// </summary>
private bool _suppressExceptions = false;
// Chart Graphic object
internal ChartGraphics ChartGraph { get; set; }
// Private data members, which store properties values
private GradientStyle _backGradientStyle = GradientStyle.None;
private Color _backSecondaryColor = Color.Empty;
private Color _backColor = Color.White;
private string _backImage = "";
private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile;
private Color _backImageTransparentColor = Color.Empty;
private ChartImageAlignmentStyle _backImageAlign = ChartImageAlignmentStyle.TopLeft;
private Color _borderColor = Color.White;
private int _borderWidth = 1;
private ChartDashStyle _borderDashStyle = ChartDashStyle.NotSet;
private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None;
private AntiAliasingStyles _antiAliasing = AntiAliasingStyles.All;
private TextAntiAliasingQuality _textAntiAliasingQuality = TextAntiAliasingQuality.High;
private bool _isSoftShadows = true;
private int _width = 300;
private int _height = 300;
private DataManipulator _dataManipulator = new DataManipulator();
internal HotRegionsList hotRegionsList = null;
private BorderSkin _borderSkin = null;
#if !Microsoft_CONTROL
private bool _isMapEnabled = true;
private MapAreasCollection _mapAreas = null;
#endif
// Chart areas collection
private ChartAreaCollection _chartAreas = null;
// Chart legend collection
private LegendCollection _legends = null;
// Chart title collection
private TitleCollection _titles = null;
// Chart annotation collection
private AnnotationCollection _annotations = null;
// Annotation smart labels class
internal AnnotationSmartLabel annotationSmartLabel = new AnnotationSmartLabel();
// Chart picture events
internal event EventHandler<ChartPaintEventArgs> BeforePaint;
internal event EventHandler<ChartPaintEventArgs> AfterPaint;
// Chart title position rectangle
private RectangleF _titlePosition = RectangleF.Empty;
// Element spacing size
internal const float elementSpacing = 3F;
// Maximum size of the font in percentage
internal const float maxTitleSize = 15F;
// Printing indicator
internal bool isPrinting = false;
// Indicates chart selection mode
internal bool isSelectionMode = false;
private FontCache _fontCache = new FontCache();
// Position of the chart 3D border
private RectangleF _chartBorderPosition = RectangleF.Empty;
#if Microsoft_CONTROL
// Saving As Image indicator
internal bool isSavingAsImage = false;
// Indicates that chart background is restored from the double buffer
// prior to drawing top level objects like annotations, cursors and selection.
internal bool backgroundRestored = false;
// Buffered image of non-top level chart elements
internal Bitmap nonTopLevelChartBuffer = null;
#endif // Microsoft_CONTROL
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
/// <param name="container">Service container</param>
public ChartPicture(IServiceContainer container)
{
if(container == null)
{
throw(new ArgumentNullException(SR.ExceptionInvalidServiceContainer));
}
// Create and set Common Elements
Common = new CommonElements(container);
ChartGraph= new ChartGraphics(Common);
hotRegionsList = new HotRegionsList(Common);
// Create border properties class
_borderSkin = new BorderSkin(this);
// Create a collection of chart areas
_chartAreas = new ChartAreaCollection(this);
// Create a collection of legends
_legends = new LegendCollection(this);
// Create a collection of titles
_titles = new TitleCollection(this);
// Create a collection of annotations
_annotations = new AnnotationCollection(this);
// Set Common elements for data manipulator
_dataManipulator.Common = Common;
#if !Microsoft_CONTROL
// Create map areas collection
_mapAreas = new MapAreasCollection();
#endif
}
/// <summary>
/// Returns Chart service object
/// </summary>
/// <param name="serviceType">Service AxisName</param>
/// <returns>Chart picture</returns>
[EditorBrowsableAttribute(EditorBrowsableState.Never)]
object IServiceProvider.GetService(Type serviceType)
{
if(serviceType == typeof(ChartPicture))
{
return this;
}
throw (new ArgumentException( SR.ExceptionChartPictureUnsupportedType( serviceType.ToString() ) ) );
}
#endregion
#region Painting and selection methods
/// <summary>
/// Performs empty painting.
/// </summary>
internal void PaintOffScreen()
{
// Check chart size
// NOTE: Fixes issue #4733
if (this.Width <= 0 || this.Height <= 0)
{
return;
}
// Set process Mode to hot regions
this.Common.HotRegionsList.ProcessChartMode |= ProcessMode.HotRegions;
#if Microsoft_CONTROL
this.Common.HotRegionsList.hitTestCalled = true;
#endif // Microsoft_CONTROL
// Enable selection mode
this.isSelectionMode = true;
// Hot Region list does not exist. Create the list.
//this.common.HotRegionsList.List = new ArrayList();
this.Common.HotRegionsList.Clear();
// Create a new bitmap
Bitmap image = new Bitmap(Math.Max(1,Width), Math.Max(1,Height));
// Creates a new Graphics object from the
// specified Image object.
Graphics offScreen = Graphics.FromImage(image);
// Connect Graphics object with Chart Graphics object
ChartGraph.Graphics = offScreen;
// Remember the previous dirty flag
#if Microsoft_CONTROL
bool oldDirtyFlag = this.Common.Chart.dirtyFlag;
#endif //Microsoft_CONTROL
Paint(ChartGraph.Graphics, false);
image.Dispose();
// Restore the previous dirty flag
#if Microsoft_CONTROL
this.Common.Chart.dirtyFlag = oldDirtyFlag;
#endif //Microsoft_CONTROL
// Disable selection mode
this.isSelectionMode = false;
// Set process Mode to hot regions
this.Common.HotRegionsList.ProcessChartMode |= ProcessMode.HotRegions;
}
/// <summary>
/// Gets text rendering quality.
/// </summary>
/// <returns>Text rendering quality.</returns>
internal TextRenderingHint GetTextRenderingHint()
{
TextRenderingHint result = TextRenderingHint.SingleBitPerPixelGridFit;
if( (this.AntiAliasing & AntiAliasingStyles.Text) == AntiAliasingStyles.Text )
{
result = TextRenderingHint.ClearTypeGridFit;
if(this.TextAntiAliasingQuality == TextAntiAliasingQuality.Normal)
{
result = TextRenderingHint.AntiAlias;
}
else if(this.TextAntiAliasingQuality == TextAntiAliasingQuality.SystemDefault)
{
result = TextRenderingHint.SystemDefault;
}
}
else
{
result = TextRenderingHint.SingleBitPerPixelGridFit;
}
return result;
}
internal bool GetBorderSkinVisibility()
{
return _borderSkin.SkinStyle != BorderSkinStyle.None && this.Width > 20 && this.Height > 20;
}
/// <summary>
/// This function paints a chart.
/// </summary>
/// <param name="graph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param>
/// <param name="paintTopLevelElementOnly">Indicates that only chart top level elements like cursors, selection or annotation objects must be redrawn.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "3#svg")]
internal void Paint(
Graphics graph,
bool paintTopLevelElementOnly )
{
#if Microsoft_CONTROL
// Reset restored and saved backgound flags
this.backgroundRestored = false;
#endif // Microsoft_CONTROL
// Reset Annotation Smart Labels
this.annotationSmartLabel.Reset();
// Do not draw the control if size is less than 5 pixel
if (this.Width < 5 || this.Height < 5)
{
return;
}
#if Microsoft_CONTROL
bool resetHotRegionList = false;
if(
this.Common.HotRegionsList.hitTestCalled
|| IsToolTipsEnabled()
)
{
Common.HotRegionsList.ProcessChartMode = ProcessMode.HotRegions | ProcessMode.Paint;
this.Common.HotRegionsList.hitTestCalled = false;
// Clear list of hot regions
if(paintTopLevelElementOnly)
{
// If repainting only top level elements (annotations) -
// clear top level objects hot regions only
for(int index = 0; index < this.Common.HotRegionsList.List.Count; index++)
{
HotRegion region = (HotRegion)this.Common.HotRegionsList.List[index];
if(region.Type == ChartElementType.Annotation)
{
this.Common.HotRegionsList.List.RemoveAt(index);
--index;
}
}
}
else
{
// If repainting whole chart - clear all hot regions
resetHotRegionList = true;
}
}
else
{
Common.HotRegionsList.ProcessChartMode = ProcessMode.Paint;
// If repainting whole chart - clear all hot regions
resetHotRegionList = true;
}
// Reset hot region list
if(resetHotRegionList)
{
this.Common.HotRegionsList.Clear();
}
#else
if( this.IsMapEnabled )
{
Common.HotRegionsList.ProcessChartMode |= ProcessMode.ImageMaps | ProcessMode.Paint;
// Clear any existing non-custom image map areas
for(int index = 0; index < this.MapAreas.Count; index++)
{
MapArea mapArea = this.MapAreas[index];
if(!mapArea.IsCustom)
{
this.MapAreas.RemoveAt(index);
--index;
}
}
}
#endif //#if Microsoft_CONTROL
// Check if control was data bound
ChartImage chartImage = this as ChartImage;
if(chartImage != null && !chartImage.boundToDataSource)
{
if(this.Common != null && this.Common.Chart != null && !this.Common.Chart.IsDesignMode())
{
this.Common.Chart.DataBind();
}
}
// Connect Graphics object with Chart Graphics object
ChartGraph.Graphics = graph;
Common.graph = ChartGraph;
// Set anti alias mode
ChartGraph.AntiAliasing = _antiAliasing;
ChartGraph.softShadows = _isSoftShadows;
ChartGraph.TextRenderingHint = GetTextRenderingHint();
try
{
// Check if only chart area cursors and annotations must be redrawn
if(!paintTopLevelElementOnly)
{
// Fire Before Paint event
OnBeforePaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
// Flag indicates that resize method should be called
// after adjusting the intervals in 3D charts
bool resizeAfterIntervalAdjusting = false;
// RecalculateAxesScale paint chart areas
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.Set3DAnglesAndReverseMode();
area.SetTempValues();
area.ReCalcInternal();
// Resize should be called the second time
if( area.Area3DStyle.Enable3D && !area.chartAreaIsCurcular)
{
resizeAfterIntervalAdjusting = true;
}
}
}
// Call Customize event
this.Common.Chart.CallOnCustomize();
// Resize picture
Resize(ChartGraph, resizeAfterIntervalAdjusting);
// This code is introduce because labels has to
// be changed when scene is rotated.
bool intervalReCalculated = false;
foreach (ChartArea area in _chartAreas )
{
if( area.Area3DStyle.Enable3D &&
!area.chartAreaIsCurcular
&& area.Visible
)
{
// Make correction for interval in 3D space
intervalReCalculated = true;
area.Estimate3DInterval( ChartGraph );
area.ReCalcInternal();
}
}
// Resize chart areas after updating 3D interval
if(resizeAfterIntervalAdjusting)
{
// NOTE: Fixes issue #6808.
// In 3D chart area interval will be changed to compenstae for the axis rotation angle.
// This will cause all standard labels to be changed. We need to call the customize event
// the second time to give user a chance to modify those labels.
if (intervalReCalculated)
{
// Call Customize event
this.Common.Chart.CallOnCustomize();
}
// Resize chart elements
Resize(ChartGraph);
}
//***********************************************************************
//** Draw chart 3D border
//***********************************************************************
if (GetBorderSkinVisibility())
{
// Fill rectangle with page color
ChartGraph.FillRectangleAbs( new RectangleF( 0, 0, Width-1 , Height-1 ),
_borderSkin.PageColor,
ChartHatchStyle.None,
"",
ChartImageWrapMode.Tile,
Color.Empty,
ChartImageAlignmentStyle.Center,
GradientStyle.None,
Color.Empty,
_borderSkin.PageColor,
1,
ChartDashStyle.Solid,
PenAlignment.Inset );
// Draw 3D border
ChartGraph.Draw3DBorderAbs(
_borderSkin,
this._chartBorderPosition,
BackColor,
BackHatchStyle,
BackImage,
BackImageWrapMode,
BackImageTransparentColor,
BackImageAlignment,
BackGradientStyle,
BackSecondaryColor,
BorderColor,
BorderWidth,
BorderDashStyle);
}
// Paint Background
else
{
ChartGraph.FillRectangleAbs( new RectangleF( 0, 0, Width-1 , Height-1 ),
BackColor,
BackHatchStyle,
BackImage,
BackImageWrapMode,
BackImageTransparentColor,
BackImageAlignment,
BackGradientStyle,
BackSecondaryColor,
BorderColor,
BorderWidth,
BorderDashStyle,
PenAlignment.Inset );
}
// Call BackPaint event
this.Chart.CallOnPrePaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
// Call paint function for each chart area.
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.Paint(ChartGraph);
}
}
// This code is introduced because of GetPointsInterval method,
// which is very time consuming. There is no reason to calculate
// interval after painting.
foreach (ChartArea area in _chartAreas )
{
// Reset interval data
area.intervalData = double.NaN;
}
// Draw Legends
foreach(Legend legendCurrent in this.Legends)
{
legendCurrent.Paint(ChartGraph);
}
// Draw chart titles from the collection
foreach(Title titleCurrent in this.Titles)
{
titleCurrent.Paint(ChartGraph);
}
// Call Paint event
this.Chart.CallOnPostPaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
}
// Draw annotation objects
this.Annotations.Paint(ChartGraph, paintTopLevelElementOnly);
// Draw chart areas cursors in all areas.
// Only if not in selection
if(!this.isSelectionMode)
{
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.PaintCursors(ChartGraph, paintTopLevelElementOnly);
}
}
}
// Return default values
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.Restore3DAnglesAndReverseMode();
area.GetTempValues();
}
}
}
catch(System.Exception)
{
throw;
}
finally
{
// Fire After Paint event
OnAfterPaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
// Restore temp values for each chart area
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.Restore3DAnglesAndReverseMode();
area.GetTempValues();
}
}
#if !Microsoft_CONTROL
if (this.Chart.IsDesignMode())
{
this.Chart.MapAreas.RemoveNonCustom();
}
#endif //!Microsoft_CONTROL
}
}
/// <summary>
/// Invoke before paint delegates.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnBeforePaint(ChartPaintEventArgs e)
{
if (BeforePaint != null)
{
//Invokes the delegates.
BeforePaint(this, e);
}
}
/// <summary>
/// Invoke after paint delegates.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnAfterPaint(ChartPaintEventArgs e)
{
if (AfterPaint != null)
{
//Invokes the delegates.
AfterPaint(this, e);
}
}
internal override void Invalidate()
{
base.Invalidate();
#if Microsoft_CONTROL
if (Chart!=null)
Chart.Invalidate();
#endif
}
#endregion
#region Resizing methods
/// <summary>
/// Resize the chart picture.
/// </summary>
/// <param name="chartGraph">Chart graphics.</param>
public void Resize(ChartGraphics chartGraph)
{
Resize(chartGraph, false);
}
/// <summary>
/// Resize the chart picture.
/// </summary>
/// <param name="chartGraph">Chart graphics.</param>
/// <param name="calcAreaPositionOnly">Indicates that only chart area position is calculated.</param>
public void Resize(ChartGraphics chartGraph, bool calcAreaPositionOnly)
{
// Set the chart size for Common elements
Common.Width = _width;
Common.Height = _height;
// Set the chart size for Chart graphics
chartGraph.SetPictureSize( _width, _height );
// Initialize chart area(s) rectangle
RectangleF chartAreasRectangle = new RectangleF(0, 0, _width - 1, _height - 1);
chartAreasRectangle = chartGraph.GetRelativeRectangle(chartAreasRectangle);
//******************************************************
//** Get the 3D border interface
//******************************************************
_titlePosition = RectangleF.Empty;
IBorderType border3D = null;
bool titleInBorder = false;
if(_borderSkin.SkinStyle != BorderSkinStyle.None)
{
// Set border size
this._chartBorderPosition = chartGraph.GetAbsoluteRectangle(chartAreasRectangle);
// Get border interface
border3D = Common.BorderTypeRegistry.GetBorderType(_borderSkin.SkinStyle.ToString());
if(border3D != null)
{
border3D.Resolution = chartGraph.Graphics.DpiX;
// Check if title should be displayed in the border
titleInBorder = border3D.GetTitlePositionInBorder() != RectangleF.Empty;
_titlePosition = chartGraph.GetRelativeRectangle(border3D.GetTitlePositionInBorder());
_titlePosition.Width = chartAreasRectangle.Width - _titlePosition.Width;
// Adjust are position to the border size
border3D.AdjustAreasPosition(chartGraph, ref chartAreasRectangle);
}
}
//******************************************************
//** Calculate position of all titles in the collection
//******************************************************
RectangleF frameTitlePosition = RectangleF.Empty;
if(titleInBorder)
{
frameTitlePosition = new RectangleF(_titlePosition.Location, _titlePosition.Size);
}
foreach(Title title in this.Titles)
{
if (title.DockedToChartArea == Constants.NotSetValue &&
title.Position.Auto &&
title.Visible)
{
title.CalcTitlePosition(chartGraph, ref chartAreasRectangle, ref frameTitlePosition, elementSpacing);
}
}
//******************************************************
//** Calculate position of all legends in the collection
//******************************************************
this.Legends.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing);
//******************************************************
//** Calculate position of the chart area(s)
//******************************************************
chartAreasRectangle.Width -= elementSpacing;
chartAreasRectangle.Height -= elementSpacing;
RectangleF areaPosition = new RectangleF();
// Get number of chart areas that requeres automatic positioning
int areaNumber = 0;
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
if(area.Position.Auto)
{
++areaNumber;
}
}
}
// Calculate how many columns & rows of areas we going to have
int areaColumns = (int)Math.Floor(Math.Sqrt(areaNumber));
if(areaColumns < 1)
{
areaColumns = 1;
}
int areaRows = (int)Math.Ceiling(((float)areaNumber) / ((float)areaColumns));
// Set position for all areas
int column = 0;
int row = 0;
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
if(area.Position.Auto)
{
// Calculate area position
areaPosition.Width = chartAreasRectangle.Width / areaColumns - elementSpacing;
areaPosition.Height = chartAreasRectangle.Height / areaRows - elementSpacing;
areaPosition.X = chartAreasRectangle.X + column * (chartAreasRectangle.Width / areaColumns) + elementSpacing;
areaPosition.Y = chartAreasRectangle.Y + row * (chartAreasRectangle.Height / areaRows) + elementSpacing;
// Calculate position of all titles in the collection docked outside of the chart area
TitleCollection.CalcOutsideTitlePosition(this, chartGraph, area, ref areaPosition, elementSpacing);
// Calculate position of the legend if it's docked outside of the chart area
this.Legends.CalcOutsideLegendPosition(chartGraph, area, ref areaPosition, elementSpacing);
// Set area position without changing the Auto flag
area.Position.SetPositionNoAuto(areaPosition.X, areaPosition.Y, areaPosition.Width, areaPosition.Height);
// Go to next area
++row;
if(row >= areaRows)
{
row = 0;
++column;
}
}
else
{
RectangleF rect = area.Position.ToRectangleF();
// Calculate position of all titles in the collection docked outside of the chart area
TitleCollection.CalcOutsideTitlePosition(this, chartGraph, area, ref rect, elementSpacing);
// Calculate position of the legend if it's docked outside of the chart area
this.Legends.CalcOutsideLegendPosition(chartGraph, area, ref rect, elementSpacing);
}
}
}
//******************************************************
//** Align chart areas Position if required
//******************************************************
AlignChartAreasPosition();
//********************************************************
//** Check if only chart area position must be calculated.
//********************************************************
if(!calcAreaPositionOnly)
{
//******************************************************
//** Call Resize function for each chart area.
//******************************************************
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.Resize(chartGraph);
}
}
//******************************************************
//** Align chart areas InnerPlotPosition if required
//******************************************************
AlignChartAreas(AreaAlignmentStyles.PlotPosition);
//******************************************************
//** Calculate position of the legend if it's inside
//** chart plotting area
//******************************************************
// Calculate position of all titles in the collection docked outside of the chart area
TitleCollection.CalcInsideTitlePosition(this, chartGraph, elementSpacing);
this.Legends.CalcInsideLegendPosition(chartGraph, elementSpacing);
}
}
/// <summary>
/// Minimum and maximum do not have to be calculated
/// from data series every time. It is very time
/// consuming. Minimum and maximum are buffered
/// and only when this flags are set Minimum and
/// Maximum are refreshed from data.
/// </summary>
internal void ResetMinMaxFromData()
{
if (_chartAreas != null)
{
// Call ResetMinMaxFromData function for each chart area.
foreach (ChartArea area in _chartAreas)
{
// Check if area is visible
if (area.Visible)
{
area.ResetMinMaxFromData();
}
}
}
}
/// <summary>
/// RecalculateAxesScale the chart picture.
/// </summary>
public void Recalculate()
{
// Call ReCalc function for each chart area.
foreach (ChartArea area in _chartAreas )
{
// Check if area is visible
if(area.Visible)
{
area.ReCalcInternal();
}
}
}
#endregion
#region Chart picture properties
// VSTS 96787-Text Direction (RTL/LTR)
#if !Microsoft_CONTROL
private RightToLeft rightToLeft = RightToLeft.No;
#endif //!Microsoft_CONTROL
/// <summary>
/// Gets or sets the RightToLeft type.
/// </summary>
[
DefaultValue(RightToLeft.No)
]
public RightToLeft RightToLeft
{
get
{
#if Microsoft_CONTROL
return this.Common.Chart.RightToLeft;
#else // !WIN_CONTROL
return this.rightToLeft;
#endif // WIN_CONTROL
}
set
{
#if Microsoft_CONTROL
this.Common.Chart.RightToLeft = value;
#else // !Microsoft_CONTROL
this.rightToLeft = value;
#endif // Microsoft_CONTROL
}
}
/// <summary>
/// Indicates that non-critical chart exceptions will be suppressed.
/// </summary>
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(false),
SRDescription("DescriptionAttributeSuppressExceptions"),
]
internal bool SuppressExceptions
{
set
{
_suppressExceptions = value;
}
get
{
return _suppressExceptions;
}
}
/// <summary>
/// Chart border skin style.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(BorderSkinStyle.None),
SRDescription("DescriptionAttributeBorderSkin"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
]
public BorderSkin BorderSkin
{
get
{
return _borderSkin;
}
set
{
_borderSkin = value;
}
}
#if ! Microsoft_CONTROL
/// <summary>
/// Indicates that chart image map is enabled.
/// </summary>
[
SRCategory("CategoryAttributeMap"),
Bindable(true),
SRDescription("DescriptionAttributeMapEnabled"),
PersistenceMode(PersistenceMode.InnerProperty),
DefaultValue(true)
]
public bool IsMapEnabled
{
get
{
return _isMapEnabled;
}
set
{
_isMapEnabled = value;
}
}
/// <summary>
/// Chart map areas collection.
/// </summary>
[
SRCategory("CategoryAttributeMap"),
SRDescription("DescriptionAttributeMapAreas"),
PersistenceMode(PersistenceMode.InnerProperty),
Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
]
public MapAreasCollection MapAreas
{
get
{
return _mapAreas;
}
}
#endif
/// <summary>
/// Reference to chart area collection
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
SRDescription("DescriptionAttributeChartAreas"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
]
public ChartAreaCollection ChartAreas
{
get
{
return _chartAreas;
}
}
/// <summary>
/// Chart legend collection.
/// </summary>
[
SRCategory("CategoryAttributeChart"),
SRDescription("DescriptionAttributeLegends"),
Editor(Editors.LegendCollectionEditor.Editor, Editors.LegendCollectionEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
]
public LegendCollection Legends
{
get
{
return _legends;
}
}
/// <summary>
/// Chart title collection.
/// </summary>
[
SRCategory("CategoryAttributeCharttitle"),
SRDescription("DescriptionAttributeTitles"),
Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
]
public TitleCollection Titles
{
get
{
return _titles;
}
}
/// <summary>
/// Chart annotation collection.
/// </summary>
[
SRCategory("CategoryAttributeChart"),
SRDescription("DescriptionAttributeAnnotations3"),
Editor(Editors.AnnotationCollectionEditor.Editor, Editors.AnnotationCollectionEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
]
public AnnotationCollection Annotations
{
get
{
return _annotations;
}
}
/// <summary>
/// Background color for the Chart
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), "White"),
SRDescription("DescriptionAttributeBackColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color BackColor
{
get
{
return _backColor;
}
set
{
#if !Microsoft_CONTROL
if(value == Color.Empty || value.A != 255 || value == Color.Transparent)
{
// NOTE: Transparent colors are valid
}
#endif
_backColor = value;
}
}
/// <summary>
/// Border color for the Chart
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), "White"),
SRDescription("DescriptionAttributeBorderColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color BorderColor
{
get
{
return _borderColor;
}
set
{
_borderColor = value;
}
}
/// <summary>
/// Chart width
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(300),
SRDescription("DescriptionAttributeWidth"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public int Width
{
get
{
return _width;
}
set
{
this.InspectChartDimensions(value, this.Height);
_width = value;
Common.Width = _width;
}
}
/// <summary>
/// Series Data Manipulator
/// </summary>
[
SRCategory("CategoryAttributeData"),
SRDescription("DescriptionAttributeDataManipulator"),
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden)
]
public DataManipulator DataManipulator
{
get
{
return _dataManipulator;
}
}
/// <summary>
/// Chart height
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(300),
SRDescription("DescriptionAttributeHeight3"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public int Height
{
get
{
return _height;
}
set
{
this.InspectChartDimensions(this.Width, value);
_height = value;
Common.Height = value;
}
}
/// <summary>
/// Back Hatch style
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(ChartHatchStyle.None),
SRDescription("DescriptionAttributeBackHatchStyle"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
]
public ChartHatchStyle BackHatchStyle
{
get
{
return _backHatchStyle;
}
set
{
_backHatchStyle = value;
}
}
/// <summary>
/// Chart area background image
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(""),
SRDescription("DescriptionAttributeBackImage"),
Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
NotifyParentPropertyAttribute(true)
]
public string BackImage
{
get
{
return _backImage;
}
set
{
_backImage = value;
}
}
/// <summary>
/// Chart area background image drawing mode.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(ChartImageWrapMode.Tile),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeImageWrapMode"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public ChartImageWrapMode BackImageWrapMode
{
get
{
return _backImageWrapMode;
}
set
{
_backImageWrapMode = value;
}
}
/// <summary>
/// Background image transparent color.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeImageTransparentColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color BackImageTransparentColor
{
get
{
return _backImageTransparentColor;
}
set
{
_backImageTransparentColor = value;
}
}
/// <summary>
/// Background image alignment used by ClampUnscale drawing mode.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(ChartImageAlignmentStyle.TopLeft),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackImageAlign"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public ChartImageAlignmentStyle BackImageAlignment
{
get
{
return _backImageAlign;
}
set
{
_backImageAlign = value;
}
}
/// <summary>
/// Indicates that smoothing is applied while drawing shadows.
/// </summary>
[
SRCategory("CategoryAttributeImage"),
Bindable(true),
DefaultValue(true),
SRDescription("DescriptionAttributeSoftShadows3"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public bool IsSoftShadows
{
get
{
return _isSoftShadows;
}
set
{
_isSoftShadows = value;
}
}
/// <summary>
/// Specifies whether smoothing (antialiasing) is applied while drawing chart.
/// </summary>
[
SRCategory("CategoryAttributeImage"),
Bindable(true),
DefaultValue(typeof(AntiAliasingStyles), "All"),
SRDescription("DescriptionAttributeAntiAlias"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public AntiAliasingStyles AntiAliasing
{
get
{
return _antiAliasing;
}
set
{
_antiAliasing = value;
}
}
/// <summary>
/// Specifies the quality of text antialiasing.
/// </summary>
[
SRCategory("CategoryAttributeImage"),
Bindable(true),
DefaultValue(typeof(TextAntiAliasingQuality), "High"),
SRDescription("DescriptionAttributeTextAntiAliasingQuality"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public TextAntiAliasingQuality TextAntiAliasingQuality
{
get
{
return _textAntiAliasingQuality;
}
set
{
_textAntiAliasingQuality = value;
}
}
/// <summary>
/// A type for the background gradient
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(GradientStyle.None),
SRDescription("DescriptionAttributeBackGradientStyle"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
]
public GradientStyle BackGradientStyle
{
get
{
return _backGradientStyle;
}
set
{
_backGradientStyle = value;
}
}
/// <summary>
/// The second color which is used for a gradient
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), ""),
SRDescription("DescriptionAttributeBackSecondaryColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color BackSecondaryColor
{
get
{
return _backSecondaryColor;
}
set
{
#if !Microsoft_CONTROL
if(value != Color.Empty && (value.A != 255 || value == Color.Transparent))
{
throw (new ArgumentException( SR.ExceptionBackSecondaryColorIsTransparent));
}
#endif
_backSecondaryColor = value;
}
}
/// <summary>
/// The width of the border line
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(1),
SRDescription("DescriptionAttributeChart_BorderlineWidth"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public int BorderWidth
{
get
{
return _borderWidth;
}
set
{
if(value < 0)
{
throw(new ArgumentOutOfRangeException("value", SR.ExceptionChartBorderIsNegative));
}
_borderWidth = value;
}
}
/// <summary>
/// The style of the border line
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(ChartDashStyle.NotSet),
SRDescription("DescriptionAttributeBorderDashStyle"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public ChartDashStyle BorderDashStyle
{
get
{
return _borderDashStyle;
}
set
{
_borderDashStyle = value;
}
}
/// <summary>
/// Gets the font cache.
/// </summary>
/// <value>The font cache.</value>
internal FontCache FontCache
{
get { return _fontCache; }
}
#endregion
#region Chart areas alignment methods
/// <summary>
/// Checks if any of the chart areas are aligned.
/// Also checks if the chart ares name in AlignWithChartArea property is valid.
/// </summary>
/// <returns>True if at least one area requires alignment.</returns>
private bool IsAreasAlignmentRequired()
{
bool alignmentRequired = false;
// Loop through all chart areas
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
// Check if area is aligned
if (area.AlignWithChartArea != Constants.NotSetValue)
{
alignmentRequired = true;
// Check the chart area used for alignment
if (this._chartAreas.IndexOf(area.AlignWithChartArea)<0)
{
throw (new InvalidOperationException(SR.ExceptionChartAreaNameReferenceInvalid(area.Name, area.AlignWithChartArea)));
}
}
}
}
return alignmentRequired;
}
/// <summary>
/// Creates a list of the aligned chart areas.
/// </summary>
/// <param name="masterArea">Master chart area.</param>
/// <param name="type">Alignment type.</param>
/// <param name="orientation">Vertical or Horizontal orientation.</param>
/// <returns>List of areas that area aligned to the master area.</returns>
private ArrayList GetAlignedAreasGroup(ChartArea masterArea, AreaAlignmentStyles type, AreaAlignmentOrientations orientation)
{
ArrayList areaList = new ArrayList();
// Loop throught the chart areas and get the ones aligned with specified master area
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
if(area.Name != masterArea.Name &&
area.AlignWithChartArea == masterArea.Name &&
(area.AlignmentStyle & type) == type &&
(area.AlignmentOrientation & orientation) == orientation )
{
// Add "slave" area into the list
areaList.Add(area);
}
}
}
// If list is not empty insert "master" area in the beginning
if(areaList.Count > 0)
{
areaList.Insert(0, masterArea);
}
return areaList;
}
/// <summary>
/// Performs specified type of alignment for the chart areas.
/// </summary>
/// <param name="type">Alignment type required.</param>
internal void AlignChartAreas(AreaAlignmentStyles type)
{
// Check if alignment required
if(IsAreasAlignmentRequired())
{
// Loop through all chart areas
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
// Get vertical areas alignment group using current area as a master
ArrayList alignGroup = GetAlignedAreasGroup(
area,
type,
AreaAlignmentOrientations.Vertical);
// Align each area in the group
if(alignGroup.Count > 0)
{
AlignChartAreasPlotPosition(alignGroup, AreaAlignmentOrientations.Vertical);
}
// Get horizontal areas alignment group using current area as a master
alignGroup = GetAlignedAreasGroup(
area,
type,
AreaAlignmentOrientations.Horizontal);
// Align each area in the group
if(alignGroup.Count > 0)
{
AlignChartAreasPlotPosition(alignGroup, AreaAlignmentOrientations.Horizontal);
}
}
}
}
}
/// <summary>
/// Align inner plot position of the chart areas in the group.
/// </summary>
/// <param name="areasGroup">List of areas in the group.</param>
/// <param name="orientation">Group orientation.</param>
private void AlignChartAreasPlotPosition(ArrayList areasGroup, AreaAlignmentOrientations orientation)
{
//****************************************************************
//** Find the smalles size of the inner plot
//****************************************************************
RectangleF areaPlotPosition = ((ChartArea)areasGroup[0]).PlotAreaPosition.ToRectangleF();
foreach(ChartArea area in areasGroup)
{
if(area.PlotAreaPosition.X > areaPlotPosition.X)
{
areaPlotPosition.X += area.PlotAreaPosition.X - areaPlotPosition.X;
areaPlotPosition.Width -= area.PlotAreaPosition.X - areaPlotPosition.X;
}
if(area.PlotAreaPosition.Y > areaPlotPosition.Y)
{
areaPlotPosition.Y += area.PlotAreaPosition.Y - areaPlotPosition.Y;
areaPlotPosition.Height -= area.PlotAreaPosition.Y - areaPlotPosition.Y;
}
if(area.PlotAreaPosition.Right < areaPlotPosition.Right)
{
areaPlotPosition.Width -= areaPlotPosition.Right - area.PlotAreaPosition.Right;
if(areaPlotPosition.Width < 5)
{
areaPlotPosition.Width = 5;
}
}
if(area.PlotAreaPosition.Bottom < areaPlotPosition.Bottom)
{
areaPlotPosition.Height -= areaPlotPosition.Bottom - area.PlotAreaPosition.Bottom;
if(areaPlotPosition.Height < 5)
{
areaPlotPosition.Height = 5;
}
}
}
//****************************************************************
//** Align inner plot position for all areas
//****************************************************************
foreach(ChartArea area in areasGroup)
{
// Get curretn plot position of the area
RectangleF rect = area.PlotAreaPosition.ToRectangleF();
// Adjust area position
if( (orientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical)
{
rect.X = areaPlotPosition.X;
rect.Width = areaPlotPosition.Width;
}
if( (orientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal)
{
rect.Y = areaPlotPosition.Y;
rect.Height = areaPlotPosition.Height;
}
// Set new plot position in coordinates relative to chart picture
area.PlotAreaPosition.SetPositionNoAuto(rect.X, rect.Y, rect.Width, rect.Height);
// Set new plot position in coordinates relative to chart area position
rect.X = (rect.X - area.Position.X) / area.Position.Width * 100f;
rect.Y = (rect.Y - area.Position.Y) / area.Position.Height * 100f;
rect.Width = rect.Width / area.Position.Width * 100f;
rect.Height = rect.Height / area.Position.Height * 100f;
area.InnerPlotPosition.SetPositionNoAuto(rect.X, rect.Y, rect.Width, rect.Height);
if( (orientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical)
{
area.AxisX2.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
area.AxisX.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
}
if( (orientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal)
{
area.AxisY2.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
area.AxisY.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
}
}
}
/// <summary>
/// Aligns positions of the chart areas.
/// </summary>
private void AlignChartAreasPosition()
{
// Check if alignment required
if(IsAreasAlignmentRequired())
{
// Loop through all chart areas
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
// Check if area is alignd by Position to any other area
if (area.AlignWithChartArea != Constants.NotSetValue && (area.AlignmentStyle & AreaAlignmentStyles.Position) == AreaAlignmentStyles.Position)
{
// Get current area position
RectangleF areaPosition = area.Position.ToRectangleF();
// Get master chart area
ChartArea masterArea = this.ChartAreas[area.AlignWithChartArea];
// Vertical alignment
if((area.AlignmentOrientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical)
{
// Align area position
areaPosition.X = masterArea.Position.X;
areaPosition.Width = masterArea.Position.Width;
}
// Horizontal alignment
if((area.AlignmentOrientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal)
{
// Align area position
areaPosition.Y = masterArea.Position.Y;
areaPosition.Height = masterArea.Position.Height;
}
// Set new position
area.Position.SetPositionNoAuto(areaPosition.X, areaPosition.Y, areaPosition.Width, areaPosition.Height);
}
}
}
}
}
#if Microsoft_CONTROL
/// <summary>
/// Align chart areas cursor.
/// </summary>
/// <param name="changedArea">Changed chart area.</param>
/// <param name="orientation">Orientation of the changed cursor.</param>
/// <param name="selectionChanged">AxisName of change cursor or selection.</param>
internal void AlignChartAreasCursor(ChartArea changedArea, AreaAlignmentOrientations orientation, bool selectionChanged)
{
// Check if alignment required
if(IsAreasAlignmentRequired())
{
// Loop through all chart areas
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
// Get vertical areas alignment group using current area as a master
ArrayList alignGroup = GetAlignedAreasGroup(
area,
AreaAlignmentStyles.Cursor,
orientation);
// Align each area in the group if it contains changed area
if(alignGroup.Contains(changedArea))
{
// Set cursor position for all areas in the group
foreach(ChartArea groupArea in alignGroup)
{
groupArea.alignmentInProcess = true;
if(orientation == AreaAlignmentOrientations.Vertical)
{
if(selectionChanged)
{
groupArea.CursorX.SelectionStart = changedArea.CursorX.SelectionStart;
groupArea.CursorX.SelectionEnd = changedArea.CursorX.SelectionEnd;
}
else
{
groupArea.CursorX.Position = changedArea.CursorX.Position;
}
}
if(orientation == AreaAlignmentOrientations.Horizontal)
{
if(selectionChanged)
{
groupArea.CursorY.SelectionStart = changedArea.CursorY.SelectionStart;
groupArea.CursorY.SelectionEnd = changedArea.CursorY.SelectionEnd;
}
else
{
groupArea.CursorY.Position = changedArea.CursorY.Position;
}
}
groupArea.alignmentInProcess = false;
}
}
}
}
}
}
/// <summary>
/// One of the chart areas was zoomed by the user.
/// </summary>
/// <param name="changedArea">Changed chart area.</param>
/// <param name="orientation">Orientation of the changed scaleView.</param>
/// <param name="disposeBufferBitmap">Area double fuffer image must be disposed.</param>
internal void AlignChartAreasZoomed(ChartArea changedArea, AreaAlignmentOrientations orientation, bool disposeBufferBitmap)
{
// Check if alignment required
if(IsAreasAlignmentRequired())
{
// Loop through all chart areas
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
// Get vertical areas alignment group using current area as a master
ArrayList alignGroup = GetAlignedAreasGroup(
area,
AreaAlignmentStyles.AxesView,
orientation);
// Align each area in the group if it contains changed area
if(alignGroup.Contains(changedArea))
{
// Set cursor position for all areas in the group
foreach(ChartArea groupArea in alignGroup)
{
// Clear image buffer
if(groupArea.areaBufferBitmap != null && disposeBufferBitmap)
{
groupArea.areaBufferBitmap.Dispose();
groupArea.areaBufferBitmap = null;
}
if(orientation == AreaAlignmentOrientations.Vertical)
{
groupArea.CursorX.SelectionStart = double.NaN;
groupArea.CursorX.SelectionEnd = double.NaN;
}
if(orientation == AreaAlignmentOrientations.Horizontal)
{
groupArea.CursorY.SelectionStart = double.NaN;
groupArea.CursorY.SelectionEnd = double.NaN;
}
}
}
}
}
}
}
#endif //Microsoft_CONTROL
/// <summary>
/// Align chart areas axes views.
/// </summary>
/// <param name="changedArea">Changed chart area.</param>
/// <param name="orientation">Orientation of the changed scaleView.</param>
internal void AlignChartAreasAxesView(ChartArea changedArea, AreaAlignmentOrientations orientation)
{
// Check if alignment required
if(IsAreasAlignmentRequired())
{
// Loop through all chart areas
foreach(ChartArea area in this.ChartAreas)
{
// Check if chart area is visible
if(area.Visible)
{
// Get vertical areas alignment group using current area as a master
ArrayList alignGroup = GetAlignedAreasGroup(
area,
AreaAlignmentStyles.AxesView,
orientation);
// Align each area in the group if it contains changed area
if(alignGroup.Contains(changedArea))
{
// Set cursor position for all areas in the group
foreach(ChartArea groupArea in alignGroup)
{
groupArea.alignmentInProcess = true;
if(orientation == AreaAlignmentOrientations.Vertical)
{
groupArea.AxisX.ScaleView.Position = changedArea.AxisX.ScaleView.Position;
groupArea.AxisX.ScaleView.Size = changedArea.AxisX.ScaleView.Size;
groupArea.AxisX.ScaleView.SizeType = changedArea.AxisX.ScaleView.SizeType;
groupArea.AxisX2.ScaleView.Position = changedArea.AxisX2.ScaleView.Position;
groupArea.AxisX2.ScaleView.Size = changedArea.AxisX2.ScaleView.Size;
groupArea.AxisX2.ScaleView.SizeType = changedArea.AxisX2.ScaleView.SizeType;
}
if(orientation == AreaAlignmentOrientations.Horizontal)
{
groupArea.AxisY.ScaleView.Position = changedArea.AxisY.ScaleView.Position;
groupArea.AxisY.ScaleView.Size = changedArea.AxisY.ScaleView.Size;
groupArea.AxisY.ScaleView.SizeType = changedArea.AxisY.ScaleView.SizeType;
groupArea.AxisY2.ScaleView.Position = changedArea.AxisY2.ScaleView.Position;
groupArea.AxisY2.ScaleView.Size = changedArea.AxisY2.ScaleView.Size;
groupArea.AxisY2.ScaleView.SizeType = changedArea.AxisY2.ScaleView.SizeType;
}
groupArea.alignmentInProcess = false;
}
}
}
}
}
}
#endregion
#region Helper methods
/// <summary>
/// Inspects the chart dimensions.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
internal void InspectChartDimensions(int width, int height)
{
if (this.Chart.IsDesignMode() && ((width * height) > (100 * 1024 *1024)))
{
throw new ArgumentException(SR.ExceptionChartOutOfLimits);
}
if (width < 0)
{
throw new ArgumentException(SR.ExceptionValueMustBeGreaterThan("Width", "0px"));
}
if (height < 0)
{
throw new ArgumentException(SR.ExceptionValueMustBeGreaterThan("Height", "0px"));
}
}
/// <summary>
/// Loads chart appearance template from file.
/// </summary>
/// <param name="name">Template file name to load from.</param>
public void LoadTemplate(string name)
{
// Check arguments
if (name == null)
throw new ArgumentNullException("name");
// Load template data into the stream
#if Microsoft_CONTROL
Stream stream = new FileStream(name, FileMode.Open, FileAccess.Read);
#else // Microsoft_CONTROL
Stream stream = LoadTemplateData(name);
#endif // Microsoft_CONTROL
// Load template from stream
LoadTemplate(stream);
// Close tempate stream
stream.Close();
}
/// <summary>
/// Loads chart appearance template from stream.
/// </summary>
/// <param name="stream">Template stream to load from.</param>
public void LoadTemplate(Stream stream)
{
// Check arguments
if (stream == null)
throw new ArgumentNullException("stream");
ChartSerializer serializer = (ChartSerializer)this.Common.container.GetService(typeof(ChartSerializer));
if (serializer != null)
{
// Save previous serializer properties
string oldSerializableContent = serializer.SerializableContent;
string oldNonSerializableContent = serializer.NonSerializableContent;
SerializationFormat oldFormat = serializer.Format;
bool oldIgnoreUnknownXmlAttributes = serializer.IsUnknownAttributeIgnored;
bool oldTemplateMode = serializer.IsTemplateMode;
// Set serializer properties
serializer.Content = SerializationContents.Appearance;
serializer.SerializableContent += ",Chart.Titles,Chart.Annotations," +
"Chart.Legends,Legend.CellColumns,Legend.CustomItems,LegendItem.Cells," +
"Chart.Series,Series.*Style," +
"Chart.ChartAreas,ChartArea.Axis*," +
"Axis.*Grid,Axis.*TickMark, Axis.*Style," +
"Axis.StripLines, Axis.CustomLabels";
serializer.Format = SerializationFormat.Xml;
serializer.IsUnknownAttributeIgnored = true;
serializer.IsTemplateMode = true;
try
{
// Load template
serializer.Load(stream);
}
catch (Exception ex)
{
throw (new InvalidOperationException(ex.Message));
}
finally
{
// Restore previous serializer properties
serializer.SerializableContent = oldSerializableContent;
serializer.NonSerializableContent = oldNonSerializableContent;
serializer.Format = oldFormat;
serializer.IsUnknownAttributeIgnored = oldIgnoreUnknownXmlAttributes;
serializer.IsTemplateMode = oldTemplateMode;
}
}
}
#if !Microsoft_CONTROL
/// <summary>
/// Loads template data from the URL.
/// </summary>
/// <param name="url">Template URL.</param>
/// <returns>Stream with template data or null if error.</returns>
private Stream LoadTemplateData(string url)
{
Debug.Assert(url != null, "LoadTemplateData: handed a null url string");
Stream dataStream = null;
// Try to load as relative URL using the Control object
if(dataStream == null)
{
if (this.Common != null &&
this.Common.Chart != null &&
this.Common.Chart.Page != null)
{
try
{
dataStream = new FileStream(
this.Common.Chart.Page.MapPath(url),
FileMode.Open);
}
catch (NotSupportedException)
{
dataStream = null;
}
catch (SecurityException)
{
dataStream = null;
}
catch (FileNotFoundException)
{
dataStream = null;
}
catch (DirectoryNotFoundException)
{
dataStream = null;
}
catch (PathTooLongException)
{
dataStream = null;
}
}
}
// Try to load image using the Web Request
if(dataStream == null)
{
Uri templateUri = null;
try
{
// Try to create URI directly from template URL (will work in case of absolute URL)
templateUri = new Uri(url);
}
catch (UriFormatException)
{
templateUri = null;
}
// Make absolute URL using web form document URL
if(templateUri == null)
{
if (this.Common != null && this.Common.Chart != null)
{
string webFormUrl = this.Common.Chart.webFormDocumentURL;
int slashIndex = webFormUrl.LastIndexOf('/');
if(slashIndex != -1)
{
webFormUrl = webFormUrl.Substring(0, slashIndex + 1);
}
try
{
templateUri = new Uri(new Uri(webFormUrl), url);
}
catch (UriFormatException)
{
templateUri = null;
}
}
}
// Load image from file or web resource
if(templateUri != null)
{
try
{
WebRequest request = WebRequest.Create(templateUri);
dataStream = request.GetResponse().GetResponseStream();
}
catch (NotSupportedException)
{
dataStream = null;
}
catch (NotImplementedException)
{
dataStream = null;
}
catch (SecurityException)
{
dataStream = null;
}
}
}
// Try to load as file
if(dataStream == null)
{
dataStream = new FileStream(url, FileMode.Open);
}
return dataStream;
}
#endif // Microsoft_CONTROL
#if !Microsoft_CONTROL
/// <summary>
/// Writes chart map tag into the stream.
/// </summary>
/// <param name="output">Html writer to output the data to.</param>
/// <param name="mapName">Chart map name.</param>
internal void WriteChartMapTag(HtmlTextWriter output, string mapName)
{
output.WriteLine();
output.AddAttribute(HtmlTextWriterAttribute.Name, mapName);
output.AddAttribute(HtmlTextWriterAttribute.Id, mapName);
output.RenderBeginTag(HtmlTextWriterTag.Map);
//****************************************************
//** Fire map areas customize event
//****************************************************
// Make sure only non-custom items are passed into the event handler
MapAreasCollection custCollection = new MapAreasCollection();
// Move all non-custom items
for (int index = 0; index < _mapAreas.Count; index++)
{
if (!_mapAreas[index].IsCustom)
{
custCollection.Add(_mapAreas[index]);
_mapAreas.RemoveAt(index);
--index;
}
}
// Call a notification event, so that area items collection can be modified by user
Common.Chart.CallOnCustomizeMapAreas(custCollection);
// Add customized items
foreach(MapArea area in custCollection)
{
area.IsCustom = false;
_mapAreas.Add(area);
}
//****************************************************
//** Add all map areas
//****************************************************
foreach (MapArea area in _mapAreas)
{
area.RenderTag(output, this.Common.Chart);
}
// if this procedure is enforced to run the image maps have to have at least one map area.
if (_mapAreas.Count == 0)
{
output.Write("<area shape=\"rect\" coords=\"0,0,0,0\" alt=\"\" />");
}
//****************************************************
//** End of the map
//****************************************************
output.RenderEndTag();
return;
}
#endif
/// <summary>
/// Returns the default title from Titles collection.
/// </summary>
/// <param name="create">Create title if it doesn't exists.</param>
/// <returns>Default title.</returns>
internal Title GetDefaultTitle(bool create)
{
// Check if default title exists
Title defaultTitle = null;
foreach(Title title in this.Titles)
{
if(title.Name == "Default Title")
{
defaultTitle = title;
}
}
// Create new default title
if(defaultTitle == null && create)
{
defaultTitle = new Title();
defaultTitle.Name = "Default Title";
this.Titles.Insert(0, defaultTitle);
}
return defaultTitle;
}
/// <summary>
/// Checks if tooltips are enabled
/// </summary>
/// <returns>true if tooltips enabled</returns>
private bool IsToolTipsEnabled()
{
// Data series loop
foreach( Series series in Common.DataManager.Series )
{
// Check series tooltips
if( series.ToolTip.Length > 0)
{
// ToolTips enabled
return true;
}
// Check series tooltips
if( series.LegendToolTip.Length > 0 ||
series.LabelToolTip.Length > 0)
{
// ToolTips enabled
return true;
}
// Check point tooltips only for "non-Fast" chart types
if( !series.IsFastChartType() )
{
// Data point loop
foreach( DataPoint point in series.Points )
{
// ToolTip empty
if( point.ToolTip.Length > 0)
{
// ToolTips enabled
return true;
}
// ToolTip empty
if( point.LegendToolTip.Length > 0 ||
point.LabelToolTip.Length > 0)
{
// ToolTips enabled
return true;
}
}
}
}
// Legend items loop
foreach( Legend legend in Legends )
{
foreach( LegendItem legendItem in legend.CustomItems )
{
// ToolTip empty
if( legendItem.ToolTip.Length > 0 )
{
return true;
}
}
}
// Title items loop
foreach( Title title in Titles )
{
// ToolTip empty
if( title.ToolTip.Length > 0 )
{
return true;
}
}
return false;
}
#endregion
#region IDisposable Members
/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed resources
if (ChartGraph != null)
{
ChartGraph.Dispose();
ChartGraph = null;
}
if (_legends != null)
{
_legends.Dispose();
_legends = null;
}
if (_titles != null)
{
_titles.Dispose();
_titles = null;
}
if (_chartAreas != null)
{
_chartAreas.Dispose();
_chartAreas = null;
}
if (_annotations != null)
{
_annotations.Dispose();
_annotations = null;
}
if (hotRegionsList != null)
{
hotRegionsList.Dispose();
hotRegionsList = null;
}
if (_fontCache != null)
{
_fontCache.Dispose();
_fontCache = null;
}
if (_borderSkin != null)
{
_borderSkin.Dispose();
_borderSkin = null;
}
#if ! Microsoft_CONTROL
if (_mapAreas != null)
{
_mapAreas.Dispose();
_mapAreas = null;
}
#endif
#if Microsoft_CONTROL
if (nonTopLevelChartBuffer != null)
{
nonTopLevelChartBuffer.Dispose();
nonTopLevelChartBuffer = null;
}
#endif
}
base.Dispose(disposing);
}
#endregion
}
/// <summary>
/// Event arguments of Chart paint event.
/// </summary>
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class ChartPaintEventArgs : EventArgs
{
#region Fields
// Private fields
private object _chartElement = null;
private ChartGraphics _chartGraph = null;
private CommonElements _common = null;
private Chart _chart = null;
private ElementPosition _position = null;
#endregion
#region Properties
/// <summary>
/// Gets the chart element of the event.
/// </summary>
/// <value>The chart element.</value>
public object ChartElement
{
get
{
return _chartElement;
}
}
/// <summary>
/// Gets the ChartGraphics object of the event.
/// </summary>
public ChartGraphics ChartGraphics
{
get
{
return _chartGraph;
}
}
/// <summary>
/// Chart Common elements.
/// </summary>
internal CommonElements CommonElements
{
get
{
return _common;
}
}
/// <summary>
/// Chart element position in relative coordinates of the event.
/// </summary>
public ElementPosition Position
{
get
{
return _position;
}
}
/// <summary>
/// Chart object of the event.
/// </summary>
public Chart Chart
{
get
{
if (_chart == null && _common != null)
{
_chart = _common.Chart;
}
return _chart;
}
}
#endregion
#region Methods
/// <summary>
/// Default constructor is not accessible
/// </summary>
private ChartPaintEventArgs()
{
}
/// <summary>
/// Paint event arguments constructor.
/// </summary>
/// <param name="chartElement">Chart element.</param>
/// <param name="chartGraph">Chart graphics.</param>
/// <param name="common">Common elements.</param>
/// <param name="position">Position.</param>
internal ChartPaintEventArgs(object chartElement, ChartGraphics chartGraph, CommonElements common, ElementPosition position)
{
this._chartElement = chartElement;
this._chartGraph = chartGraph;
this._common = common;
this._position = position;
}
#endregion
}
/// <summary>
/// Event arguments of localized numbers formatting event.
/// </summary>
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class FormatNumberEventArgs : EventArgs
{
#region Fields
// Private fields
private double _value;
private string _format;
private string _localizedValue;
private ChartValueType _valueType = ChartValueType.Auto;
private object _senderTag;
private ChartElementType _elementType = ChartElementType.Nothing;
#endregion
#region Properties
/// <summary>
/// Value to be formatted.
/// </summary>
public double Value
{
get { return this._value; }
}
/// <summary>
/// Localized text.
/// </summary>
public string LocalizedValue
{
get { return _localizedValue; }
set { _localizedValue = value; }
}
/// <summary>
/// Format string.
/// </summary>
public string Format
{
get { return _format; }
}
/// <summary>
/// Value type.
/// </summary>
public ChartValueType ValueType
{
get { return _valueType; }
}
/// <summary>
/// The sender object of the event.
/// </summary>
public object SenderTag
{
get { return _senderTag; }
}
/// <summary>
/// Chart element type.
/// </summary>
public ChartElementType ElementType
{
get { return _elementType; }
}
#endregion
#region Methods
/// <summary>
/// Default constructor is not accessible
/// </summary>
private FormatNumberEventArgs()
{
}
/// <summary>
/// Object constructor.
/// </summary>
/// <param name="value">Value to be formatted.</param>
/// <param name="format">Format string.</param>
/// <param name="valueType">Value type..</param>
/// <param name="localizedValue">Localized value.</param>
/// <param name="senderTag">Chart element object tag.</param>
/// <param name="elementType">Chart element type.</param>
internal FormatNumberEventArgs(double value, string format, ChartValueType valueType, string localizedValue, object senderTag, ChartElementType elementType)
{
this._value = value;
this._format = format;
this._valueType = valueType;
this._localizedValue = localizedValue;
this._senderTag = senderTag;
this._elementType = elementType;
}
#endregion
}
#region FontCache
/// <summary>
/// Font cache class helps ChartElements to reuse the Font instances
/// </summary>
internal class FontCache : IDisposable
{
#region Static
// Default font family name
private static string _defaultFamilyName;
/// <summary>
/// Gets the default font family name.
/// </summary>
/// <value>The default font family name.</value>
public static string DefaultFamilyName
{
get
{
if (_defaultFamilyName == null)
{
// Find the "Microsoft Sans Serif" font
foreach (FontFamily fontFamily in FontFamily.Families)
{
if (fontFamily.Name == "Microsoft Sans Serif")
{
_defaultFamilyName = fontFamily.Name;
break;
}
}
// Not found - use the default Sans Serif font
if (_defaultFamilyName == null)
{
_defaultFamilyName = FontFamily.GenericSansSerif.Name;
}
}
return _defaultFamilyName;
}
}
#endregion
#region Fields
// Cached fonts dictionary
private Dictionary<KeyInfo, Font> _fontCache = new Dictionary<KeyInfo, Font>(new KeyInfo.EqualityComparer());
#endregion // Fields
#region Properties
/// <summary>
/// Gets the default font.
/// </summary>
/// <value>The default font.</value>
public Font DefaultFont
{
get { return this.GetFont(DefaultFamilyName, 8); }
}
/// <summary>
/// Gets the default font.
/// </summary>
/// <value>The default font.</value>
public Font DefaultBoldFont
{
get { return this.GetFont(DefaultFamilyName, 8, FontStyle.Bold); }
}
#endregion
#region Methods
/// <summary>
/// Gets the font.
/// </summary>
/// <param name="familyName">Name of the family.</param>
/// <param name="size">The size.</param>
/// <returns>Font instance</returns>
public Font GetFont(string familyName, int size)
{
KeyInfo key = new KeyInfo(familyName, size);
if (!this._fontCache.ContainsKey(key))
{
this._fontCache.Add(key, new Font(familyName, size));
}
return this._fontCache[key];
}
/// <summary>
/// Gets the font.
/// </summary>
/// <param name="familyName">Name of the family.</param>
/// <param name="size">The size.</param>
/// <param name="style">The style.</param>
/// <returns>Font instance</returns>
public Font GetFont(string familyName, float size, FontStyle style)
{
KeyInfo key = new KeyInfo(familyName, size, style);
if (!this._fontCache.ContainsKey(key))
{
this._fontCache.Add(key, new Font(familyName, size, style));
}
return this._fontCache[key];
}
/// <summary>
/// Gets the font.
/// </summary>
/// <param name="family">The family.</param>
/// <param name="size">The size.</param>
/// <param name="style">The style.</param>
/// <returns>Font instance</returns>
public Font GetFont(FontFamily family, float size, FontStyle style)
{
KeyInfo key = new KeyInfo(family, size, style);
if (!this._fontCache.ContainsKey(key))
{
this._fontCache.Add(key, new Font(family, size, style));
}
return this._fontCache[key];
}
/// <summary>
/// Gets the font.
/// </summary>
/// <param name="family">The family.</param>
/// <param name="size">The size.</param>
/// <param name="style">The style.</param>
/// <param name="unit">The unit.</param>
/// <returns>Font instance</returns>
public Font GetFont(FontFamily family, float size, FontStyle style, GraphicsUnit unit)
{
KeyInfo key = new KeyInfo(family, size, style, unit);
if (!this._fontCache.ContainsKey(key))
{
this._fontCache.Add(key, new Font(family, size, style, unit));
}
return this._fontCache[key];
}
#endregion
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
foreach (Font font in _fontCache.Values)
{
font.Dispose();
}
_fontCache.Clear();
GC.SuppressFinalize(this);
}
#endregion
#region FontKeyInfo struct
/// <summary>
/// Font key info
/// </summary>
private class KeyInfo
{
string _familyName;
float _size = 8;
GraphicsUnit _unit = GraphicsUnit.Point;
FontStyle _style = FontStyle.Regular;
int _gdiCharSet = 1;
/// <summary>
/// Initializes a new instance of the <see cref="KeyInfo"/> class.
/// </summary>
/// <param name="familyName">Name of the family.</param>
/// <param name="size">The size.</param>
public KeyInfo(string familyName, float size)
{
this._familyName = familyName;
this._size = size;
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyInfo"/> class.
/// </summary>
/// <param name="familyName">Name of the family.</param>
/// <param name="size">The size.</param>
/// <param name="style">The style.</param>
public KeyInfo(string familyName, float size, FontStyle style)
{
this._familyName = familyName;
this._size = size;
this._style = style;
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyInfo"/> class.
/// </summary>
/// <param name="family">The family.</param>
/// <param name="size">The size.</param>
/// <param name="style">The style.</param>
public KeyInfo(FontFamily family, float size, FontStyle style)
{
this._familyName = family.ToString();
this._size = size;
this._style = style;
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyInfo"/> class.
/// </summary>
/// <param name="family">The family.</param>
/// <param name="size">The size.</param>
/// <param name="style">The style.</param>
/// <param name="unit">The unit.</param>
public KeyInfo(FontFamily family, float size, FontStyle style, GraphicsUnit unit)
{
this._familyName = family.ToString();
this._size = size;
this._style = style;
this._unit = unit;
}
#region IEquatable<FontKeyInfo> Members
/// <summary>
/// KeyInfo equality comparer
/// </summary>
internal class EqualityComparer : IEqualityComparer<KeyInfo>
{
/// <summary>
/// Determines whether the specified objects are equal.
/// </summary>
/// <param name="x">The first object of type <paramref name="x"/> to compare.</param>
/// <param name="y">The second object of type <paramref name="y"/> to compare.</param>
/// <returns>
/// true if the specified objects are equal; otherwise, false.
/// </returns>
public bool Equals(KeyInfo x, KeyInfo y)
{
return
x._size == y._size &&
x._familyName == y._familyName &&
x._unit == y._unit &&
x._style == y._style &&
x._gdiCharSet == y._gdiCharSet;
}
/// <summary>
/// Returns a hash code for the specified object.
/// </summary>
/// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
/// <returns>A hash code for the specified object.</returns>
/// <exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception>
public int GetHashCode(KeyInfo obj)
{
return obj._familyName.GetHashCode() ^ obj._size.GetHashCode();
}
}
#endregion
}
#endregion
}
#endregion
}