Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/referencesource/System.Web.DataVisualization/Common/General/Chart.cs')
-rw-r--r--mcs/class/referencesource/System.Web.DataVisualization/Common/General/Chart.cs4361
1 files changed, 4361 insertions, 0 deletions
diff --git a/mcs/class/referencesource/System.Web.DataVisualization/Common/General/Chart.cs b/mcs/class/referencesource/System.Web.DataVisualization/Common/General/Chart.cs
new file mode 100644
index 00000000000..a83a2fb7137
--- /dev/null
+++ b/mcs/class/referencesource/System.Web.DataVisualization/Common/General/Chart.cs
@@ -0,0 +1,4361 @@
+//-------------------------------------------------------------
+// <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
+
+
+}