File: WinForm\ChartWinControl.cs
Project: ndp\fx\src\DataVisualization\System.Windows.Forms.DataVisualization.csproj (System.Windows.Forms.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		ChartWinControl.cs
//
//  Namespace:	System.Windows.Forms.DataVisualization.Charting
//
//	Classes:	Chart
//
//  Purpose:	Main windows forms chart control class.
//
//	Reviewed:	AG - August 7, 2002
//
//===================================================================
 
 
#region Used namespaces
 
using System.Resources;
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Data;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.IO;
using System.Xml;
using System.Reflection;
using System.ComponentModel.Design.Serialization;
using System.Runtime.InteropServices;
using System.Globalization;
 
 
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;
using System.Windows.Forms.DataVisualization.Charting.Formulas;
using System.Net;
using System.Diagnostics.CodeAnalysis;
#endregion
 
namespace System.Windows.Forms.DataVisualization.Charting
{
	#region Enumerations
 
	/// <summary>
	/// Specifies the format of the image
	/// </summary>
	public enum ChartImageFormat
	{
		/// <summary>
		/// Gets the Joint Photographic Experts Group (JPEG) image format.
		/// </summary>
		Jpeg,
 
		/// <summary>
		/// Gets the W3C Portable Network Graphics (PNG) image format.
		/// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Png")]
        Png,
 
		/// <summary>
		/// Gets the bitmap image format (BMP).
		/// </summary>
		Bmp,
 
		/// <summary>
		/// Gets the Tag Image File Format (TIFF) image format.
		/// </summary>
		Tiff,
 
		/// <summary>
		/// Gets the Graphics Interchange Format (GIF) image format.
		/// </summary>
		Gif,
 
		/// <summary>
		/// Gets the Enhanced Meta File (Emf) image format.
		/// </summary>
		Emf,
 
		/// <summary>
		/// Enhanced Meta File (EmfDual) image format.
		/// </summary>
		EmfDual,
		
		/// <summary>
		/// Enhanced Meta File (Emf+) image format.
		/// </summary>
		EmfPlus,
	}
 
	#endregion
 
	/// <summary>
	/// Chart windows forms control
	/// </summary>
    [ToolboxBitmap(typeof(Chart), "ChartControl.ico")]
	[SRDescription("DescriptionAttributeChart_Chart")]
    [Designer(Editors.ChartWinDesigner)]
	[DesignerSerializer(Editors.ChartWinDesignerSerializer.Designer, Editors.ChartWinDesignerSerializer.Base)]
	[DisplayNameAttribute("Chart")]
    public class Chart : System.Windows.Forms.Control, ISupportInitialize, IDisposable
	{
        #region Control fields
 
        /// <summary>
        /// Determines whether or not to show debug markings in debug mode. For internal use.
        /// </summary>
        internal bool ShowDebugMarkings = false;
 
		// Chart services components
		private ChartTypeRegistry				_chartTypeRegistry = null;
		private BorderTypeRegistry				_borderTypeRegistry = null;
		private CustomPropertyRegistry			_customAttributeRegistry = null;
		private DataManager						_dataManager = null;
		internal ChartImage						chartPicture = null;
		private ImageLoader						_imageLoader = null;
		internal ServiceContainer				serviceContainer = null;
		private ChartSerializer					_chartSerializer = null;
		private	PrintingManager					_printingManager = null;
 
		// Selection class
		internal Selection						selection = null;
 
		// Named images collection
		private NamedImagesCollection			_namedImages = null;
 
		
		// Formula registry servise component
		private FormulaRegistry					_formulaRegistry = null;
 
 
		// Indicates that control invalidation is temporary disabled
		internal bool							disableInvalidates = false;
 
		// Indicates that chart is serializing the data
		internal bool							serializing = false;
 
        // Detailed serialization status which allows not only to determine if serialization
        // is curently in process but also check if we are saving, loading or resetting the chart.
        internal SerializationStatus            serializationStatus = SerializationStatus.None;
 
		// Bitmap used for double buffering chart painting
		internal Bitmap							paintBufferBitmap = null;
 
		// Graphics of the double buffered bitmap
		internal Graphics						paintBufferBitmapGraphics = null;
 
		// Indicates that only chart area cursor/selection must be drawn during the next paint event
		internal bool							paintTopLevelElementOnly = false;
 
		// Indicates that some chart properties where changed (used for painting)
		internal bool							dirtyFlag = true;
 
 
		// Chart default cursor
		internal System.Windows.Forms.Cursor	defaultCursor = Cursors.Default;
 
		// Keywords registry
		private KeywordsRegistry				_keywordsRegistry = null;
 
		// Horizontal rendering resolution.
		static internal double					renderingDpiX = 96.0;
 
		// Vertical rendering resolution.
		static internal double					renderingDpiY = 96.0;
 
 
		#endregion 
 
		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
		}
		#endregion
 
		#region Control constructors
 
		/// <summary>
		/// Chart control constructor.
		/// </summary>
		public Chart()
		{
 
			//*******************************************************
			//** Check control license
			//*******************************************************
 
			//*********************************************************
			//** Set control styles
			//*********************************************************
			this.SetStyle(ControlStyles.ResizeRedraw, true);
			//this.SetStyle(ControlStyles.Opaque, true);
			this.SetStyle(ControlStyles.UserPaint, true);
			this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
			this.SetStyle(ControlStyles.Selectable, true);
 
			// NOTE: Fixes issue #4475
			this.SetStyle(ControlStyles.DoubleBuffer, true);
 
			if (AccessibilityImprovements.Level3)
			{
				// This is necessary to raise focus event on chart mouse click.
				this.SetStyle(ControlStyles.UserMouse, true);
			}
 
			//*********************************************************
			//** Create services
			//*********************************************************
            serviceContainer = new ServiceContainer();
			_chartTypeRegistry = new ChartTypeRegistry();
			_borderTypeRegistry = new BorderTypeRegistry();
			_customAttributeRegistry = new CustomPropertyRegistry();
 
			_keywordsRegistry = new KeywordsRegistry();
 
			_dataManager = new DataManager(serviceContainer);
			_imageLoader = new ImageLoader(serviceContainer);
 
			chartPicture = new ChartImage(serviceContainer);
			_chartSerializer = new ChartSerializer(serviceContainer);
			_printingManager = new PrintingManager(serviceContainer);
			_formulaRegistry = new FormulaRegistry();
 
			// Add services to the service container
			serviceContainer.AddService(typeof(Chart), this);							// Chart Control
			serviceContainer.AddService(_chartTypeRegistry.GetType(), _chartTypeRegistry);// Chart types registry
			serviceContainer.AddService(_borderTypeRegistry.GetType(), _borderTypeRegistry);// Border types registry
			serviceContainer.AddService(_customAttributeRegistry.GetType(), _customAttributeRegistry);// Custom attribute registry
			serviceContainer.AddService(_dataManager.GetType(), _dataManager);			// Data Manager service
			serviceContainer.AddService(_imageLoader.GetType(), _imageLoader);			// Image Loader service
			serviceContainer.AddService(chartPicture.GetType(), chartPicture);			// Chart image service
			serviceContainer.AddService(_chartSerializer.GetType(), _chartSerializer);	// Chart serializer service
			serviceContainer.AddService(_printingManager.GetType(), _printingManager);	// Printing manager service
			serviceContainer.AddService(_formulaRegistry.GetType(), _formulaRegistry);	// Formula modules service
			serviceContainer.AddService(_keywordsRegistry.GetType(), _keywordsRegistry);	// Keywords registry
 
			// Initialize objects
			_dataManager.Initialize();
 
 
			// Register known chart types
			_chartTypeRegistry.Register( ChartTypeNames.Bar, typeof(BarChart));
			_chartTypeRegistry.Register( ChartTypeNames.Column, typeof(ColumnChart));
			_chartTypeRegistry.Register( ChartTypeNames.Point, typeof(PointChart));
			_chartTypeRegistry.Register( ChartTypeNames.Bubble, typeof(BubbleChart));
			_chartTypeRegistry.Register( ChartTypeNames.Line, typeof(LineChart));
			_chartTypeRegistry.Register( ChartTypeNames.Spline, typeof(SplineChart));
			_chartTypeRegistry.Register( ChartTypeNames.StepLine, typeof(StepLineChart));
			_chartTypeRegistry.Register( ChartTypeNames.Area, typeof(AreaChart));
			_chartTypeRegistry.Register( ChartTypeNames.SplineArea, typeof(SplineAreaChart));
			_chartTypeRegistry.Register( ChartTypeNames.StackedArea, typeof(StackedAreaChart));
			_chartTypeRegistry.Register( ChartTypeNames.Pie, typeof(PieChart));
            _chartTypeRegistry.Register( ChartTypeNames.Stock, typeof(StockChart));
            _chartTypeRegistry.Register( ChartTypeNames.Candlestick, typeof(CandleStickChart));
			_chartTypeRegistry.Register( ChartTypeNames.Doughnut, typeof(DoughnutChart));
			_chartTypeRegistry.Register( ChartTypeNames.StackedBar, typeof(StackedBarChart));
			_chartTypeRegistry.Register( ChartTypeNames.StackedColumn, typeof(StackedColumnChart));
            _chartTypeRegistry.Register( ChartTypeNames.OneHundredPercentStackedColumn, typeof(HundredPercentStackedColumnChart));
            _chartTypeRegistry.Register( ChartTypeNames.OneHundredPercentStackedBar, typeof(HundredPercentStackedBarChart));
            _chartTypeRegistry.Register( ChartTypeNames.OneHundredPercentStackedArea, typeof(HundredPercentStackedAreaChart));
 
 
 
			_chartTypeRegistry.Register(ChartTypeNames.Range, typeof(RangeChart));
            _chartTypeRegistry.Register(ChartTypeNames.SplineRange, typeof(SplineRangeChart));
            _chartTypeRegistry.Register(ChartTypeNames.RangeBar, typeof(RangeBarChart));
            _chartTypeRegistry.Register(ChartTypeNames.Radar, typeof(RadarChart));
            _chartTypeRegistry.Register(ChartTypeNames.RangeColumn, typeof(RangeColumnChart));
            _chartTypeRegistry.Register(ChartTypeNames.ErrorBar, typeof(ErrorBarChart));
            _chartTypeRegistry.Register(ChartTypeNames.BoxPlot, typeof(BoxPlotChart));
 
 
 
            _chartTypeRegistry.Register(ChartTypeNames.Renko, typeof(RenkoChart));
			_chartTypeRegistry.Register(ChartTypeNames.ThreeLineBreak, typeof(ThreeLineBreakChart));
            _chartTypeRegistry.Register(ChartTypeNames.Kagi, typeof(KagiChart));
            _chartTypeRegistry.Register(ChartTypeNames.PointAndFigure, typeof(PointAndFigureChart));
 
 
 
 
 
            _chartTypeRegistry.Register(ChartTypeNames.Polar, typeof(PolarChart));
            _chartTypeRegistry.Register(ChartTypeNames.FastLine, typeof(FastLineChart));
            _chartTypeRegistry.Register(ChartTypeNames.Funnel, typeof(FunnelChart));
            _chartTypeRegistry.Register(ChartTypeNames.Pyramid, typeof(PyramidChart));
 
 
 
 
 
			_chartTypeRegistry.Register(ChartTypeNames.FastPoint, typeof(FastPointChart));
 
 
 
			// Register known formula modules
            _formulaRegistry.Register(SR.FormulaNamePriceIndicators, typeof(PriceIndicators));
			_formulaRegistry.Register(SR.FormulaNameGeneralTechnicalIndicators,typeof(GeneralTechnicalIndicators));
            _formulaRegistry.Register(SR.FormulaNameTechnicalVolumeIndicators, typeof(VolumeIndicators));
            _formulaRegistry.Register(SR.FormulaNameOscillator, typeof(Oscillators));
            _formulaRegistry.Register(SR.FormulaNameGeneralFormulas, typeof(GeneralFormulas));
            _formulaRegistry.Register(SR.FormulaNameTimeSeriesAndForecasting, typeof(TimeSeriesAndForecasting));
            _formulaRegistry.Register(SR.FormulaNameStatisticalAnalysis, typeof(StatisticalAnalysis));
 
 
 
			// Register known 3D border types
			_borderTypeRegistry.Register("Emboss", typeof(EmbossBorder));
			_borderTypeRegistry.Register("Raised", typeof(RaisedBorder));
			_borderTypeRegistry.Register("Sunken", typeof(SunkenBorder));
			_borderTypeRegistry.Register("FrameThin1", typeof(FrameThin1Border));
			_borderTypeRegistry.Register("FrameThin2", typeof(FrameThin2Border));
			_borderTypeRegistry.Register("FrameThin3", typeof(FrameThin3Border));
			_borderTypeRegistry.Register("FrameThin4", typeof(FrameThin4Border));
			_borderTypeRegistry.Register("FrameThin5", typeof(FrameThin5Border));
			_borderTypeRegistry.Register("FrameThin6", typeof(FrameThin6Border));
			_borderTypeRegistry.Register("FrameTitle1", typeof(FrameTitle1Border));
			_borderTypeRegistry.Register("FrameTitle2", typeof(FrameTitle2Border));
			_borderTypeRegistry.Register("FrameTitle3", typeof(FrameTitle3Border));
			_borderTypeRegistry.Register("FrameTitle4", typeof(FrameTitle4Border));
			_borderTypeRegistry.Register("FrameTitle5", typeof(FrameTitle5Border));
			_borderTypeRegistry.Register("FrameTitle6", typeof(FrameTitle6Border));
			_borderTypeRegistry.Register("FrameTitle7", typeof(FrameTitle7Border));
			_borderTypeRegistry.Register("FrameTitle8", typeof(FrameTitle8Border));
 
			// Enable chart invalidating
			this.disableInvalidates = false;
			
			// Create selection object
            selection = new Selection(serviceContainer);
 
			// Create named images collection
            _namedImages = new NamedImagesCollection();
 
            // Hook up event handlers
            ChartAreas.NameReferenceChanged += new EventHandler<NameReferenceChangedEventArgs>(Series.ChartAreaNameReferenceChanged);
            ChartAreas.NameReferenceChanged += new EventHandler<NameReferenceChangedEventArgs>(Legends.ChartAreaNameReferenceChanged);
            ChartAreas.NameReferenceChanged += new EventHandler<NameReferenceChangedEventArgs>(Titles.ChartAreaNameReferenceChanged);
            ChartAreas.NameReferenceChanged += new EventHandler<NameReferenceChangedEventArgs>(Annotations.ChartAreaNameReferenceChanged);
            ChartAreas.NameReferenceChanged += new EventHandler<NameReferenceChangedEventArgs>(ChartAreas.ChartAreaNameReferenceChanged);
            Legends.NameReferenceChanged += new EventHandler<NameReferenceChangedEventArgs>(Series.LegendNameReferenceChanged);
        }
 
 
 
		#endregion
 
        #region Control painting methods
 
        /// <summary>
		/// Paint chart control.
		/// </summary>
		/// <param name="e">Paint event arguments.</param>
		protected override void OnPaint(PaintEventArgs e)
		{
 
			//*******************************************************
			//** Check control license
 
			// Disable invalidates
			this.disableInvalidates = true;
 
			//*******************************************************
			//** If chart background is transparent - draw without
			//** double buffering.
			//*******************************************************
			if(this.IsBorderTransparent() ||
				!this.BackColor.IsEmpty && 
				(this.BackColor == Color.Transparent || this.BackColor.A != 255) )
			{
 
				// Draw chart directly on the graphics
				try
				{
					if(this.paintTopLevelElementOnly)
					{
						chartPicture.Paint(e.Graphics, false);
					}
					chartPicture.Paint(e.Graphics, this.paintTopLevelElementOnly);
				}
				catch(Exception)
				{
					// Draw exception method
					DrawException(e.Graphics);
 
 
					// Rethrow exception if not in design-time mode
					if(!this.DesignMode)
					{
						throw;
					}
 
				}
                
			}
			else
			{
 
				//*******************************************************
				//** If nothing was changed in the chart and last image is stored in the buffer
				//** there is no need to repaint the chart.
				//*******************************************************
				if(this.dirtyFlag || paintBufferBitmap == null)
				{
 
                    // Get scaling component from the drawing graphics
                    float scaleX = e.Graphics.Transform.Elements[0];
                    float scaleY = e.Graphics.Transform.Elements[3];
 
					// Create offscreen buffer bitmap
					if(paintBufferBitmap == null ||
                        paintBufferBitmap.Width < scaleX * ClientRectangle.Width ||
                        paintBufferBitmap.Height < scaleY * ClientRectangle.Height)
					{
						if(paintBufferBitmap != null)
						{
							paintBufferBitmap.Dispose();
							paintBufferBitmapGraphics.Dispose();
						}
 
                        // Create offscreen bitmap taking in consideration graphics scaling
                        paintBufferBitmap = new Bitmap((int)(ClientRectangle.Width * scaleX), (int)(ClientRectangle.Height * scaleY), e.Graphics);
						paintBufferBitmapGraphics = Graphics.FromImage(paintBufferBitmap);
                        paintBufferBitmapGraphics.ScaleTransform(scaleX, scaleY);
					}
 
					//*******************************************************
					//** Draw chart in bitmap buffer
					//*******************************************************
					try
					{
						chartPicture.Paint(paintBufferBitmapGraphics, this.paintTopLevelElementOnly);
					}
					catch(Exception)
					{
						// Draw exception method
						DrawException(paintBufferBitmapGraphics);
 
						// Rethrow exception if not in design-time mode
						if(!this.DesignMode)
						{
							throw;
						}
					}
				}
 
				//*******************************************************
				//** Push bitmap buffer forward into the screen
				//*******************************************************
                // Set drawing scale 1:1. Only persist the transformation from current matrix
                System.Drawing.Drawing2D.Matrix drawingMatrix = new System.Drawing.Drawing2D.Matrix();
                System.Drawing.Drawing2D.Matrix oldMatrix = e.Graphics.Transform;
                drawingMatrix.Translate(oldMatrix.OffsetX, oldMatrix.OffsetY);
                e.Graphics.Transform = drawingMatrix;
 
                // Draw image
                e.Graphics.DrawImage(paintBufferBitmap, 0, 0);
                e.Graphics.Transform = oldMatrix;
			}
 
			// Clears control dirty flag
			this.dirtyFlag = false;
			this.disableInvalidates = false;
 
            // Call base class
            base.OnPaint(e);
 
			//*******************************************************
			//** Check if smart client data must be loaded
			//*******************************************************
		}
 
		/// <summary>
		/// Paints control background.
		/// </summary>
		/// <param name="pevent">Event arguments.</param>
		protected override void OnPaintBackground(PaintEventArgs pevent)
		{
			this.disableInvalidates = true;
 
			//*********************************************************
			//** Check if chart back ground has a transparent color
			//*********************************************************
			bool	transpBack = false;
			if(chartPicture.BackColor.A != 255 && chartPicture.BackColor != Color.Empty)
			{
				transpBack = true;
			}
			else if(chartPicture.BackImageTransparentColor.A != 255 && 
				chartPicture.BackImageTransparentColor != Color.Empty &&
				!String.IsNullOrEmpty(chartPicture.BackImage))
			{
				transpBack = true;
			}
 
			//*********************************************************
			//** If chart or chart border page colr has transparent color
			//*********************************************************
			bool transpBorder = this.IsBorderTransparent();
			if( transpBorder || transpBack)
			{
				Color oldBackColor = chartPicture.BackColor;
				if(transpBorder)
 
				{
					chartPicture.BackColor = Color.Transparent;
				}
 
				// Call base class 
				base.OnPaintBackground(pevent);
 
				chartPicture.BackColor = oldBackColor;
			}
 
			this.disableInvalidates = false;
		}
 
        /// <summary>
        /// When user changes system color, the Chart redraws itself.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected override void OnSystemColorsChanged(EventArgs e)
        {
            base.OnSystemColorsChanged(e);
 
            this.Invalidate();
        }
 
		/// <summary>
		/// Checks if border skins is enabled in the chart and it uses transparency in the page color
		/// </summary>
		/// <returns>True if transparency is used in the border.</returns>
		private bool IsBorderTransparent()
		{
			bool	transpBorder = false;
			if(chartPicture.BorderSkin.SkinStyle != BorderSkinStyle.None)
			{
				if(	chartPicture.BorderSkin.PageColor.A != 255 && 
					chartPicture.BorderSkin.PageColor != Color.Empty)
				{
					transpBorder = true;
				}
				if(chartPicture.BorderSkin.BackColor.A != 255 && chartPicture.BorderSkin.BackColor != Color.Empty)
				{
					transpBorder = true;
				}
				else if(chartPicture.BorderSkin.BackImageTransparentColor.A != 255 && 
					chartPicture.BorderSkin.BackImageTransparentColor != Color.Empty &&
					!String.IsNullOrEmpty(chartPicture.BorderSkin.BackImage))
				{
					transpBorder = true;
				}
			}
 
			return transpBorder;
		}
 
		/// <summary>
		/// Draws exception information at design-time.
		/// </summary>
		/// <param name="graphics">Chart graphics to use.</param>
		private void DrawException(Graphics graphics)
		{
			// Fill background
			graphics.FillRectangle(Brushes.White, 0, 0, this.Width, this.Height);
            
            string addMessage = SR.ExceptionChartPreviewNotAvailable;
            // Get text rectangle
			RectangleF		rect = new RectangleF(3, 3, this.Width-6, this.Height-6);
            
            // Draw exception text
            using (StringFormat format = new StringFormat())
            {
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;
                using (Font font = new Font(FontCache.DefaultFamilyName, 8))
                {
                    graphics.DrawString(addMessage, font, Brushes.Black, rect, format);
                }
            }
		}
 
		/// <summary>
		/// Forces the control to invalidate its client area and immediately redraw itself and any child controls.
		/// </summary>
		[
		EditorBrowsable(EditorBrowsableState.Never)
		]
		public override void Refresh()
		{
			// Clear bitmap used to improve the performance of elements
			// like cursors and annotations
			// NOTE: Fixes issue #4157
			if(this.chartPicture.nonTopLevelChartBuffer != null)
			{
				this.chartPicture.nonTopLevelChartBuffer.Dispose();
				this.chartPicture.nonTopLevelChartBuffer = null;
			}
 
			this.dirtyFlag = true;
            this.ResetAccessibilityObject();
			base.Refresh();
		}
 
		/// <summary>
		/// Invalidates a specific region of the control and causes a paint message to be sent to the control.
		/// </summary>
		public new void Invalidate()
		{
			this.dirtyFlag = true;
            this.ResetAccessibilityObject();
			if(!this.disableInvalidates)
			{
				base.Invalidate(true);
 
			}
 
			// NOTE: Code below required for the Diagram integration. -AG
			if(!this.chartPicture.isSavingAsImage)
			{
				InvalidateEventArgs e = new InvalidateEventArgs(Rectangle.Empty);
				this.OnInvalidated(e);
			}
 
		}
 
		/// <summary>
		/// Invalidates a specific region of the control and causes a paint message to be sent to the control.
		/// </summary>
        public new void Invalidate(Rectangle rectangle)
		{
			this.dirtyFlag = true;
            this.ResetAccessibilityObject();
			if(!this.disableInvalidates)
			{
				base.Invalidate(rectangle);
	
			}
 
			// NOTE: Code below required for the Diagram integration. -AG
			if(!this.chartPicture.isSavingAsImage)
			{
				InvalidateEventArgs e = new InvalidateEventArgs(Rectangle.Empty);
				this.OnInvalidated(e);
			}                 
		}
 
 
 
 
		/// <summary>
		/// Updates chart cursor and range selection only.
		/// </summary>
		public void UpdateCursor()
		{
			// Set flag to redraw cursor/selection only
			this.paintTopLevelElementOnly = true;
 
			// Update chart cursor and range selection
			base.Update();
 
			// Clear flag to redraw cursor/selection only
			this.paintTopLevelElementOnly = false;
		}
 
 
 
		/// <summary>
		/// Updates chart annotations only.
		/// </summary>
		public void UpdateAnnotations()
		{
			// Set flag to redraw cursor/selection only
			this.paintTopLevelElementOnly = true;
 
			// Update chart cursor and range selection
			base.Update();
 
			// Clear flag to redraw cursor/selection only
			this.paintTopLevelElementOnly = false;
		}
		
 
 
		#endregion
 
		#region Control size and location properties/methods
 
		/// <summary>
		/// Returns default control size.
		/// </summary>
		protected override Size DefaultSize 
		{
			get
			{
				return new Size(300, 300);
			}
		}
 
		/// <summary>
		/// Control location changed.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected override void OnLocationChanged(EventArgs e)
		{
			// If chart or chart border page color has transparent color
			if((chartPicture.BackColor.A != 255 && chartPicture.BackColor != Color.Empty) || 
				(chartPicture.BorderSkin.SkinStyle != BorderSkinStyle.None && 
				chartPicture.BorderSkin.PageColor.A != 255 && 
				chartPicture.BorderSkin.PageColor != Color.Empty))
			{
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
			}
			base.OnLocationChanged(e);
		}
 
		/// <summary>
		/// Control resized.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected override void OnResize(EventArgs e)
		{
			chartPicture.Width = this.Size.Width;
			chartPicture.Height = this.Size.Height;
			this.dirtyFlag = true;
            this.ResetAccessibilityObject();
			base.OnResize(e);
		}
        /// <summary>
        /// Fires RightToLeftChanged event.
        /// </summary>
        /// <param name="e">Event Arguments</param>
        protected override void OnRightToLeftChanged(EventArgs e)
        {
            base.OnRightToLeftChanged(e);
            this.Invalidate();
        }
		
        #endregion
 
		#region Chart image saving methods
 
		/// <summary>
		/// Saves chart image into the file.
		/// </summary>
		/// <param name="imageFileName">Image file name</param>
		/// <param name="format">Image format.</param>
		public void SaveImage(string imageFileName, ChartImageFormat format)
		{
            // Check arguments
            if (imageFileName == null)
                throw new ArgumentNullException("imageFileName");
 
			// Create file stream for the specified file name
			FileStream	fileStream = new FileStream(imageFileName, FileMode.Create);
 
			// Save into stream
			try 
			{
				SaveImage(fileStream, format);
			}
			finally
			{
				// Close file stream
				fileStream.Close();
			}
		}
 
		/// <summary>
		/// Saves chart image into the file.
		/// </summary>
		/// <param name="imageFileName">Image file name</param>
		/// <param name="format">Image format.</param>
		public void SaveImage(string imageFileName, ImageFormat format)
		{
            // Check arguments
            if (imageFileName == null)
                throw new ArgumentNullException("imageFileName");
            if (format == null)
                throw new ArgumentNullException("format");
 
			// Create file stream for the specified file name
			FileStream	fileStream = new FileStream(imageFileName, FileMode.Create);
 
			// Save into stream
			try 
			{
				SaveImage(fileStream, format);
			}
			finally
			{
				// Close file stream
				fileStream.Close();
			}
		}
 
		/// <summary>
		/// Saves chart image into the stream.
		/// </summary>
		/// <param name="imageStream">Image stream.</param>
		/// <param name="format">Image format.</param>
		public void SaveImage(Stream imageStream, ImageFormat format)
		{
            // Check arguments
            if (imageStream == null)
                throw new ArgumentNullException("imageStream");
            if (format == null)
                throw new ArgumentNullException("format");
 
			// Indicate that chart is saved into the image
			this.chartPicture.isSavingAsImage = true;
 
			if(format == ImageFormat.Emf || format == ImageFormat.Wmf)
			{
				this.chartPicture.SaveIntoMetafile(imageStream, EmfType.EmfOnly);
			}
			else
			{
				// Get chart image
				Image chartImage = this.chartPicture.GetImage();
 
				// Save image into the file
				chartImage.Save(imageStream, format);
 
				// Dispose image
				chartImage.Dispose();
			}
 
			// Reset flag
			this.chartPicture.isSavingAsImage = false;
		}
 
		/// <summary>
		/// Saves chart image into the stream.
		/// </summary>
		/// <param name="imageStream">Image stream.</param>
		/// <param name="format">Image format.</param>
		public void SaveImage( Stream imageStream, ChartImageFormat format )
		{
            // Check arguments
            if (imageStream == null)
                throw new ArgumentNullException("imageStream");
 
			// Indicate that chart is saved into the image
			this.chartPicture.isSavingAsImage = true;
 
			if( format == ChartImageFormat.Emf ||
				format == ChartImageFormat.EmfPlus ||
				format == ChartImageFormat.EmfDual)
			{
				EmfType emfType = EmfType.EmfOnly;
				if(format == ChartImageFormat.EmfDual)
				{
					emfType = EmfType.EmfPlusDual;
				}
				else if(format == ChartImageFormat.EmfPlus)
				{
					emfType = EmfType.EmfPlusOnly;
				}
 
				this.chartPicture.SaveIntoMetafile(imageStream, emfType);
			} 
			else 
			{
				// Get chart image
				Image chartImage = this.chartPicture.GetImage();
 
				ImageFormat standardImageFormat = ImageFormat.Png;
 
				switch( format )
				{
					case ChartImageFormat.Bmp:
						standardImageFormat = ImageFormat.Bmp;
						break;
					case ChartImageFormat.Gif:
						standardImageFormat = ImageFormat.Gif;
						break;
					case ChartImageFormat.Jpeg:
						standardImageFormat = ImageFormat.Jpeg;
						break;
					case ChartImageFormat.Png:
						standardImageFormat = ImageFormat.Png;
						break;
					case ChartImageFormat.Tiff:
						standardImageFormat = ImageFormat.Tiff;
						break;
				}
 
				// Save image into the file
				chartImage.Save(imageStream, standardImageFormat);
 
				// Dispose image
				chartImage.Dispose();
			}
 
			// Reset flag
			this.chartPicture.isSavingAsImage = false;
		}
 
 
#endregion
 
		#region Control public properties
 
		/// <summary>
		/// Array of custom palette colors.
		/// </summary>
		/// <remarks>
		/// When this custom colors array is non-empty the <b>Palette</b> property is ignored.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		SerializationVisibilityAttribute(SerializationVisibility.Attribute),
		SRDescription("DescriptionAttributeChart_PaletteCustomColors"),
		TypeConverter(typeof(ColorArrayConverter))
		]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
		public Color[] PaletteCustomColors
		{
			set
			{
				this._dataManager.PaletteCustomColors = value;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
			}
			get
			{
				return this._dataManager.PaletteCustomColors;
			}
		}
 
		/// <summary>
		/// Method resets custom colors array. Internal use only.
		/// </summary>
		[EditorBrowsable(EditorBrowsableState.Never)]
		internal void ResetPaletteCustomColors()
		{
			this.PaletteCustomColors = new Color[0];
		}
 
		/// <summary>
		/// Method resets custom colors array. Internal use only.
		/// </summary>
		[EditorBrowsable(EditorBrowsableState.Never)]
        internal bool ShouldSerializePaletteCustomColors()
		{
			if(this.PaletteCustomColors == null ||
				this.PaletteCustomColors.Length == 0)
			{
				return false;
			}
			return true;
		}
		
		/// <summary>
		/// Indicates that non-critical chart exceptions will be suppressed.
		/// </summary>
		[
        SRCategory("CategoryAttributeMisc"),
		DefaultValue(false),
		SRDescription("DescriptionAttributeSuppressExceptions"),
		]
		public bool SuppressExceptions
		{
			set
			{
				this.chartPicture.SuppressExceptions = value;
			}
			get
			{
				return this.chartPicture.SuppressExceptions;
			}
		}
 
 
		/// <summary>
		/// "The data source used to populate series data. Series ValueMember properties must be also set."
		/// </summary>
		[
        SRCategory("CategoryAttributeData"),
		Bindable(true),
		SRDescription("DescriptionAttributeDataSource"),
		DefaultValue(null),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
        AttributeProvider(typeof(IListSource))
		]
		public object DataSource
		{
			get
			{
				return chartPicture.DataSource;
			}
			set
			{
				chartPicture.DataSource = value;
			}
		}
 
		/// <summary>
		/// Chart named images collection.
		/// </summary>
		[
		SRCategory("CategoryAttributeChart"),
		Bindable(false),
		SRDescription("DescriptionAttributeChart_Images"),
		Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		]
		public NamedImagesCollection Images
		{
			get
			{
				return _namedImages;
			}
		}
 
 
		/// <summary>
		/// Chart printing object.
		/// </summary>
		[
		SRCategory("CategoryAttributeChart"),
		Bindable(false),
		SRDescription("DescriptionAttributeChart_Printing"),
		Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public PrintingManager Printing
		{
			get
			{
				return _printingManager;
			}
		}
 
 
		/// <summary>
		/// Chart series collection.
		/// </summary>
		[
        SRCategory("CategoryAttributeChart"),
		SRDescription("DescriptionAttributeChart_Series"),
        Editor(Editors.SeriesCollectionEditor.Editor, Editors.SeriesCollectionEditor.Base),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
		]
		public SeriesCollection Series
		{
			get
			{
				return _dataManager.Series;
			}
		}
 
		/// <summary>
		/// Chart legend collection.
		/// </summary>
		[
		SRCategory("CategoryAttributeChart"),
		SRDescription("DescriptionAttributeLegends"),
        Editor(Editors.LegendCollectionEditor.Editor, Editors.LegendCollectionEditor.Base),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
		]
		public LegendCollection Legends
		{
			get
			{
				return chartPicture.Legends;
			}
		}
 
		/// <summary>
		/// Chart title collection.
		/// </summary>
		[
		SRCategory("CategoryAttributeChart"),
		SRDescription("DescriptionAttributeTitles"),
        Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
		]
		public TitleCollection Titles
		{
			get
			{
				return chartPicture.Titles;
			}
		}
 
		/// <summary>
		/// Chart annotation collection.
		/// </summary>
		[
		SRCategory("CategoryAttributeChart"),
		SRDescription("DescriptionAttributeAnnotations3"),
        Editor(Editors.AnnotationCollectionEditor.Editor, Editors.AnnotationCollectionEditor.Base),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		]
		public AnnotationCollection Annotations
		{
			get
			{
				return chartPicture.Annotations;
			}
		}
 
		/// <summary>
		/// BackImage is not used. Use BackImage property instead.
		/// </summary>
		[
		Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public override Image BackgroundImage
		{
			get
			{
                return base.BackgroundImage;
			}
			set
			{
                base.BackgroundImage = value;
			}
		}
 
		/// <summary>
		/// Color palette to use
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		SRDescription("DescriptionAttributePalette"),
        DefaultValue(ChartColorPalette.BrightPastel),
        Editor(Editors.ColorPaletteEditor.Editor, Editors.ColorPaletteEditor.Base)
		]
		public ChartColorPalette Palette
		{
			get
			{
				return _dataManager.Palette;
			}
			set
			{
				_dataManager.Palette = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
		
		/// <summary>
		/// Specifies whether smoothing (antialiasing) is applied while drawing chart.
		/// </summary>
		[
		SRCategory("CategoryAttributeImage"),
		Bindable(true),
		DefaultValue(typeof(AntiAliasingStyles), "All"),
		SRDescription("DescriptionAttributeAntiAlias"),
        Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base)
		]
		public System.Windows.Forms.DataVisualization.Charting.AntiAliasingStyles AntiAliasing
		{
			get
			{
				return chartPicture.AntiAliasing;
			}
			set
			{
				if(chartPicture.AntiAliasing != value)
				{
					chartPicture.AntiAliasing = value;
 
					this.dirtyFlag = true;
					if(!this.disableInvalidates)
					{
						this.Invalidate();
					}
				}
			}
		}
 
		/// <summary>
		/// Specifies the quality of text antialiasing.
		/// </summary>
		[
		SRCategory("CategoryAttributeImage"),
		Bindable(true),
		DefaultValue(typeof(TextAntiAliasingQuality), "High"),
		SRDescription("DescriptionAttributeTextAntiAliasingQuality"),
#if !WINFORMS_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
#endif
		]
		public TextAntiAliasingQuality TextAntiAliasingQuality
		{
			get
			{
				return chartPicture.TextAntiAliasingQuality;
			}
			set
			{
				chartPicture.TextAntiAliasingQuality = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
			}
		}
 
		/// <summary>
		/// Specifies whether smoothing is applied while drawing shadows.
		/// </summary>
		[
		SRCategory("CategoryAttributeImage"),
		Bindable(true),
		DefaultValue(true),
		SRDescription("DescriptionAttributeChart_SoftShadows"),
		]
		public bool IsSoftShadows
		{
			get
			{
				return chartPicture.IsSoftShadows;
			}
			set
			{
				chartPicture.IsSoftShadows = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// Reference to chart area collection
		/// </summary>
		[
		SRCategory("CategoryAttributeChart"),
		Bindable(true),
		SRDescription("DescriptionAttributeChartAreas"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
        Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
		]
		public ChartAreaCollection ChartAreas
		{
			get
			{
				return chartPicture.ChartAreas;
			}
		}
 
		/// <summary>
		/// Back ground 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),
		]
		public override Color BackColor
		{
			get
			{
				return chartPicture.BackColor;
			}
			set
			{
                if (chartPicture.BackColor != value)
                {
                    chartPicture.BackColor = value;
                    this.dirtyFlag = true;
                    if (!this.disableInvalidates)
                    {
                        this.Invalidate();
                    }
 
                    // Call notification event
                    this.OnBackColorChanged(EventArgs.Empty);
                }
			}
		}
 
		/// <summary>
		/// Fore color propery (not used)
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(false),
		Browsable(false),
		DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeForeColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public override Color ForeColor
		{
			get
			{
				return Color.Empty;
			}
			set
			{
			}
		}
 
        ///// <summary>
        ///// Color that will not be used in the chart drawing.
        ///// </summary>
        //[
        //SRCategory("CategoryAttributeAppearance"),
        //DefaultValue(typeof(Color), ""),
        //SRDescription("DescriptionAttributeChart_UnusedColor"),
        //Browsable(false),
        //TypeConverter(typeof(ColorConverter)),
        //Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
        //]
        //public Color UnusedColor
        //{
        //    get
        //    {
        //        return unusedColor;
        //    }
        //    set
        //    {
        //        unusedColor = value;
        //    }
        //}
 
        /// <summary>
        /// Fore color propery (not used)
        /// </summary>
        [
        SRCategory("CategoryAttributeLayout"),
        Bindable(true),
        DefaultValue(typeof(Size), "300, 300"),
        SRDescription("DescriptionAttributeChart_Size"),
        ]
        public new Size Size
        {
            get
            {
                return base.Size;
            }
            set
            {
                chartPicture.InspectChartDimensions(value.Width, value.Height);
                base.Size = value;
            }
        }
		
		/// <summary>
		/// Series data manipulator
		/// </summary>
		[
		SRCategory("CategoryAttributeData"),
		SRDescription("DescriptionAttributeDataManipulator"),
		Browsable(false),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public DataManipulator DataManipulator
		{
			get
			{
				return chartPicture.DataManipulator;
			}
		}
 
		/// <summary>
		/// Chart serializer object.
		/// </summary>
		[
		SRCategory("CategoryAttributeSerializer"),
		SRDescription("DescriptionAttributeChart_Serializer"),
		Browsable(false),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public ChartSerializer Serializer
		{
			get
			{
				return _chartSerializer;
			}
		}
 
 
		/// <summary>
		/// Title font
		/// </summary>
		[
		SRCategory("CategoryAttributeCharttitle"),
		Bindable(false),
		Browsable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public new Font Font
		{
			get
			{
				return base.Font;
			}
			set
			{
				base.Font = value;
			}
		}
 
 
		/// <summary>
		/// Back Hatch style
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartHatchStyle.None),
        SRDescription("DescriptionAttributeBackHatchStyle"),
        Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
		]
		public ChartHatchStyle BackHatchStyle
		{
			get
			{
				return chartPicture.BackHatchStyle;
			}
			set
			{
				chartPicture.BackHatchStyle = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
 
 
		/// <summary>
		/// Chart area background image
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(""),
        SRDescription("DescriptionAttributeBackImage"),
		NotifyParentPropertyAttribute(true),
        Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
		]
		public string BackImage
		{
			get
			{
				return chartPicture.BackImage;
			}
			set
			{
				chartPicture.BackImage = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// Chart area background image drawing mode.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartImageWrapMode.Tile),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeImageWrapMode"),
		]
		public ChartImageWrapMode BackImageWrapMode
		{
			get
			{
				return chartPicture.BackImageWrapMode;
			}
			set
			{
				chartPicture.BackImageWrapMode = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <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),
		]
		public Color BackImageTransparentColor
		{
			get
			{
				return chartPicture.BackImageTransparentColor;
			}
			set
			{
				chartPicture.BackImageTransparentColor = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// Background image alignment used by ClampUnscale drawing mode.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartImageAlignmentStyle.TopLeft),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeBackImageAlign"),
		]
		public ChartImageAlignmentStyle BackImageAlignment
		{
			get
			{
				return chartPicture.BackImageAlignment;
			}
			set
			{
				chartPicture.BackImageAlignment = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// A type for the background gradient
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(GradientStyle.None),
        SRDescription("DescriptionAttributeBackGradientStyle"),
        Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
		]
		public GradientStyle BackGradientStyle
		{
			get
			{
				return chartPicture.BackGradientStyle;
			}
			set
			{
				chartPicture.BackGradientStyle = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <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),
		]
		public Color BackSecondaryColor
		{
			get
			{
				return chartPicture.BackSecondaryColor;
			}
			set
			{
				chartPicture.BackSecondaryColor = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// Border color for the Chart
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(false),
		Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
		DefaultValue(typeof(Color), "White"),
		SRDescription("DescriptionAttributeBorderColor"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color BorderColor
		{
			get
			{
				return chartPicture.BorderColor;
			}
			set
			{
				chartPicture.BorderColor = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// The width of the border line
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(false),
		Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
		DefaultValue(1),
		SRDescription("DescriptionAttributeChart_BorderlineWidth"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public int BorderWidth
		{
			get
			{
				return chartPicture.BorderWidth;
			}
			set
			{
				chartPicture.BorderWidth = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// The style of the border line
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(false),
		Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
		DefaultValue(ChartDashStyle.NotSet),
        SRDescription("DescriptionAttributeBorderDashStyle"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public ChartDashStyle BorderDashStyle
		{
			get
			{
				return chartPicture.BorderDashStyle;
			}
			set
			{
				chartPicture.BorderDashStyle = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <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),
		]
		public Color BorderlineColor
		{
			get
			{
				return chartPicture.BorderColor;
			}
			set
			{
				chartPicture.BorderColor = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// The width of the border line
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(1),
		SRDescription("DescriptionAttributeChart_BorderlineWidth"),
		]
		public int BorderlineWidth
		{
			get
			{
				return chartPicture.BorderWidth;
			}
			set
			{
				chartPicture.BorderWidth = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// The style of the border line
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartDashStyle.NotSet),
        SRDescription("DescriptionAttributeBorderDashStyle"),
		]
		public ChartDashStyle BorderlineDashStyle
		{
			get
			{
				return chartPicture.BorderDashStyle;
			}
			set
			{
				chartPicture.BorderDashStyle = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
 
		/// <summary>
		/// Chart border skin style.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(BorderSkinStyle.None),
		SRDescription("DescriptionAttributeBorderSkin"),
		NotifyParentPropertyAttribute(true),
		TypeConverterAttribute(typeof(LegendConverter)),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content)
		]
		public BorderSkin BorderSkin
		{
			get
			{
				return chartPicture.BorderSkin;
			}
			set
			{
				chartPicture.BorderSkin = value;
				this.dirtyFlag = true;
				if(!this.disableInvalidates)
				{
					this.Invalidate();
				}
 
			}
		}
 
		/// <summary>
		/// Build number of the control
		/// </summary>
		[
		SRDescription("DescriptionAttributeChart_BuildNumber"),
		Browsable(false),
		EditorBrowsable(EditorBrowsableState.Never),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
		DefaultValue("")
		]
		public string BuildNumber
		{
			get
			{
				// Get build number from the assembly
				string	buildNumber = String.Empty;
				Assembly assembly = Assembly.GetExecutingAssembly();
				if(assembly != null)
				{
					buildNumber = assembly.FullName.ToUpper(CultureInfo.InvariantCulture);
					int	versionIndex = buildNumber.IndexOf("VERSION=", StringComparison.Ordinal);
					if(versionIndex >= 0)
					{
						buildNumber = buildNumber.Substring(versionIndex + 8);
					}
                    versionIndex = buildNumber.IndexOf(",", StringComparison.Ordinal);
					if(versionIndex >= 0)
					{
						buildNumber = buildNumber.Substring(0, versionIndex);
					}
				}
				return buildNumber;
			}
		}
 
		/// <summary>
		/// Vertical resolution of the chart renderer.
		/// </summary>
		/// <remarks>
		/// This property is for the internal use only.
		/// </remarks>
		[
		Browsable(false),
		EditorBrowsable(EditorBrowsableState.Never),
		SRCategory("CategoryAttributeMisc"),
		DefaultValue(96.0),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public double RenderingDpiY
		{
			set
			{
				Chart.renderingDpiY = value;
			}
			get
			{
				return Chart.renderingDpiY;
			}
		}
 
		/// <summary>
		/// Horizontal resolution of the chart renderer.
		/// </summary>
		/// <remarks>
		/// This property is for the internal use only.
		/// </remarks>
		[
		Browsable(false),
		EditorBrowsable(EditorBrowsableState.Never),
		SRCategory("CategoryAttributeMisc"),
		DefaultValue(96.0),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden)
		]
		public double RenderingDpiX
		{
			set
			{
				Chart.renderingDpiX = value;
			}
			get
			{
				return Chart.renderingDpiX;
			}
		}
 
 
		#endregion
 
		#region Control public methods
 
		/// <summary>
		/// Loads chart appearance template from file.
		/// </summary>
		/// <param name="name">Template file name to load from.</param>
		public void LoadTemplate(string name)
		{
			chartPicture.LoadTemplate(name);
		}
 
		/// <summary>
		/// Loads chart appearance template from stream.
		/// </summary>
		/// <param name="stream">Template stream to load from.</param>
		public void LoadTemplate(Stream stream)
		{
			chartPicture.LoadTemplate(stream);
		}
 
		/// <summary>
		/// Applies palette colors to series or data points.
		/// </summary>
		public void ApplyPaletteColors()
		{
			// Apply palette colors to series
			this._dataManager.ApplyPaletteColors();
 
			// Apply palette colors to data Points in series
			foreach(Series series in this.Series)
			{
				// Check if palette colors should be aplied to the points
				bool	applyToPoints = false;
				if(series.Palette != ChartColorPalette.None)
				{
					applyToPoints = true;
				}
				else
				{
					IChartType chartType = this._chartTypeRegistry.GetChartType(series.ChartType);
					applyToPoints = chartType.ApplyPaletteColorsToPoints;
				}
 
				// Apply palette colors to the points
				if(applyToPoints)
				{
					series.ApplyPaletteColors();
				}
			}
		}
 
		/// <summary>
		/// Checks if control is in design mode.
		/// </summary>
		/// <returns>True if control is in design mode.</returns>
		internal bool IsDesignMode()
		{
			return this.DesignMode;
		}
 
		/// <summary>
		/// Reset auto calculated chart properties values to "Auto".
		/// </summary>
		public void ResetAutoValues()
		{
			// Reset auto calculated series properties values 
			foreach(Series series in this.Series)
			{
				series.ResetAutoValues();
			}
 
			// Reset auto calculated axis properties values 
			foreach(ChartArea chartArea in this.ChartAreas)
			{
				chartArea.ResetAutoValues();
			}
 
		}
 
        /// <summary>
        /// This method performs the hit test and returns a HitTestResult objects.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
		public HitTestResult HitTest( int x, int y )
		{
			return selection.HitTest( x, y );
		}
 
        /// <summary>
        /// This method performs the hit test and returns a HitTestResult object.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="ignoreTransparent">Indicates that transparent elements should be ignored.</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
		public HitTestResult HitTest( int x, int y, bool ignoreTransparent )
		{
			return selection.HitTest( x, y, ignoreTransparent );
		}
 
        /// <summary>
        /// This method performs the hit test and returns a HitTestResult object.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="requestedElement">Only this chart element will be hit tested.</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
		public HitTestResult HitTest( int x, int y, ChartElementType requestedElement )
		{
			return selection.HitTest( x, y, requestedElement);
		}
 
        /// <summary>
        /// Call this method to determine the  chart element,
        /// if any, that is located at a point defined by the given X and Y 
        /// coordinates.
        /// <seealso cref="HitTestResult"/></summary>
        /// <param name="x">The X coordinate for the point in question.
        /// Often obtained from a parameter in an event
        /// (e.g. the X parameter value in the MouseDown event).</param>
        /// <param name="y">The Y coordinate for the point in question.
        /// Often obtained from a parameter in an event
        /// (e.g. the Y parameter value in the MouseDown event).</param>
        /// <param name="ignoreTransparent">Indicates that transparent 
        /// elements should be ignored.</param>
        /// <param name="requestedElement">
        /// An array of type which specify the types                  
        /// to test for, on order to filter the result. If omitted checking for                 
        /// elementTypes will be ignored and all kind of elementTypes will be 
        /// valid.
        ///  </param>
        /// <returns>
        /// A array of <see cref="HitTestResult"/> objects,
        /// which provides information concerning the  chart element
        /// (if any) that is at the specified location. Result contains at least
        /// one element, which could be ChartElementType.Nothing. 
        /// The objects in the result are sorted in from top to bottom of 
        /// different layers of control. </returns>
        /// <remarks>Call this method to determine the  gauge element
        /// (if any) that is located at a specified point. Often this method is used in
        /// some mouse-related event (e.g. MouseDown)
        /// to determine what  gauge element the end-user clicked on.
        /// The X and Y mouse coordinates obtained from the
        /// event parameters are then used for the X and Y parameter              
        /// values of this method call.   The returned 
        /// <see cref="HitTestResult"/> object's properties
        /// can then be used to determine what  chart element was clicked on,
        /// and also provides a reference to the actual object selected (if 
        /// any).</remarks>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")] 
        public HitTestResult[] HitTest(int x, int y, bool ignoreTransparent, params ChartElementType[] requestedElement)
        {
            return this.selection.HitTest(x, y, ignoreTransparent, requestedElement);
        }
 
 
        /// <summary>
        /// Gets the chart element outline.
        /// </summary>
        /// <param name="element">The chart object.</param>
        /// <param name="elementType">Type of the element.</param>
        /// <returns> A <see cref="ChartElementOutline"/> object which contains
        /// 1) An array of points in absolute coordinates which can be used as outline markers arround this chart element.
        /// 2) A GraphicsPath for drawing aouline around this chart emenent.
        /// </returns>
        /// <remarks>
        /// If the <paramref name="element"/> is not part of the chart or <paramref name="elementType"/> cannot be combined 
        /// with <paramref name="element"/> then the result will contain empty array of marker points. 
        /// The marker points are sorted clockwize.
        /// </remarks>
        public ChartElementOutline GetChartElementOutline(object element, ChartElementType elementType)
        {
            return this.selection.GetChartElementOutline(element, elementType);
        }
 
        #endregion
 
        #region Control protected methods
 
        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
 
            if (!AccessibilityImprovements.Level3)
            {
                return;
            }
 
            using (Graphics g = Graphics.FromHwndInternal(Handle))
            {
                ControlPaint.DrawFocusRectangle(g, new Rectangle(1, 1, Size.Width - 2, Size.Height - 2));
            }
        }
 
        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
 
            if (!AccessibilityImprovements.Level3)
            {
                return;
            }
 
            using (Graphics g = Graphics.FromHwndInternal(Handle))
            {
                using (Brush b = new SolidBrush(BackColor))
                {
                    Rectangle topBorder = new Rectangle(1, 1, Size.Width - 2, 1);
                    g.FillRectangle(b, topBorder);
 
                    Rectangle rightBorder = new Rectangle(Size.Width - 2, 1, 1, Size.Height - 2);
                    g.FillRectangle(b, rightBorder);
 
                    Rectangle bottomBorder = new Rectangle(1, Size.Height - 2, Size.Width - 2, 1);
                    g.FillRectangle(b, bottomBorder);
 
                    Rectangle leftBorder = new Rectangle(1, 1, 1, Size.Height - 2);
                    g.FillRectangle(b, leftBorder);
                }
            }
        }
 
        #endregion
 
        #region ISupportInitialize implementation
 
        /// <summary>
        /// Signals the object that initialization is starting.
        /// </summary>
        public void BeginInit()
		{
			// Disable control invalidation
			disableInvalidates = true;
		}
		
		/// <summary>
		/// Signals the object that initialization is complete.
		/// </summary>
		public void EndInit()
		{
			// Enable control invalidation
			disableInvalidates = false;
 
			// If control is durty - invalidate it
			if(this.dirtyFlag)
			{
				base.Invalidate();
			}
 
		}
 
		#endregion
 
		#region Control mouse events
 
        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.CursorChanged"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
        protected override void OnCursorChanged(EventArgs e)
        {
            this.defaultCursor = this.Cursor;
            base.OnCursorChanged(e);
        }
 
 
		/// <summary>
		/// Mouse button pressed in the control.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected override void OnMouseDown(MouseEventArgs e)
		{
			OnChartMouseDown(e);
		}
 
		/// <summary>
		/// Mouse button pressed in the control.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		internal void OnChartMouseDown(MouseEventArgs e)
		{
			bool	handled = false;
 
		if(!handled)
		{
			// Notify annotation object collection about the mouse down event
			this.Annotations.OnMouseDown(e, ref handled);
		}
 
		// Loop through all areas and notify required object about the event
		if(!handled)
		{
			foreach(ChartArea area in this.ChartAreas)
			{
				// No cursor or scroll bar support in 3D
				if(!area.Area3DStyle.Enable3D && 
					!area.chartAreaIsCurcular
					&& area.Visible)
				{
					foreach(Axis axis in area.Axes)
					{
						// Notify axis scroll bar
						axis.ScrollBar.ScrollBar_MouseDown(this, e);
					}
 
					// Notify area X and Y cursors
					area.CursorX.Cursor_MouseDown(this, e);
					area.CursorY.Cursor_MouseDown(this, e);
				}
			}
		}
 
		// Call the base class
		base.OnMouseDown(e);
	}
 
		/// <summary>
		/// Mouse button up in the control.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected override void OnMouseUp(MouseEventArgs e)
		{
			OnChartMouseUp(e);
		}
 
		/// <summary>
		/// Mouse button up in the control.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		internal void OnChartMouseUp(MouseEventArgs e)
		{
			// Loop through all areas and notify required object about the event
			foreach(ChartArea area in this.ChartAreas)
			{
				// No cursor or scroll bar support in 3D
				if(!area.Area3DStyle.Enable3D && 
					!area.chartAreaIsCurcular
					&& area.Visible)
				{
					foreach(Axis axis in area.Axes)
					{
						// Notify axis scroll bar
						axis.ScrollBar.ScrollBar_MouseUp(this, e);
					}
 
					// Notify area X and Y cursors
					area.CursorX.Cursor_MouseUp(this, e);
					area.CursorY.Cursor_MouseUp(this, e);
				}
			}
 
			// Notify annotation object collection about the mouse down event
			this.Annotations.OnMouseUp(e);
 
			// Call the base class
			base.OnMouseUp(e);
		}
 
		/// <summary>
		/// Mouse moved in the control.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected override void OnMouseMove(MouseEventArgs e)
		{
			OnChartMouseMove(e);
		}
 
		/// <summary>
		/// Mouse moved in the control.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		internal void OnChartMouseMove(MouseEventArgs e)
		{
			// Flag which indicates if event was already isHandled
			bool handled = false;
 
			// Loop through all areas and notify required object about the event
			foreach(ChartArea area in this.ChartAreas)
			{
				// No cursor or scroll bar support in 3D
				if(!area.Area3DStyle.Enable3D && 
					!area.chartAreaIsCurcular
					&& area.Visible)
				{
					foreach(Axis axis in area.Axes)
					{
						// Notify axis scroll bar
						axis.ScrollBar.ScrollBar_MouseMove(e, ref handled);
					}
 
					// Notify area X and Y cursors
					area.CursorX.Cursor_MouseMove(e, ref handled);
					area.CursorY.Cursor_MouseMove(e, ref handled);
				}
			}
 
			// Notify Selection object for tool tips processing
			if(!handled)
			{
				this.selection.Selection_MouseMove(this, e);
			}
 
			// Notify annotation object collection about the mouse down event
			if(!handled)
			{
				this.Annotations.OnMouseMove(e);
			}
 
			// Call the base class
			base.OnMouseMove(e);
		}
 
		/// <summary>
		/// Mouse was double clicked on the control.
		/// </summary>
		/// <param name="e">Event arguments</param>
		protected override void OnDoubleClick(EventArgs e)
		{
			// Notify annotation object collection about the mouse down event
			this.Annotations.OnDoubleClick();
 
            // Call the base class
			base.OnDoubleClick(e);
		}
 
		#endregion
 
        #region Chart get tool tip text events
 
		/// <summary>
		/// Called before showing the tooltip to get the tooltip text.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_GetToolTipText"),
		SRCategory("CategoryAttributeToolTips")]
        public event EventHandler<ToolTipEventArgs> GetToolTipText;
 
		/// <summary>
		/// Checks if GetToolTipEvent is used
		/// </summary>
		/// <returns>True if event is used</returns>
		internal bool IsToolTipEventUsed()
		{
			if(GetToolTipText != null) 
			{
				return true;
			}
 
			return false;
		}
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Cursor event arguments.</param>
		internal void OnGetToolTipText(ToolTipEventArgs arguments)
		{
			if(GetToolTipText != null) 
			{
				GetToolTipText(this, arguments);
			}
		}
 
		#endregion
 
		#region Chart area cursor and selection events
		
		/// <summary>
		/// Called when cursor position is about to change.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_CursorPositionChanging"),
		SRCategory("CategoryAttributeCursor")]
        public event EventHandler<CursorEventArgs> CursorPositionChanging;
 
		/// <summary>
		/// Called when cursor position is changed.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_CursorPositionChanged"),
		SRCategory("CategoryAttributeCursor")]
        public event EventHandler<CursorEventArgs> CursorPositionChanged;
 
		/// <summary>
		/// Called when selection start/end position is about to change.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_SelectionRangeChanging"),
		SRCategory("CategoryAttributeCursor")]
        public event EventHandler<CursorEventArgs> SelectionRangeChanging;
 
		/// <summary>
		/// Called when selection start/end position is changed.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_SelectionRangeChanged"),
		SRCategory("CategoryAttributeCursor")]
        public event EventHandler<CursorEventArgs> SelectionRangeChanged;
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Cursor event arguments.</param>
		internal void OnCursorPositionChanging(CursorEventArgs arguments)
		{
			if(CursorPositionChanging != null) 
			{
				CursorPositionChanging(this, arguments);
			}
		}
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Cursor event arguments.</param>
		internal void OnCursorPositionChanged(CursorEventArgs arguments)
		{
			if(CursorPositionChanged != null) 
			{
				CursorPositionChanged(this, arguments);
			}
		}
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Cursor event arguments.</param>
		internal void OnSelectionRangeChanging(CursorEventArgs arguments)
		{
			if(SelectionRangeChanging != null) 
			{
				SelectionRangeChanging(this, arguments);
			}
		}
		
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Cursor event arguments.</param>
		internal void OnSelectionRangeChanged(CursorEventArgs arguments)
		{
 
			if(SelectionRangeChanged != null) 
			{
				SelectionRangeChanged(this, arguments);
			}
		}
 
		#endregion
 
		#region Axis data scaleView position/size changing events
 
		/// <summary>
		/// Called when axis scaleView position/size is about to change.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_AxisViewChanging"),
		SRCategory("CategoryAttributeAxisView")]
        public event EventHandler<ViewEventArgs> AxisViewChanging;
 
		/// <summary>
		/// Called when axis scaleView position/size is changed.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_AxisViewChanged"),
		SRCategory("CategoryAttributeAxisView")]
        public event EventHandler<ViewEventArgs> AxisViewChanged;
 
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Axis scaleView event arguments.</param>
		internal void OnAxisViewChanging(ViewEventArgs arguments)
		{
			if(AxisViewChanging != null) 
			{
				AxisViewChanging(this, arguments);
			}
		}
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Axis scaleView event arguments.</param>
		internal void OnAxisViewChanged(ViewEventArgs arguments)
		{
			if(AxisViewChanged != null) 
			{
				AxisViewChanged(this, arguments);
			}
		}
 
		#endregion
 
		#region Axis scroll bar events
 
		/// <summary>
		/// Called when axis scroll bar is used by user.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_AxisScrollBarClicked"),
		SRCategory("CategoryAttributeAxisView")]
        public event EventHandler<ScrollBarEventArgs> AxisScrollBarClicked;
 
 
		/// <summary>
		/// Calls event delegate.
		/// </summary>
		/// <param name="arguments">Axis scroll bar event arguments.</param>
		internal void OnAxisScrollBarClicked(ScrollBarEventArgs arguments)
		{
			if(AxisScrollBarClicked != null) 
			{
				AxisScrollBarClicked(this, arguments);
			}
		}
 
		#endregion
 
		#region Painting events
 
		/// <summary>
		/// Called when chart element is painted.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_PostPaint"),
		SRCategory("CategoryAttributeAppearance")]
        public event EventHandler<ChartPaintEventArgs> PostPaint;
 
		/// <summary>
		/// Called when chart element back ground is painted.
		/// </summary>
		[SRDescription("DescriptionAttributeChartEvent_PrePaint"),
		SRCategory("CategoryAttributeAppearance")]
        public event EventHandler<ChartPaintEventArgs> PrePaint;
 
		/// <summary>
		/// Fires when chart element backround must be drawn. 
		/// This event is fired for elements like: ChartPicture, ChartArea and Legend
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected virtual void OnPrePaint(ChartPaintEventArgs e) 
		{
			if(PrePaint != null) 
			{
				PrePaint(this, e);
			}
		}
 
        /// <summary>
        /// Fires when chart element backround must be drawn. 
        /// This event is fired for elements like: ChartPicture, ChartArea and Legend
        /// </summary>
        /// <param name="e">Event arguments.</param>
        internal void CallOnPrePaint(ChartPaintEventArgs e)
        {
            this.OnPrePaint(e);
        }
 
		/// <summary>
		/// Fires when chart element must be drawn. 
		/// This event is fired for elements like: ChartPicture, ChartArea and Legend
		/// </summary>
		/// <param name="e">Event arguments.</param>
        protected virtual void OnPostPaint(ChartPaintEventArgs e) 
		{
			if(PostPaint != null) 
			{
				PostPaint(this, e);
			}
		}
 
        /// <summary>
        /// Fires when chart element must be drawn. 
        /// This event is fired for elements like: ChartPicture, ChartArea and Legend
        /// </summary>
        /// <param name="e">Event arguments.</param>
        internal void CallOnPostPaint(ChartPaintEventArgs e)
        {
            this.OnPostPaint(e);
        }
        
        #endregion
 
		#region Customize event
 
		/// <summary>
		/// Fires just before the chart image is drawn. Use this event to customize the chart picture.
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartEvent_Customize")
		]
		public event EventHandler	Customize;
 
 
		/// <summary>
		/// Fires when all chart data is prepared to be customized before drawing. 
		/// </summary>
        [
        SRDescription("DescriptionAttributeChart_OnCustomize")
        ]
        protected virtual void OnCustomize() 
		{
			if(Customize != null)
			{
				Customize(this, EventArgs.Empty);
			}
		}
 
        /// <summary>
        /// Fires when all chart data is prepared to be customized before drawing. 
        /// </summary>
        internal void CallOnCustomize()
        {
            this.OnCustomize();
        }
 
        /// <summary>
        /// Use this event to customize chart legend.
        /// </summary>
        [
        SRDescription("DescriptionAttributeChartEvent_CustomizeLegend")
        ]
        public event EventHandler<CustomizeLegendEventArgs> CustomizeLegend;
 
 
        /// <summary>
        /// Fires when all chart data is prepared to be customized before drawing. 
        /// </summary>
        [
            SRDescription("DescriptionAttributeChart_OnCustomizeLegend")
        ]
        protected virtual void OnCustomizeLegend(LegendItemsCollection legendItems, string legendName)
        {
            if (CustomizeLegend != null)
            {
                CustomizeLegend(this, new CustomizeLegendEventArgs(legendItems, legendName)); 
            }
        }
 
        /// <summary>
        /// Fires when all chart data is prepared to be customized before drawing. 
        /// </summary>
        internal void CallOnCustomizeLegend(LegendItemsCollection legendItems, string legendName)
        {
            this.OnCustomizeLegend(legendItems, legendName);
        }
        #endregion
 
		#region Annotation events
 
#if WINFORMS_CONTROL
 
		/// <summary>
		/// Fires when annotation text was changed. 
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartEvent_AnnotationTextChanged"),
		SRCategory("CategoryAttributeAnnotation")
		]
		public event EventHandler AnnotationTextChanged;
 
		/// <summary>
		/// Fires when annotation text is changed.
		/// </summary>
		/// <param name="annotation">Annotation which text was changed.</param>
		internal void OnAnnotationTextChanged(Annotation annotation) 
		{
			if(AnnotationTextChanged != null)
			{
				AnnotationTextChanged(annotation, EventArgs.Empty);
			}
		}
 
		/// <summary>
		/// Fires when selected annotation changes. 
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartEvent_AnnotationSelectionChanged"),
		SRCategory("CategoryAttributeAnnotation")
		]
		public event EventHandler AnnotationSelectionChanged;
		/// <summary>
		/// Fires when annotation position was changed.
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartEvent_AnnotationPositionChanged"),
		SRCategory("CategoryAttributeAnnotation")
		]
		public event EventHandler AnnotationPositionChanged;
 
		/// <summary>
		/// Fires when annotation position is changing.
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartEvent_AnnotationPositionChanging"),
		SRCategory("CategoryAttributeAnnotation")
		]
        public event EventHandler<AnnotationPositionChangingEventArgs> AnnotationPositionChanging;
 
		/// <summary>
		/// Fires when annotation is placed by the user on the chart. 
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartEvent_AnnotationPlaced"),
		SRCategory("CategoryAttributeAnnotation")
		]
		public event EventHandler AnnotationPlaced;
 
 
		/// <summary>
		/// Fires when annotation is placed by the user on the chart.
		/// </summary>
		/// <param name="annotation">Annotation which was placed.</param>
		internal void OnAnnotationPlaced(Annotation annotation) 
		{
			if(AnnotationPlaced != null)
			{
				AnnotationPlaced(annotation, EventArgs.Empty);
		
			}
		}
		
		/// <summary>
		/// Fires when selected annotation changes. 
		/// </summary>
		/// <param name="annotation">Annotation which have it's selection changed.</param>
		internal void OnAnnotationSelectionChanged(Annotation annotation) 
		{
			if(AnnotationSelectionChanged != null)
			{
				AnnotationSelectionChanged(annotation, EventArgs.Empty);
			}
		}
 
		/// <summary>
		/// Fires when annotation position was changed.
		/// </summary>
		/// <param name="annotation">Annotation which have it's position changed.</param>
		internal void OnAnnotationPositionChanged(Annotation annotation) 
		{
			if(AnnotationPositionChanged != null)
			{
				AnnotationPositionChanged(annotation, EventArgs.Empty);
			}
		}
 
		/// <summary>
		/// Fires when annotation position is changing.
		/// </summary>
		/// <param name="args">Event arguments.</param>
		/// <returns>True if event was processed.</returns>
		internal bool OnAnnotationPositionChanging(ref AnnotationPositionChangingEventArgs args) 
		{
			if(AnnotationPositionChanging != null)
			{
				AnnotationPositionChanging(args.Annotation, args);
				return true;
			}
			return false;
		}
 
#endif // WINFORMS_CONTROL
 
		#endregion
 
		#region Control DataBind method
 
		/// <summary>
		/// Data binds control to the selected data source.
		/// </summary>
		public void DataBind()
		{
			this.chartPicture.DataBind();
		}
 
		/// <summary>
		/// Aligns data points using their axis labels.
		/// </summary>
		public void AlignDataPointsByAxisLabel()
		{
			this.chartPicture.AlignDataPointsByAxisLabel(false, PointSortOrder.Ascending);
		}
 
		/// <summary>
		/// Aligns data points using their axis labels.
		/// </summary>
		/// <param name="series">Comma separated list of series that should be aligned by axis label.</param>
		public void AlignDataPointsByAxisLabel(string series)
		{
            //Check arguments
            if (series == null)
                throw new ArgumentNullException("series");
 
			// Create list of series
			ArrayList seriesList = new ArrayList();
			string[] seriesNames = series.Split(',');
			foreach(string name in seriesNames)
			{
				seriesList.Add(this.Series[name.Trim()]);
			}
 
			// Align series
			this.chartPicture.AlignDataPointsByAxisLabel(seriesList, false, PointSortOrder.Ascending);
		}
 
		/// <summary>
		/// Aligns data points using their axis labels.
		/// </summary>
		/// <param name="series">Comma separated list of series that should be aligned by axis label.</param>
		/// <param name="sortingOrder">Points sorting order by axis labels.</param>
		public void AlignDataPointsByAxisLabel(string series, PointSortOrder sortingOrder)
		{
            //Check arguments
            if (series == null)
                throw new ArgumentNullException("series");
            
            // Create list of series
			ArrayList seriesList = new ArrayList();
			string[] seriesNames = series.Split(',');
			foreach(string name in seriesNames)
			{
				seriesList.Add(this.Series[name.Trim()]);
			}
 
			// Align series
			this.chartPicture.AlignDataPointsByAxisLabel(seriesList, true, sortingOrder);
		}
 
		/// <summary>
		/// Aligns data points using their axis labels.
		/// </summary>
		/// <param name="sortingOrder">Points sorting order by axis labels.</param>
		public void AlignDataPointsByAxisLabel(PointSortOrder sortingOrder)
		{
			this.chartPicture.AlignDataPointsByAxisLabel(true, sortingOrder);
		}
 
		/// <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>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X is a cartesian coordinate and well understood")]
        public void DataBindTable(
            IEnumerable dataSource,
            string xField)
        {
            this.chartPicture.DataBindTable(
                dataSource,
                xField);
        }
 
		/// <summary>
		/// Automatically creates and binds series to specified data table. 
		/// Each column of the table becomes a Y value in a separate series.
		/// </summary>
		/// <param name="dataSource">Data source.</param>
		public void DataBindTable(IEnumerable dataSource)
		{
			this.chartPicture.DataBindTable(
				dataSource, 
				String.Empty);
		}
 
		/// <summary>
		/// Data bind chart to the table. Series will be automatically added to the chart depending ont
		/// yhe 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>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
		public void DataBindCrossTable(
			IEnumerable dataSource, 
			string seriesGroupByField, 
			string xField, 
			string yFields, 
			string otherFields)
		{
			this.chartPicture.DataBindCrossTab(
				dataSource, 
				seriesGroupByField, 
				xField, 
				yFields, 
				otherFields,
				false,
				PointSortOrder.Ascending);
		}
 
		/// <summary>
		/// Data bind chart to the table. Series will be automatically added to the chart depending ont
		/// yhe 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="sortingOrder">Series will be sorted by group field values in specified order.</param>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
		public void DataBindCrossTable(
			IEnumerable dataSource, 
			string seriesGroupByField, 
			string xField, 
			string yFields, 
			string otherFields,
			PointSortOrder sortingOrder)
		{
			this.chartPicture.DataBindCrossTab(
				dataSource, 
				seriesGroupByField, 
				xField, 
				yFields, 
				otherFields,
				true,
				sortingOrder);
		}
 
		#endregion
 
		#region Special Extension Methods and Properties
 
 
		/// <summary>
		/// Gets the requested chart service.
		/// </summary>
		/// <param name="serviceType">AxisName of requested service.</param>
		/// <returns>Instance of the service or null if it can't be found.</returns>
		public new object GetService(Type serviceType)
		{
            // Check arguments
            if (serviceType == null)
                throw new ArgumentNullException("serviceType");
 
			object service = null;
			if(serviceContainer != null)
			{
				service = serviceContainer.GetService(serviceType);
			}
 
			if(service == null)
			{
				base.GetService(serviceType);
			}
 
			return service;
		}
 
        /// <summary>
        /// Called when a numeric value has to be converted to a string.
        /// </summary>
        [SRDescription("DescriptionAttributeChartEvent_PrePaint")]
        public event EventHandler<FormatNumberEventArgs> FormatNumber;
 
        /// <summary>
        /// Utility method for firing the FormatNumber event. Allows it to be
        /// handled via OnFormatNumber as is the usual pattern as well as via
        /// CallOnFormatNumber.
        /// </summary>
        /// <param name="caller">Event caller. Can be ChartPicture, ChartArea or Legend objects.</param>
        /// <param name="e">Event arguemtns</param>
        private void OnFormatNumber(object caller, FormatNumberEventArgs e)
        {
            if (FormatNumber != null)
            {
                FormatNumber(caller, e);
            }
        }
 
        /// <summary>
        /// Called when a numeric value has to be converted to a string.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnFormatNumber(FormatNumberEventArgs e)
        {
            OnFormatNumber(this, e);
        }
 
        /// <summary>
        /// Called when a numeric value has to be converted to a string.
        /// </summary>
        /// <param name="caller">Event caller. Can be ChartPicture, ChartArea or Legend objects.</param>
        /// <param name="e">Event arguments.</param>
        internal void CallOnFormatNumber(object caller, FormatNumberEventArgs e)
        {
            this.OnFormatNumber(caller, e);
        }
 
        #endregion
 
        #region Accessibility
 
        // Current chart accessibility object
        private ChartAccessibleObject _chartAccessibleObject = null;
 
        /// <summary>
        /// Overridden to return the custom AccessibleObject for the entire chart.
        /// </summary>
        /// <returns>Chart accessibility object.</returns>
        protected override AccessibleObject CreateAccessibilityInstance()
        {
            if (this._chartAccessibleObject == null)
            {
                this._chartAccessibleObject = new ChartAccessibleObject(this);
            }
            return this._chartAccessibleObject;
        }
 
        /// <summary>
        /// Reset accessibility object children.
        /// </summary>
        private void ResetAccessibilityObject()
        {
            if (this._chartAccessibleObject != null)
            {
                this._chartAccessibleObject.ResetChildren();
            }
        }
        
        #endregion // Accessibility
 
        #region IDisposable override
 
        /// <summary>
        /// Disposing control resourses
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            // call first because font cache
            base.Dispose(disposing);
 
            if (disposing)
            {
 
                // Dispose managed objects here
                if (_imageLoader != null)
                {
                    _imageLoader.Dispose();
                    _imageLoader = null;
                }
 
                if (_namedImages != null)
                {
                    _namedImages.Dispose();
                    _namedImages = null;
                }
 
                if (_chartTypeRegistry != null)
                {
                    _chartTypeRegistry.Dispose();
                    _chartTypeRegistry = null;
                }
 
                if (serviceContainer != null)
                {
                    serviceContainer.RemoveService(typeof(Chart));
                    serviceContainer.Dispose();
                    serviceContainer = null;
                }
 
                // Dispose selection manager
                if (selection != null)
                {
                    selection.Dispose();
                    selection = null;
                }
 
                // Dispose print manager
                if (_printingManager != null)
                {
                    _printingManager.Dispose();
                    _printingManager = null;
                }
 
                // Dispoase buffer
                if (paintBufferBitmap != null)
                {
                    paintBufferBitmap.Dispose();
                    paintBufferBitmap = null;
                }
 
                if (paintBufferBitmapGraphics != null)
                {
                    paintBufferBitmapGraphics.Dispose();
                    paintBufferBitmapGraphics = null;
                }
            }
            
            base.Dispose(disposing);
 
            //The chart picture and datamanager will be the last to be disposed
            if (disposing)
            {
                if (_dataManager != null)
                {
                    _dataManager.Dispose();
                    _dataManager = null;
                }
                if (chartPicture != null)
                {
                    chartPicture.Dispose();
                    chartPicture = null;
                }
            }
        }
        #endregion
    }
 
	#region Customize event delegate
 
        /// <summary>
        /// Chart legend customize events arguments
        /// </summary>
        public class CustomizeLegendEventArgs : EventArgs
        {
            private LegendItemsCollection _legendItems = null;
            private string _legendName = "";
 
            /// <summary>
            /// Default construvtor is not accessible
            /// </summary>
            private CustomizeLegendEventArgs()
            {
            }
 
            /// <summary>
            /// Customize legend event arguments constructor
            /// </summary>
            /// <param name="legendItems">Legend items collection.</param>
            public CustomizeLegendEventArgs(LegendItemsCollection legendItems)
            {
                this._legendItems = legendItems;
            }
 
            /// <summary>
            /// Customize legend event arguments constructor
            /// </summary>
            /// <param name="legendItems">Legend items collection.</param>
            /// <param name="legendName">Legend name.</param>
            public CustomizeLegendEventArgs(LegendItemsCollection legendItems, string legendName)
            {
                this._legendItems = legendItems;
                this._legendName = legendName;
            }
 
            /// <summary>
            /// Legend name.
            /// </summary>
            public string LegendName
            {
                get
                {
                    return _legendName;
                }
            }
 
            /// <summary>
            /// Legend items collection.
            /// </summary>
            public LegendItemsCollection LegendItems
            {
                get
                {
                    return _legendItems;
                }
            }
 
        }
 
	#endregion
}