Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.DataVisualization / Common / General / Chart.cs
1 //-------------------------------------------------------------
2 // <copyright company=\92Microsoft Corporation\92>
3 //   Copyright © Microsoft Corporation. All Rights Reserved.
4 // </copyright>
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 //  File:               Chart.cs
9 //
10 //  Namespace:  System.Web.UI.WebControls[Windows.Forms].Charting
11 //
12 //      Classes:        ChartImage, ChartPicture, ChartPaintEventArgs
13 //
14 //  Purpose:    This file contains classes, which are used for Image 
15 //                              creation and chart painting. This file has also a 
16 //                              class, which is used for Paint events arguments.
17 //
18 //      Reviewed:       GS - August 2, 2002
19 //                              AG - August 8, 2002
20 //              AG - Microsoft 16, 2007
21 //
22 //===================================================================
23
24 #region Used Namespaces
25
26 using System;
27 using System.Drawing;
28 using System.Drawing.Drawing2D;
29 using System.Drawing.Design;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Resources;
33 using System.Reflection;
34 using System.IO;
35 using System.Data;
36 using System.Collections;
37 using System.Drawing.Imaging;
38 using System.Drawing.Text;
39 using System.Xml;
40 using System.Globalization;
41 using System.Diagnostics.CodeAnalysis;
42 using System.Diagnostics;
43 using System.Security;
44 using System.Runtime.InteropServices;
45 using System.Collections.Generic;
46
47 #if Microsoft_CONTROL
48
49         using System.Windows.Forms.DataVisualization.Charting.Data;
50         using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
51         using System.Windows.Forms.DataVisualization.Charting.Utilities;
52         using System.Windows.Forms.DataVisualization.Charting.Borders3D;
53         using System.Windows.Forms.DataVisualization.Charting;
54 #else
55         using System.Web;
56         using System.Web.UI;
57         using System.Net;
58         using System.Web.UI.DataVisualization.Charting;
59         using System.Web.UI.DataVisualization.Charting.Data;
60         using System.Web.UI.DataVisualization.Charting.ChartTypes;
61         using System.Web.UI.DataVisualization.Charting.Utilities;
62         using System.Web.UI.DataVisualization.Charting.Borders3D;
63 #endif
64
65
66 #endregion
67
68 #if Microsoft_CONTROL
69 namespace System.Windows.Forms.DataVisualization.Charting
70 #else
71 namespace System.Web.UI.DataVisualization.Charting
72
73 #endif
74 {
75         #region Enumerations
76
77 #if !Microsoft_CONTROL
78
79         /// <summary>
80         /// An enumeration of supported image types
81         /// </summary>
82         public enum ChartImageType
83         {
84                 /// <summary>
85                 /// BMP image format
86                 /// </summary>
87                 Bmp,
88                 /// <summary>
89                 /// Jpeg image format
90                 /// </summary>
91                 Jpeg, 
92
93                 /// <summary>
94                 /// Png image format
95                 /// </summary>
96         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Png")]
97         Png,
98                 
99                 /// <summary>
100                 /// Enhanced Meta File (Emf) image format.
101                 /// </summary>
102                 Emf,
103
104     };
105 #endif
106
107
108         #endregion
109
110         /// <summary>
111     /// ChartImage class adds image type and data binding functionality to 
112     /// the base ChartPicture class.
113         /// </summary>
114         internal class ChartImage : ChartPicture
115         {
116                 #region Fields
117
118                 // Private data members, which store properties values
119                 private int                             _compression = 0;
120
121                 // Chart data source object
122                 private object  _dataSource = null;
123
124                 // Indicates that control was bound to the data source
125                 internal bool   boundToDataSource = false;
126
127 #if !Microsoft_CONTROL
128                 private ChartImageType  imageType = ChartImageType.Png;
129 #endif
130                 
131                 #endregion
132
133                 #region Constructor
134
135                 /// <summary>
136                 /// Chart internal constructor.
137                 /// </summary>
138                 /// <param name="container">Service container</param>
139         internal ChartImage(IServiceContainer container)
140             : base(container)
141         {
142         }
143
144                 #endregion // Constructor
145         
146                 #region Properties
147
148                 /// <summary>
149         /// Gets or sets the data source for the Chart object.
150                 /// </summary>
151                 [
152                 SRCategory("CategoryAttributeData"),
153                 Bindable(true),
154                 SRDescription("DescriptionAttributeDataSource"),
155                 DefaultValue(null),
156                 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
157                 SerializationVisibilityAttribute(SerializationVisibility.Hidden)
158                 ]
159                 public object DataSource
160                 {
161                         get
162                         {
163                                 return _dataSource;
164                         }
165                         set
166                         {
167                                 if(_dataSource != value)
168                                 {
169                                         _dataSource = value;
170                                         this.boundToDataSource = false;
171                                 }
172                         }
173                 }
174
175 #if !Microsoft_CONTROL
176
177                 /// <summary>
178                 /// Image type (Jpeg, BMP, Png)
179                 /// </summary>
180                 [
181                 SRCategory("CategoryAttributeImage"),
182                 Bindable(true),
183                 DefaultValue(ChartImageType.Png),
184                 SRDescription("DescriptionAttributeImageType"),
185                 PersistenceMode(PersistenceMode.Attribute)
186                 ]
187                 public ChartImageType ImageType
188                 {
189                         get
190                         {
191                                 return imageType; 
192                         }
193                         set
194                         {
195                                 imageType = value;
196                         }
197                 }
198
199 #endif
200
201                 /// <summary>
202                 /// Image compression value
203                 /// </summary>
204                 [
205                 SRCategory("CategoryAttributeImage"),
206                 Bindable(true),
207                 DefaultValue(0),
208                 SRDescription("DescriptionAttributeChartImage_Compression"),
209                 #if !Microsoft_CONTROL
210                 PersistenceMode(PersistenceMode.Attribute)
211                 #endif
212                 ]
213                 public int Compression
214                 {
215                         get
216                         {
217                                 return _compression;
218                         }
219                         set
220                         {
221                                 if(value < 0 || value > 100)
222                                 {
223                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionChartCompressionInvalid));
224                                 }
225                                 _compression = value;
226                         }
227                 }
228
229                 #endregion
230
231                 #region Methods
232
233                 #region Image Manipulation
234
235
236                 /// <summary>
237                 /// Saves image into the metafile stream. 
238                 /// </summary>
239                 /// <param name="imageStream">Image stream.</param>
240                 /// <param name="emfType">Image stream.</param>
241         [SecuritySafeCritical]
242                 public void SaveIntoMetafile(Stream imageStream, EmfType emfType)
243                 {
244             // Check arguments
245             if (imageStream == null)
246                 throw new ArgumentNullException("imageStream");
247
248                         // Create temporary Graphics object for metafile
249             using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
250             {
251                 using (Graphics newGraphics = Graphics.FromImage(bitmap))
252                 {
253                     IntPtr hdc = IntPtr.Zero;
254                     try
255                     {
256                         System.Security.Permissions.SecurityPermission securityPermission = new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode);
257                         securityPermission.Demand();
258                         
259                         hdc = newGraphics.GetHdc();
260
261
262                         // Create metafile object to record.
263                         using (Metafile metaFile = new Metafile(
264                             imageStream,
265                             hdc,
266                             new Rectangle(0, 0, this.Width, this.Height),
267                             MetafileFrameUnit.Pixel,
268                             emfType))
269                         {
270
271                             // Create graphics object to record metaFile.
272                             using (Graphics metaGraphics = Graphics.FromImage(metaFile))
273                             {
274
275                                 // Note: Fix for issue #3674. Some 3D borders shadows may be drawn outside 
276                                 // of image boundaries. This causes issues when generated EMF file 
277                                 // is placed in IE. Image looks shifted down and hot areas do not align.
278                                 if (this.BorderSkin.SkinStyle != BorderSkinStyle.None)
279                                 {
280                                     metaGraphics.Clip = new Region(new Rectangle(0, 0, this.Width, this.Height));
281                                 }
282
283                                 // Draw chart in the metafile
284                                 this.ChartGraph.IsMetafile = true;
285                                 this.Paint(metaGraphics, false);
286                                 this.ChartGraph.IsMetafile = false;
287
288                             }
289                         }
290                     }
291                     finally
292                     {
293                         if (hdc != IntPtr.Zero)
294                         {
295                             newGraphics.ReleaseHdc(hdc);
296                         }
297                     }
298                 }
299             }
300                 }
301         
302         public Bitmap GetImage()
303         {
304             return this.GetImage(96);
305         }
306                 /// <summary>
307                 /// Create Image and draw chart picture
308                 /// </summary>
309         public Bitmap GetImage(float resolution)
310                 {
311                         // Create a new bitmap
312
313             Bitmap image = null;
314
315             while (image == null)
316             {
317                 bool failed = true;
318                 try
319                 {
320                     image = new Bitmap(Math.Max(1,Width), Math.Max(1,Height));
321                     image.SetResolution(resolution, resolution);
322                     failed = false;
323                 }
324                 catch (ArgumentException)
325                 {
326                     failed = true;
327                 }
328                 catch (OverflowException)
329                 {
330                     failed = true;
331                 }
332                 catch (InvalidOperationException)
333                 {
334                     failed = true;
335                 }
336                 catch (ExternalException)
337                 {
338                     failed = true;
339                 }
340
341                 if (failed)
342                 {
343                     // if failed to create the image, decrease the size and the resolution of the chart
344                     image = null;
345                     float newResolution = Math.Max(resolution / 2, 96);
346                     Width = (int)Math.Ceiling(Width * newResolution / resolution);
347                     Height = (int)Math.Ceiling(Height * newResolution / resolution);
348                     resolution = newResolution;
349                 }
350             }
351
352                         // Creates a new Graphics object from the 
353                         // specified Image object.
354                         Graphics offScreen = Graphics.FromImage( image );
355
356
357
358             Color backGroundColor;
359
360             if (this.BackColor != Color.Empty)
361                 backGroundColor = this.BackColor;
362             else
363                 backGroundColor = Color.White;
364
365             // Get the page color if border skin is visible.
366             if (GetBorderSkinVisibility() &&
367                 this.BorderSkin.PageColor != Color.Empty)
368             {
369                 backGroundColor = this.BorderSkin.PageColor;
370             }
371
372             // draw a rctangle first with the size of the control, this prevent strange behavior when printing in the reporting services,
373             // without this rectangle, the printed picture is blurry
374             Pen pen = new Pen(backGroundColor);
375             offScreen.DrawRectangle(pen, 0, 0, Width, Height);
376             pen.Dispose();
377
378                         // Paint the chart
379                         Paint( offScreen , false);
380
381                         // Dispose Graphic object
382                         offScreen.Dispose();
383
384                         // Return reference to the image
385                         return image;
386                 }
387
388                 #endregion // Image Manipulation
389
390                 #region Data Binding
391
392                 /// <summary>
393                 /// Checks if the type of the data source is valid.
394                 /// </summary>
395                 /// <param name="dataSource">Data source object to test.</param>
396                 /// <returns>True if valid data source object.</returns>
397                 static internal bool IsValidDataSource(object dataSource)
398                 {
399             if( null != dataSource && 
400                 (
401                 dataSource is IEnumerable ||
402                                 dataSource is DataSet ||
403                                 dataSource is DataView ||
404                                 dataSource is DataTable ||
405                                 dataSource is System.Data.OleDb.OleDbCommand ||
406                                 dataSource is System.Data.SqlClient.SqlCommand ||
407                                 dataSource is System.Data.OleDb.OleDbDataAdapter ||
408                                 dataSource is System.Data.SqlClient.SqlDataAdapter ||
409                                 // ADDED: for VS2005 compatibility, DT Nov 25, 2005
410                                 dataSource.GetType().GetInterface("IDataSource") != null
411                                 // END ADDED
412                                 )
413               )
414                         {
415                                 return true;
416                         }
417
418                         return false;
419                 }
420
421
422
423                 /// <summary>
424                 /// Gets an list of the data source member names.
425                 /// </summary>
426                 /// <param name="dataSource">Data source object to get the members for.</param>
427                 /// <param name="usedForYValue">Indicates that member will be used for Y values.</param>
428                 /// <returns>List of member names.</returns>
429         [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
430             Justification = "Too large of a code change to justify making this change")]
431                 static internal ArrayList GetDataSourceMemberNames(object dataSource, bool usedForYValue)
432                 {
433                         ArrayList       names = new ArrayList();
434             if (dataSource != null)
435             {
436                 // ADDED: for VS2005 compatibility, DT Nov 25, 2004
437                 if (dataSource.GetType().GetInterface("IDataSource") != null)
438                 {
439                     try
440                     {
441                         MethodInfo m = dataSource.GetType().GetMethod("Select");
442                         if (m != null)
443                         {
444                             if (m.GetParameters().Length == 1)
445                             {
446                                 // SQL derived datasource
447                                 Type selectArgsType = dataSource.GetType().Assembly.GetType("System.Web.UI.DataSourceSelectArguments", true);
448                                 ConstructorInfo ci = selectArgsType.GetConstructor(new Type[] { });
449                                 dataSource = m.Invoke(dataSource, new object[] { ci.Invoke(new object[] { }) });
450                             }
451                             else
452                             {
453                                 // object data source
454                                 dataSource = m.Invoke(dataSource, new object[] { });
455                             }
456                         }
457                     }
458                     catch (TargetException)
459                     {
460                     }
461                     catch (TargetInvocationException)
462                     {
463                     }
464                 }
465                 // END ADDED
466
467                 // Check all DataTable based data souces
468                 DataTable dataTable = null;
469
470                 if (dataSource is DataTable)
471                 {
472                     dataTable = (DataTable)dataSource;
473                 }
474                 else if (dataSource is DataView)
475                 {
476                     dataTable = ((DataView)dataSource).Table;
477                 }
478                 else if (dataSource is DataSet && ((DataSet)dataSource).Tables.Count > 0)
479                 {
480                     dataTable = ((DataSet)dataSource).Tables[0];
481                 }
482                 else if (dataSource is System.Data.OleDb.OleDbDataAdapter)
483                 {
484                     dataTable = new DataTable();
485                     dataTable.Locale = CultureInfo.CurrentCulture;
486                     dataTable = ((System.Data.OleDb.OleDbDataAdapter)dataSource).FillSchema(dataTable, SchemaType.Mapped);
487                 }
488                 else if (dataSource is System.Data.SqlClient.SqlDataAdapter)
489                 {
490                     dataTable = new DataTable();
491                     dataTable.Locale = CultureInfo.CurrentCulture;
492                     dataTable = ((System.Data.SqlClient.SqlDataAdapter)dataSource).FillSchema(dataTable, SchemaType.Mapped);
493                 }
494                 else if (dataSource is System.Data.OleDb.OleDbDataReader)
495                 {
496                     // Add table columns names
497                     for (int fieldIndex = 0; fieldIndex < ((System.Data.OleDb.OleDbDataReader)dataSource).FieldCount; fieldIndex++)
498                     {
499                         if (!usedForYValue || ((System.Data.OleDb.OleDbDataReader)dataSource).GetFieldType(fieldIndex) != typeof(string))
500                         {
501                             names.Add(((System.Data.OleDb.OleDbDataReader)dataSource).GetName(fieldIndex));
502                         }
503                     }
504                 }
505                 else if (dataSource is System.Data.SqlClient.SqlDataReader)
506                 {
507                     // Add table columns names
508                     for (int fieldIndex = 0; fieldIndex < ((System.Data.SqlClient.SqlDataReader)dataSource).FieldCount; fieldIndex++)
509                     {
510                         if (!usedForYValue || ((System.Data.SqlClient.SqlDataReader)dataSource).GetFieldType(fieldIndex) != typeof(string))
511                         {
512                             names.Add(((System.Data.SqlClient.SqlDataReader)dataSource).GetName(fieldIndex));
513                         }
514                     }
515                 }
516                 else if (dataSource is System.Data.OleDb.OleDbCommand)
517                 {
518                     System.Data.OleDb.OleDbCommand command = (System.Data.OleDb.OleDbCommand)dataSource;
519                     if (command.Connection != null)
520                     {
521                         command.Connection.Open();
522                         System.Data.OleDb.OleDbDataReader dataReader = command.ExecuteReader();
523                         if (dataReader.Read())
524                         {
525                             for (int fieldIndex = 0; fieldIndex < dataReader.FieldCount; fieldIndex++)
526                             {
527                                 if (!usedForYValue || dataReader.GetFieldType(fieldIndex) != typeof(string))
528                                 {
529                                     names.Add(dataReader.GetName(fieldIndex));
530                                 }
531                             }
532                         }
533
534                         dataReader.Close();
535                         command.Connection.Close();
536                     }
537                 }
538                 else if (dataSource is System.Data.SqlClient.SqlCommand)
539                 {
540                     System.Data.SqlClient.SqlCommand command = (System.Data.SqlClient.SqlCommand)dataSource;
541                     if (command.Connection != null)
542                     {
543                         command.Connection.Open();
544                         System.Data.SqlClient.SqlDataReader dataReader = command.ExecuteReader();
545                         if (dataReader.Read())
546                         {
547                             for (int fieldIndex = 0; fieldIndex < dataReader.FieldCount; fieldIndex++)
548                             {
549                                 if (!usedForYValue || dataReader.GetFieldType(fieldIndex) != typeof(string))
550                                 {
551                                     names.Add(dataReader.GetName(fieldIndex));
552                                 }
553                             }
554                         }
555
556                         dataReader.Close();
557                         command.Connection.Close();
558                     }
559                 }
560
561
562                 // Check if DataTable was set
563                 if (dataTable != null)
564                 {
565                     // Add table columns names
566                     foreach (DataColumn column in dataTable.Columns)
567                     {
568                         if (!usedForYValue || column.DataType != typeof(string))
569                         {
570                             names.Add(column.ColumnName);
571                         }
572                     }
573                 }
574
575                 else if (names.Count == 0 && dataSource is ITypedList)
576                 {
577                     foreach (PropertyDescriptor pd in ((ITypedList)dataSource).GetItemProperties(null))
578                     {
579                         if (!usedForYValue || pd.PropertyType != typeof(string))
580                         {
581                             names.Add(pd.Name);
582                         }
583                     }
584                 }
585                 else if (names.Count == 0 && dataSource is IEnumerable)
586                 {
587                     // .Net 2.0 ObjectDataSource processing
588                     IEnumerator e = ((IEnumerable)dataSource).GetEnumerator();
589                     e.Reset();
590                     e.MoveNext();
591                     foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(e.Current))
592                     {
593                         if (!usedForYValue || pd.PropertyType != typeof(string))
594                         {
595                             names.Add(pd.Name);
596                         }
597
598                     }
599                 }
600
601
602
603                 // Check if list still empty
604                 if (names.Count == 0)
605                 {
606                     // Add first column or any data member name
607                     names.Add("0");
608                 }
609
610             }
611
612                         return names;
613                 }
614
615                 /// <summary>
616                 /// Data binds control to the data source
617                 /// </summary>
618         [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
619             Justification="Too large of a code change to justify making this change")]
620         internal void DataBind()
621         {
622             // Set bound flag
623             this.boundToDataSource = true;
624
625             object dataSource = this.DataSource;
626             if (dataSource != null)
627             {
628
629                 // Convert data adapters to command object
630                 if (dataSource is System.Data.OleDb.OleDbDataAdapter)
631                 {
632                     dataSource = ((System.Data.OleDb.OleDbDataAdapter)dataSource).SelectCommand;
633                 }
634                 else if (dataSource is System.Data.SqlClient.SqlDataAdapter)
635                 {
636                     dataSource = ((System.Data.SqlClient.SqlDataAdapter)dataSource).SelectCommand;
637                 }
638
639                 // Convert data source to recognizable source for the series
640                 if (dataSource is DataSet && ((DataSet)dataSource).Tables.Count > 0)
641                 {
642                     dataSource = ((DataSet)dataSource).DefaultViewManager.CreateDataView(((DataSet)dataSource).Tables[0]);
643
644                 }
645                 else if (dataSource is DataTable)
646                 {
647                     dataSource = new DataView((DataTable)dataSource);
648                 }
649                 else if (dataSource is System.Data.OleDb.OleDbCommand)
650                 {
651                     System.Data.OleDb.OleDbCommand command = (System.Data.OleDb.OleDbCommand)dataSource;
652                     command.Connection.Open();
653                     System.Data.OleDb.OleDbDataReader dataReader = command.ExecuteReader();
654
655                     this.DataBind(dataReader, null);
656
657                     dataReader.Close();
658                     command.Connection.Close();
659                     return;
660                 }
661                 else if (dataSource is System.Data.SqlClient.SqlCommand)
662                 {
663                     System.Data.SqlClient.SqlCommand command = (System.Data.SqlClient.SqlCommand)dataSource;
664                     command.Connection.Open();
665                     System.Data.SqlClient.SqlDataReader dataReader = command.ExecuteReader();
666
667                     this.DataBind(dataReader, null);
668
669                     dataReader.Close();
670                     command.Connection.Close();
671                     return;
672                 }
673                 else if (dataSource is IList)
674                 {
675                     dataSource = dataSource as IList;
676                 }
677                 else if (dataSource is IListSource  )
678                 {
679                     if (((IListSource)dataSource).ContainsListCollection && ((IListSource)dataSource).GetList().Count > 0)
680                     {
681                         dataSource = ((IListSource)dataSource).GetList()[0] as IEnumerable;
682                     }
683                     else
684                     {
685                         dataSource = ((IListSource)dataSource).GetList();
686                     }
687                 }
688                 else
689                 {
690                     dataSource = dataSource as IEnumerable;
691                 }
692
693                 // Data bind
694                 DataBind(dataSource as IEnumerable, null);
695             }
696         }
697
698                 /// <summary>
699                 /// Data binds control to the data source
700                 /// </summary>
701                 /// <param name="dataSource">Data source to bind to.</param>
702                 /// <param name="seriesList">List of series to bind.</param>
703                 internal void DataBind(IEnumerable dataSource, ArrayList seriesList)
704                 {
705                         // Data bind series
706                         if(dataSource != null && this.Common != null)
707                         {
708                                 //************************************************************
709                                 //** If list of series is not provided - bind all of them.
710                                 //************************************************************
711                                 if(seriesList == null)
712                                 {
713                                         seriesList = new ArrayList();
714                                         foreach(Series series in this.Common.Chart.Series)
715                                         {
716                         // note: added for design time data binding
717                         if (this.Common.Chart.IsDesignMode())
718                         {
719                             if (series.YValueMembers.Length > 0)
720                             {
721                                 seriesList.Add(series);
722                             }
723                         }
724                         else
725                         {
726                             seriesList.Add(series);
727                         }
728                                         }
729                                 }
730
731                                 //************************************************************
732                                 //** Clear all data points in data bound series
733                                 //************************************************************
734                                 foreach(Series series in seriesList)
735                                 {
736                                         if(series.XValueMember.Length > 0 || series.YValueMembers.Length > 0)
737                                         {
738                                                 series.Points.Clear();
739                                         }
740                                 }
741
742                                 //************************************************************
743                                 //** Get and reset data enumerator.
744                                 //************************************************************
745                                 IEnumerator     enumerator = dataSource.GetEnumerator();
746                                 if(enumerator.GetType() != typeof(System.Data.Common.DbEnumerator) )
747                                 {
748                     try
749                     {
750                         enumerator.Reset();
751                     }
752                     // Some enumerators may not support Resetting 
753                     catch (InvalidOperationException)
754                     {
755                     }
756                     catch (NotImplementedException)
757                     {
758                     }
759                     catch (NotSupportedException)
760                     {
761                     }
762                                 }
763
764
765                                 //************************************************************
766                                 //** Loop through the enumerator.
767                                 //************************************************************
768                                 bool    valueExsists = true;
769                                 bool    autoDetectType = true;
770                                 do
771                                 {
772                                         // Move to the next item
773                                         valueExsists = enumerator.MoveNext();
774
775                                         // Loop through all series 
776                                         foreach(Series series in seriesList)
777                                         {
778                                                 if(series.XValueMember.Length > 0 || series.YValueMembers.Length > 0)
779                                                 {
780                                                         //************************************************************
781                                                         //** Check and convert fields names.
782                                                         //************************************************************
783
784                                                         // Convert comma separated field names string to array of names
785                                                         string[] yFieldNames = null;
786                                                         if(series.YValueMembers.Length > 0)
787                                                         {
788                                                                 yFieldNames = series.YValueMembers.Replace(",,", "\n").Split(',');
789                                                                 for(int index = 0; index < yFieldNames.Length; index++)
790                                                                 {
791                                                                         yFieldNames[index] = yFieldNames[index].Replace("\n", ",").Trim();
792                                                                 }
793                                                         }
794                         
795                                                         // Double check that a string object is not provided for data binding
796                                                         if(dataSource is string)
797                                                         {
798                                 throw (new ArgumentException(SR.ExceptionDataBindYValuesToString, "dataSource"));
799                                                         }
800
801                                                         // Check number of fields
802                                                         if(yFieldNames == null || yFieldNames.GetLength(0) > series.YValuesPerPoint)
803                                                         {
804                                                                 throw(new ArgumentOutOfRangeException("dataSource", SR.ExceptionDataPointYValuesCountMismatch(series.YValuesPerPoint.ToString(System.Globalization.CultureInfo.InvariantCulture) ) ) );
805                                                         }
806
807                                                         //************************************************************
808                                                         //** Create new data point.
809                                                         //************************************************************
810                                                         if(valueExsists)
811                                                         {
812                                                                 // Auto detect values type
813                                                                 if(autoDetectType)
814                                                                 {
815                                                                         autoDetectType = false;
816
817                                                                         // Make sure Y field is not empty
818                                                                         string  yField = yFieldNames[0];
819                                                                         int             fieldIndex = 1;
820                                                                         while(yField.Length == 0 && fieldIndex < yFieldNames.Length)
821                                                                         {
822                                                                                 yField = yFieldNames[fieldIndex++];
823                                                                         }
824
825                                                                         DataPointCollection.AutoDetectValuesType(series, enumerator, series.XValueMember.Trim(), enumerator, yField);
826                                                                 }
827
828
829                                                                 // Create new point
830                                                                 DataPoint       newDataPoint = new DataPoint(series);
831                                                                 bool            emptyValues = false;
832                                                                 bool            xValueIsNull = false;
833                                                                 
834                                                                 //************************************************************
835                                                                 //** Get new point X and Y values.
836                                                                 //************************************************************
837                                                                 object[]        yValuesObj = new object[yFieldNames.Length];
838                                                                 object          xValueObj = null;
839
840                                                                 // Set X to the value provided or use sequence numbers starting with 1
841                                                                 if(series.XValueMember.Length > 0)
842                                                                 {
843                                                                         xValueObj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, series.XValueMember.Trim());
844                                                                         if(xValueObj is System.DBNull || xValueObj == null)
845                                                                         {
846                                                                                 xValueIsNull = true;
847                                                                                 emptyValues = true;
848                                                                                 xValueObj = 0.0;
849                                                                         }
850                                                                 }
851
852                                                                 if(yFieldNames.Length == 0)
853                                                                 {
854                                                                         yValuesObj[0] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, null);
855                                                                         if(yValuesObj[0] is System.DBNull || yValuesObj[0] == null)
856                                                                         {
857                                                                                 emptyValues = true;
858                                                                                 yValuesObj[0] = 0.0;
859                                                                         }
860                                                                 }
861                                                                 else
862                                                                 {
863                                                                         for(int i = 0; i < yFieldNames.Length; i++)
864                                                                         {
865                                                                                 if(yFieldNames[i].Length > 0)
866                                                                                 {
867                                                                                         yValuesObj[i] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, yFieldNames[i]);
868                                                                                         if(yValuesObj[i] is System.DBNull || yValuesObj[i] == null)
869                                                                                         {
870                                                                                                 emptyValues = true;
871                                                                                                 yValuesObj[i] = 0.0;
872                                                                                         }
873                                                                                 }
874                                                                                 else
875                                                                                 {
876                                                                                         yValuesObj[i] = (((Series)seriesList[0]).IsYValueDateTime()) ? DateTime.Now.Date.ToOADate() : 0.0;
877                                                                                 }
878                                                                         }
879                                                                 }
880
881
882                                                                 // Add data point if X value is not Null
883                                                                 if(!xValueIsNull)
884                                                                 {
885                                                                         if(emptyValues)
886                                                                         {
887                                                                                 if(xValueObj != null)
888                                                                                 {
889                                                                                         newDataPoint.SetValueXY(xValueObj, yValuesObj);
890                                                                                 }
891                                                                                 else
892                                                                                 {
893                                                                                         newDataPoint.SetValueXY(0, yValuesObj);
894                                                                                 }
895                                                                                 series.Points.DataPointInit(ref newDataPoint);
896                                                                                 newDataPoint.IsEmpty = true;
897                                                                                 series.Points.Add(newDataPoint);
898                                                                         }
899                                                                         else
900                                                                         {
901                                                                                 if(xValueObj != null)
902                                                                                 {
903                                                                                         newDataPoint.SetValueXY(xValueObj, yValuesObj);
904                                                                                 }
905                                                                                 else
906                                                                                 {
907                                                                                         newDataPoint.SetValueXY(0, yValuesObj);
908                                                                                 }
909                                                                                 series.Points.DataPointInit(ref newDataPoint);
910                                                                                 series.Points.Add(newDataPoint);
911                                                                         }
912                                                                 }
913                                 if (this.Common.Chart.IsDesignMode())
914                                 {
915                                     series["TempDesignData"] = "true";
916                                 }
917                                                         }
918                                                 }
919                                         }
920                                 
921                                 } while(valueExsists);
922
923                         }
924                 }
925
926
927                 /// <summary>
928                 /// Aligns data points using their axis labels.
929                 /// </summary>
930                 /// <param name="sortAxisLabels">Indicates if points should be sorted by axis labels.</param>
931                 /// <param name="sortingOrder">Sorting pointSortOrder.</param>
932                 internal void AlignDataPointsByAxisLabel(bool sortAxisLabels, PointSortOrder sortingOrder)
933                 {
934                         // Find series which are attached to the same X axis in the same chart area
935                         foreach(ChartArea chartArea in this.ChartAreas)
936                         {
937
938                                 // Check if chart area is visible
939                                 if(chartArea.Visible)
940
941                                 {
942                                         // Create series list for primary and secondary X axis
943                                         ArrayList chartAreaSeriesPrimary = new ArrayList();
944                                         ArrayList chartAreaSeriesSecondary = new ArrayList();
945                                         foreach(Series series in this.Common.Chart.Series)
946                                         {
947                         // Check if series belongs to the chart area
948                         if (series.ChartArea == chartArea.Name)
949                                                 {
950                                                         if(series.XSubAxisName.Length == 0)
951                                                         {
952                                                                 if(series.XAxisType == AxisType.Primary)
953                                                                 {
954                                                                         chartAreaSeriesPrimary.Add(series);
955                                                                 }
956                                                                 else
957                                                                 {
958                                                                         chartAreaSeriesSecondary.Add(series);
959                                                                 }
960                                                         }
961                                                 }
962                                         }
963
964                                         // Align series
965                                         AlignDataPointsByAxisLabel(chartAreaSeriesPrimary, sortAxisLabels, sortingOrder);
966                                         AlignDataPointsByAxisLabel(chartAreaSeriesSecondary, sortAxisLabels, sortingOrder);
967                                 }
968                         }
969                 }
970
971                 /// <summary>
972                 /// Aligns data points using their axis labels.
973                 /// </summary>
974                 /// <param name="seriesList">List of series to align.</param>
975                 /// <param name="sortAxisLabels">Indicates if points should be sorted by axis labels.</param>
976                 /// <param name="sortingOrder">Sorting order.</param>
977                 internal void AlignDataPointsByAxisLabel(
978                         ArrayList seriesList, 
979                         bool sortAxisLabels, 
980                         PointSortOrder sortingOrder)
981                 {
982                         // List is empty
983                         if(seriesList.Count == 0)
984                         {
985                                 return;
986                         }
987
988                         // Collect information about all points in all series
989                         bool            indexedX = true;
990                         bool            uniqueAxisLabels = true;
991                         ArrayList       axisLabels = new ArrayList();
992                         foreach(Series series in seriesList)
993                         {
994                                 ArrayList       seriesAxisLabels = new ArrayList();
995                                 foreach(DataPoint point in series.Points)
996                                 {
997                                         // Check if series has indexed X values
998                                         if(!series.IsXValueIndexed && point.XValue != 0.0)
999                                         {
1000                                                 indexedX = false;
1001                                                 break;
1002                                         }
1003
1004                                         // Add axis label to the list and make sure it's non-empty and unique
1005                                         if(point.AxisLabel.Length == 0)
1006                                         {
1007                                                 uniqueAxisLabels = false;
1008                                                 break;
1009                                         }
1010                                         else if(seriesAxisLabels.Contains(point.AxisLabel))
1011                                         {
1012                                                 uniqueAxisLabels = false;
1013                                                 break;
1014                                         }
1015                                         else if(!axisLabels.Contains(point.AxisLabel))
1016                                         {
1017                                                 axisLabels.Add(point.AxisLabel);
1018                                         }
1019
1020                                         seriesAxisLabels.Add(point.AxisLabel);
1021                                 }
1022                         }
1023
1024                         // Sort axis labels
1025                         if(sortAxisLabels)
1026                         {
1027                                 axisLabels.Sort();
1028                                 if(sortingOrder == PointSortOrder.Descending)
1029                                 {
1030                                         axisLabels.Reverse();
1031                                 }
1032                         }
1033
1034                         // All series must be indexed
1035                         if(!indexedX)
1036                         {
1037                 throw (new InvalidOperationException(SR.ExceptionChartDataPointsAlignmentFaild));
1038                         }
1039
1040                         // AxisLabel can't be empty or duplicated
1041                         if(!uniqueAxisLabels)
1042                         {
1043                 throw (new InvalidOperationException(SR.ExceptionChartDataPointsAlignmentFaildAxisLabelsInvalid));
1044                         }
1045
1046                         // Assign unique X values for data points in all series with same axis LabelStyle
1047                         if(indexedX && uniqueAxisLabels)
1048                         {
1049                                 foreach(Series series in seriesList)
1050                                 {
1051                                         foreach(DataPoint point in series.Points)
1052                                         {
1053                                                 point.XValue = axisLabels.IndexOf(point.AxisLabel) + 1;
1054                                         }
1055
1056                                         // Sort points by X value
1057                                         series.Sort(PointSortOrder.Ascending, "X");
1058                                 }
1059
1060                                 // Make sure ther are no missing points
1061                                 foreach(Series series in seriesList)
1062                                 {
1063                                         series.IsXValueIndexed = true;
1064                                         for(int index = 0; index < axisLabels.Count; index++)
1065                                         {
1066                                                 if(index >= series.Points.Count ||
1067                                                         series.Points[index].XValue != index + 1)
1068                                                 {
1069                                                         DataPoint newPoint = new DataPoint(series);
1070                                                         newPoint.AxisLabel = (string)axisLabels[index];
1071                                                         newPoint.XValue = index + 1;
1072                                                         newPoint.YValues[0] = 0.0;
1073                                                         newPoint.IsEmpty = true;
1074                                                         series.Points.Insert(index, newPoint);
1075                                                 }
1076                                         }
1077                                 }
1078
1079                         }
1080
1081                 }
1082
1083         /// <summary>
1084         /// Data bind chart to the table. Series will be automatically added to the chart depending on
1085         /// the number of unique values in the seriesGroupByField column of the data source.
1086         /// Data source can be the Ole(SQL)DataReader, DataView, DataSet, DataTable or DataRow.
1087         /// </summary>
1088         /// <param name="dataSource">Data source.</param>
1089         /// <param name="seriesGroupByField">Name of the field used to group data into series.</param>
1090         /// <param name="xField">Name of the field for X values.</param>
1091         /// <param name="yFields">Comma separated name(s) of the field(s) for Y value(s).</param>
1092         /// <param name="otherFields">Other point properties binding rule in format: PointProperty=Field[{Format}] [,PointProperty=Field[{Format}]]. For example: "Tooltip=Price{C1},Url=WebSiteName".</param>
1093         /// <param name="sort">Indicates that series should be sorted by group field.</param>
1094         /// <param name="sortingOrder">Series sorting order by group field.</param>
1095                 internal void DataBindCrossTab(
1096                         IEnumerable dataSource, 
1097                         string seriesGroupByField, 
1098                         string xField, 
1099                         string yFields, 
1100                         string otherFields,
1101                         bool sort,
1102                         PointSortOrder sortingOrder)
1103                 {
1104             // Check arguments
1105             if (dataSource == null)
1106                 throw (new ArgumentNullException("dataSource", SR.ExceptionDataPointInsertionNoDataSource));
1107
1108             if (dataSource is string)
1109                 throw (new ArgumentException(SR.ExceptionDataBindSeriesToString, "dataSource"));
1110
1111             if (String.IsNullOrEmpty(yFields))
1112                 throw (new ArgumentException(SR.ExceptionChartDataPointsInsertionFailedYValuesEmpty, "yFields"));
1113
1114             if (String.IsNullOrEmpty(seriesGroupByField))
1115                 throw (new ArgumentException(SR.ExceptionDataBindSeriesGroupByParameterIsEmpty, "seriesGroupByField"));
1116
1117             
1118             // List of series and group by field values
1119                         ArrayList seriesList = new ArrayList();
1120                         ArrayList groupByValueList = new ArrayList();
1121
1122                         // Convert comma separated Y values field names string to array of names
1123                         string[] yFieldNames = null;
1124                         if(yFields != null)
1125                         {
1126                                 yFieldNames = yFields.Replace(",,", "\n").Split(',');
1127                                 for(int index = 0; index < yFieldNames.Length; index++)
1128                                 {
1129                                         yFieldNames[index] = yFieldNames[index].Replace("\n", ",");
1130                                 }
1131                         }
1132
1133                         // Convert other fields/properties names to two arrays of names
1134                         string[] otherAttributeNames = null;
1135                         string[] otherFieldNames = null;
1136                         string[] otherValueFormat = null;
1137                         DataPointCollection.ParsePointFieldsParameter(
1138                                 otherFields,
1139                                 ref otherAttributeNames,
1140                                 ref otherFieldNames,
1141                                 ref otherValueFormat);
1142                         
1143
1144                         // Get and reset enumerator
1145                         IEnumerator     enumerator = DataPointCollection.GetDataSourceEnumerator(dataSource);
1146                         if(enumerator.GetType() != typeof(System.Data.Common.DbEnumerator))
1147                         {
1148                 try
1149                 {
1150                     enumerator.Reset();
1151                 }
1152                 // Some enumerators may not support Resetting 
1153                 catch (NotSupportedException)
1154                 {
1155                 }
1156                 catch (NotImplementedException)
1157                 {
1158                 }
1159                 catch (InvalidOperationException)
1160                 {
1161                 }
1162
1163                         }
1164
1165                         // Add data points
1166                         bool            valueExsist = true;
1167                         object[]        yValuesObj = new object[yFieldNames.Length];
1168                         object          xValueObj = null;
1169                         bool            autoDetectType = true;
1170
1171                         do 
1172                         {
1173                                 // Move to the next objects in the enumerations
1174                                 if(valueExsist)
1175                                 {
1176                                         valueExsist = enumerator.MoveNext();
1177                                 }
1178
1179                                 // Create and initialize data point
1180                                 if(valueExsist)
1181                                 {
1182                                         // Get value of the group by field
1183                                         object groupObj = DataPointCollection.ConvertEnumerationItem(
1184                                                 enumerator.Current, 
1185                                                 seriesGroupByField);
1186
1187                                         // Check series group by field and create new series if required
1188                                         Series series = null;
1189                                         int seriesIndex = groupByValueList.IndexOf(groupObj);
1190                                         if(seriesIndex >= 0)
1191                                         {
1192                                                 // Select existing series from the list
1193                                                 series = (Series)seriesList[seriesIndex];
1194                                         }
1195                                         else
1196                                         {
1197                                                 // Create new series
1198                                                 series = new Series();
1199                                                 series.YValuesPerPoint = yFieldNames.GetLength(0);
1200
1201                                                 // If not the first series in the list copy some properties
1202                                                 if(seriesList.Count > 0)
1203                                                 {
1204                                                         series.XValueType = ((Series)seriesList[0]).XValueType;
1205                                                         series.autoXValueType = ((Series)seriesList[0]).autoXValueType;
1206                                                         series.YValueType = ((Series)seriesList[0]).YValueType;
1207                                                         series.autoYValueType = ((Series)seriesList[0]).autoYValueType;
1208                                                 }
1209
1210                                                 // Try to set series name based on grouping vlaue
1211                         string groupObjStr = groupObj as string;
1212                                                 if(groupObjStr != null)
1213                                                 {
1214                             series.Name = groupObjStr;
1215                                                 }
1216                                                 else
1217                                                 {
1218                                                         series.Name = seriesGroupByField + " - " + groupObj.ToString();
1219                                                 }
1220                                                 
1221                                         
1222                                                 // Add series and group value into the lists
1223                                                 groupByValueList.Add(groupObj);
1224                                                 seriesList.Add(series);
1225                                         }
1226
1227                                         
1228                                         // Auto detect valu(s) type
1229                                         if(autoDetectType)
1230                                         {
1231                                                 autoDetectType = false;
1232                                                 DataPointCollection.AutoDetectValuesType(series, enumerator, xField, enumerator, yFieldNames[0]);
1233                                         }
1234
1235                                         // Create new data point
1236                                         DataPoint       newDataPoint = new DataPoint(series);
1237                                         bool            emptyValues = false;
1238
1239                                         // Set X to the value provided
1240                                         if(xField.Length > 0)
1241                                         {
1242                                                 xValueObj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, xField);
1243                                                 if( DataPointCollection.IsEmptyValue(xValueObj) )
1244                                                 {
1245                                                         emptyValues = true;
1246                                                         xValueObj = 0.0;
1247                                                 }
1248                                         }
1249
1250                                         // Set Y values
1251                                         if(yFieldNames.Length == 0)
1252                                         {
1253                                                 yValuesObj[0] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, null);
1254                                                 if( DataPointCollection.IsEmptyValue(yValuesObj[0]) )
1255                                                 {
1256                                                         emptyValues = true;
1257                                                         yValuesObj[0] = 0.0;
1258                                                 }
1259                                         }
1260                                         else
1261                                         {
1262                                                 for(int i = 0; i < yFieldNames.Length; i++)
1263                                                 {
1264                                                         yValuesObj[i] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, yFieldNames[i]);
1265                                                         if( DataPointCollection.IsEmptyValue(yValuesObj[i] ) )
1266                                                         {
1267                                                                 emptyValues = true;
1268                                                                 yValuesObj[i] = 0.0;
1269                                                         }
1270                                                 }
1271                                         }
1272
1273                                         // Set other values
1274                                         if(otherAttributeNames != null && 
1275                                                 otherAttributeNames.Length > 0)
1276                                         {
1277                                                 for(int i = 0; i < otherFieldNames.Length; i++)
1278                                                 {
1279                                                         // Get object by field name
1280                                                         object obj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, otherFieldNames[i]);
1281                                                         if( !DataPointCollection.IsEmptyValue( obj ) )
1282                                                         {
1283                                                                 newDataPoint.SetPointCustomProperty(
1284                                                                         obj, 
1285                                                                         otherAttributeNames[i], 
1286                                                                         otherValueFormat[i]);
1287                                                         }
1288                                                 }
1289                                         }
1290
1291                                         // IsEmpty value was detected
1292                                         if(emptyValues)
1293                                         {
1294                                                 if(xValueObj != null)
1295                                                 {
1296                                                         newDataPoint.SetValueXY(xValueObj, yValuesObj);
1297                                                 }
1298                                                 else
1299                                                 {
1300                                                         newDataPoint.SetValueXY(0, yValuesObj);
1301                                                 }
1302                                                 DataPointCollection.DataPointInit(series, ref newDataPoint);
1303                                                 newDataPoint.IsEmpty = true;
1304                                                 series.Points.Add(newDataPoint);
1305                                         }
1306                                         else
1307                                         {
1308                                                 if(xValueObj != null)
1309                                                 {
1310                                                         newDataPoint.SetValueXY(xValueObj, yValuesObj);
1311                                                 }
1312                                                 else
1313                                                 {
1314                                                         newDataPoint.SetValueXY(0, yValuesObj);
1315                                                 }
1316                         DataPointCollection.DataPointInit(series, ref newDataPoint);
1317                                                 series.Points.Add(newDataPoint);
1318                                         }
1319                                 }
1320
1321                         } while(valueExsist);
1322
1323                         // Sort series usig values of group by field
1324                         if(sort)
1325                         {
1326                                 // Duplicate current list
1327                                 ArrayList oldList = (ArrayList)groupByValueList.Clone();
1328
1329                                 // Sort list 
1330                                 groupByValueList.Sort();
1331                                 if(sortingOrder == PointSortOrder.Descending)
1332                                 {
1333                                         groupByValueList.Reverse();
1334                                 }
1335
1336                                 // Change order of series in collection
1337                                 ArrayList sortedSeriesList = new ArrayList();
1338                                 foreach(object obj in groupByValueList)
1339                                 {
1340                                         sortedSeriesList.Add(seriesList[oldList.IndexOf(obj)]);
1341                                 }
1342                                 seriesList = sortedSeriesList;
1343                         }
1344
1345                         // Add all series from the list into the series collection
1346                         foreach(Series series in seriesList)
1347                         {
1348                                 this.Common.Chart.Series.Add(series);
1349                         }
1350                 }
1351
1352                 /// <summary>
1353                 /// Automatically creates and binds series to specified data table. 
1354                 /// Each column of the table becomes a Y value in a separate series.
1355                 /// Series X value field may also be provided. 
1356                 /// </summary>
1357                 /// <param name="dataSource">Data source.</param>
1358                 /// <param name="xField">Name of the field for series X values.</param>
1359         internal void DataBindTable(
1360             IEnumerable dataSource,
1361             string xField)
1362         {
1363             // Check arguments
1364             if (dataSource == null)
1365                 throw new ArgumentNullException("dataSource");
1366
1367             // Get list of member names from the data source
1368             ArrayList dataSourceFields = GetDataSourceMemberNames(dataSource, true);
1369
1370             // Remove X value field if it's there
1371             if (xField != null && xField.Length > 0)
1372             {
1373                 int index = -1;
1374                 for (int i = 0; i < dataSourceFields.Count; i++)
1375                 {
1376                     if ( String.Equals((string)dataSourceFields[i], xField, StringComparison.OrdinalIgnoreCase ) )
1377                     {
1378                         index = i;
1379                         break;
1380                     }
1381                 }
1382                 if (index >= 0)
1383                 {
1384                     dataSourceFields.RemoveAt(index);
1385                 }
1386                 else
1387                 {
1388                     // Check if field name passed as index
1389                     bool parseSucceed = int.TryParse(xField, NumberStyles.Any, CultureInfo.InvariantCulture, out index);
1390                     if (parseSucceed && index >= 0 && index < dataSourceFields.Count)
1391                     {
1392                         dataSourceFields.RemoveAt(index);
1393                     }
1394                 }
1395             }
1396
1397             // Get number of series
1398             int seriesNumber = dataSourceFields.Count;
1399             if (seriesNumber > 0)
1400             {
1401                 // Create as many series as fields in the data source
1402                 ArrayList seriesList = new ArrayList();
1403                 int index = 0;
1404                 foreach (string fieldName in dataSourceFields)
1405                 {
1406                     Series series = new Series(fieldName);
1407
1408                     // Set binding properties
1409                     series.YValueMembers = fieldName;
1410                     series.XValueMember = xField;
1411
1412                     // Add to list
1413                     seriesList.Add(series);
1414                     ++index;
1415                 }
1416
1417
1418                 // Data bind series
1419                 this.DataBind(dataSource, seriesList);
1420
1421                 // Add all series from the list into the series collection
1422                 foreach (Series series in seriesList)
1423                 {
1424                     // Clear binding properties
1425                     series.YValueMembers = String.Empty;
1426                     series.XValueMember = String.Empty;
1427
1428                     // Add series into the list
1429                     this.Common.Chart.Series.Add(series);
1430                 }
1431             }
1432         }
1433
1434                 #endregion // Data Binding
1435
1436         #endregion
1437
1438     }
1439         
1440         /// <summary>
1441     /// ChartPicture class represents chart content like legends, titles, 
1442     /// chart areas and series. It provides methods for positioning and 
1443     /// drawing all chart elements.
1444         /// </summary>
1445     internal class ChartPicture : ChartElement, IServiceProvider
1446         {
1447         #region Fields
1448
1449         /// <summary>
1450                         /// Indicates that chart exceptions should be suppressed.
1451                         /// </summary>
1452                         private bool                                    _suppressExceptions = false;
1453
1454                         // Chart Graphic object
1455             internal ChartGraphics ChartGraph { get; set; }
1456
1457                         // Private data members, which store properties values
1458                         private GradientStyle                   _backGradientStyle = GradientStyle.None;
1459                         private Color                                   _backSecondaryColor = Color.Empty;
1460                         private Color                                   _backColor = Color.White;
1461                         private string                                  _backImage = "";
1462                         private ChartImageWrapMode              _backImageWrapMode = ChartImageWrapMode.Tile;
1463                         private Color                                   _backImageTransparentColor = Color.Empty;
1464                         private ChartImageAlignmentStyle                        _backImageAlign = ChartImageAlignmentStyle.TopLeft;
1465                         private Color                                   _borderColor = Color.White;
1466                         private int                                             _borderWidth = 1;
1467                         private ChartDashStyle                  _borderDashStyle = ChartDashStyle.NotSet;
1468                         private ChartHatchStyle                 _backHatchStyle = ChartHatchStyle.None;
1469                         private AntiAliasingStyles              _antiAliasing = AntiAliasingStyles.All;
1470                         private TextAntiAliasingQuality _textAntiAliasingQuality = TextAntiAliasingQuality.High;
1471                         private bool                                    _isSoftShadows = true;
1472                         private int                                             _width = 300;
1473                         private int                                             _height = 300;
1474                         private DataManipulator                 _dataManipulator = new DataManipulator();
1475                         internal HotRegionsList                 hotRegionsList = null;
1476                         private BorderSkin                  _borderSkin = null;
1477 #if !Microsoft_CONTROL
1478                         private bool                                    _isMapEnabled = true;
1479                         private MapAreasCollection              _mapAreas = null;
1480 #endif
1481             // Chart areas collection
1482             private ChartAreaCollection     _chartAreas = null;
1483
1484                         // Chart legend collection
1485                         private LegendCollection                _legends = null;
1486
1487                         // Chart title collection
1488                         private TitleCollection                 _titles = null;
1489
1490                     // Chart annotation collection
1491                         private AnnotationCollection    _annotations = null;
1492
1493                         // Annotation smart labels class
1494                         internal AnnotationSmartLabel   annotationSmartLabel = new AnnotationSmartLabel();
1495
1496                         // Chart picture events
1497             internal event EventHandler<ChartPaintEventArgs> BeforePaint;
1498             internal event EventHandler<ChartPaintEventArgs> AfterPaint;
1499
1500                         // Chart title position rectangle
1501                         private RectangleF                              _titlePosition = RectangleF.Empty;
1502
1503                         // Element spacing size
1504                         internal const float                    elementSpacing = 3F;
1505
1506                         // Maximum size of the font in percentage
1507                         internal const float                    maxTitleSize = 15F;
1508
1509                         // Printing indicator
1510                         internal bool                                   isPrinting = false;
1511
1512                         // Indicates chart selection mode
1513                         internal bool                                   isSelectionMode = false;
1514
1515             private FontCache               _fontCache = new FontCache();
1516             
1517                         // Position of the chart 3D border
1518                         private RectangleF                              _chartBorderPosition = RectangleF.Empty;
1519
1520 #if Microsoft_CONTROL
1521
1522                         // Saving As Image indicator
1523                         internal bool                                   isSavingAsImage = false;
1524
1525             // Indicates that chart background is restored from the double buffer
1526                         // prior to drawing top level objects like annotations, cursors and selection.
1527                         internal bool                                   backgroundRestored = false;
1528
1529             // Buffered image of non-top level chart elements
1530                     internal            Bitmap                          nonTopLevelChartBuffer = null;
1531
1532 #endif // Microsoft_CONTROL
1533
1534         #endregion
1535
1536             #region Constructors
1537
1538             /// <summary>
1539                 /// Constructor.
1540                 /// </summary>
1541                 /// <param name="container">Service container</param>
1542                 public ChartPicture(IServiceContainer container) 
1543                 {
1544                         if(container == null)
1545                         {
1546                                 throw(new ArgumentNullException(SR.ExceptionInvalidServiceContainer));
1547                         }
1548
1549                         // Create and set Common Elements
1550             Common = new CommonElements(container);
1551                         ChartGraph= new ChartGraphics(Common);
1552                         hotRegionsList = new HotRegionsList(Common);
1553
1554                         // Create border properties class
1555                         _borderSkin = new BorderSkin(this);
1556
1557                         // Create a collection of chart areas
1558                         _chartAreas = new ChartAreaCollection(this);
1559
1560                         // Create a collection of legends
1561                         _legends = new LegendCollection(this);
1562
1563                         // Create a collection of titles
1564                         _titles = new TitleCollection(this);
1565
1566                         // Create a collection of annotations
1567                         _annotations = new AnnotationCollection(this);
1568
1569                         // Set Common elements for data manipulator
1570                         _dataManipulator.Common = Common;
1571
1572 #if !Microsoft_CONTROL
1573                         // Create map areas collection
1574                         _mapAreas = new MapAreasCollection();
1575 #endif
1576         }
1577
1578                 /// <summary>
1579                 /// Returns Chart service object
1580                 /// </summary>
1581                 /// <param name="serviceType">Service AxisName</param>
1582                 /// <returns>Chart picture</returns>
1583                 [EditorBrowsableAttribute(EditorBrowsableState.Never)]
1584                 object IServiceProvider.GetService(Type serviceType)
1585                 {
1586                         if(serviceType == typeof(ChartPicture))
1587                         {
1588                                 return this;
1589                         }
1590                         throw (new ArgumentException( SR.ExceptionChartPictureUnsupportedType( serviceType.ToString() ) ) );
1591                 }
1592
1593                 #endregion
1594
1595                 #region Painting and selection methods
1596
1597         /// <summary>
1598         /// Performs empty painting.
1599         /// </summary>
1600         internal void PaintOffScreen()
1601         {
1602             // Check chart size
1603             // NOTE: Fixes issue #4733
1604             if (this.Width <= 0 || this.Height <= 0)
1605             {
1606                 return;
1607             }
1608             
1609             // Set process Mode to hot regions
1610             this.Common.HotRegionsList.ProcessChartMode |= ProcessMode.HotRegions;
1611 #if Microsoft_CONTROL
1612             this.Common.HotRegionsList.hitTestCalled = true;
1613 #endif // Microsoft_CONTROL
1614
1615             // Enable selection mode
1616             this.isSelectionMode = true;
1617
1618             // Hot Region list does not exist. Create the list.
1619             //this.common.HotRegionsList.List = new ArrayList();
1620             this.Common.HotRegionsList.Clear();
1621
1622             // Create a new bitmap
1623             Bitmap image = new Bitmap(Math.Max(1,Width), Math.Max(1,Height));
1624
1625             // Creates a new Graphics object from the 
1626             // specified Image object.
1627             Graphics offScreen = Graphics.FromImage(image);
1628
1629             // Connect Graphics object with Chart Graphics object
1630             ChartGraph.Graphics = offScreen;
1631
1632             // Remember the previous dirty flag
1633 #if Microsoft_CONTROL                   
1634                         bool oldDirtyFlag = this.Common.Chart.dirtyFlag;
1635 #endif //Microsoft_CONTROL
1636
1637
1638             Paint(ChartGraph.Graphics, false);
1639
1640             image.Dispose();
1641
1642             // Restore the previous dirty flag
1643 #if Microsoft_CONTROL                   
1644                         this.Common.Chart.dirtyFlag = oldDirtyFlag;
1645 #endif //Microsoft_CONTROL
1646
1647             // Disable selection mode
1648             this.isSelectionMode = false;
1649
1650                         // Set process Mode to hot regions
1651                         this.Common.HotRegionsList.ProcessChartMode |= ProcessMode.HotRegions;
1652
1653         }
1654
1655                 /// <summary>
1656                 /// Gets text rendering quality.
1657                 /// </summary>
1658                 /// <returns>Text rendering quality.</returns>
1659                 internal TextRenderingHint GetTextRenderingHint()
1660                 {
1661                         TextRenderingHint result = TextRenderingHint.SingleBitPerPixelGridFit;
1662                         if( (this.AntiAliasing & AntiAliasingStyles.Text) == AntiAliasingStyles.Text )
1663                         {
1664                                 result = TextRenderingHint.ClearTypeGridFit;
1665                                 if(this.TextAntiAliasingQuality == TextAntiAliasingQuality.Normal)
1666                                 {
1667                                         result = TextRenderingHint.AntiAlias;
1668                                 }
1669                                 else if(this.TextAntiAliasingQuality == TextAntiAliasingQuality.SystemDefault)
1670                                 {
1671                                         result = TextRenderingHint.SystemDefault;
1672                                 }
1673                         }
1674                         else
1675                         {
1676                                 result = TextRenderingHint.SingleBitPerPixelGridFit;
1677                         }
1678
1679                         return result;
1680                 }
1681
1682         internal bool GetBorderSkinVisibility()
1683         {
1684             return _borderSkin.SkinStyle != BorderSkinStyle.None && this.Width > 20 && this.Height > 20;
1685         }
1686
1687         /// <summary>
1688         /// This function paints a chart.
1689         /// </summary>
1690         /// <param name="graph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param>
1691         /// <param name="paintTopLevelElementOnly">Indicates that only chart top level elements like cursors, selection or annotation objects must be redrawn.</param>
1692         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "3#svg")]
1693         internal void Paint( 
1694                         Graphics graph, 
1695                         bool paintTopLevelElementOnly )
1696                 {
1697
1698 #if Microsoft_CONTROL
1699
1700                         // Reset restored and saved backgound flags
1701                         this.backgroundRestored = false;
1702
1703 #endif // Microsoft_CONTROL
1704
1705                         // Reset Annotation Smart Labels 
1706                         this.annotationSmartLabel.Reset();
1707
1708             // Do not draw the control if size is less than 5 pixel
1709             if (this.Width < 5 || this.Height < 5)
1710             {
1711                 return;
1712             }
1713
1714 #if Microsoft_CONTROL
1715
1716                         bool    resetHotRegionList = false;
1717             
1718                         if( 
1719                 this.Common.HotRegionsList.hitTestCalled 
1720                 || IsToolTipsEnabled() 
1721                 )
1722                         {
1723                                 Common.HotRegionsList.ProcessChartMode = ProcessMode.HotRegions | ProcessMode.Paint;
1724
1725                                 this.Common.HotRegionsList.hitTestCalled = false;
1726
1727                                 // Clear list of hot regions 
1728                                 if(paintTopLevelElementOnly)
1729                                 {
1730                                         // If repainting only top level elements (annotations) - 
1731                                         // clear top level objects hot regions only
1732                                         for(int index = 0; index < this.Common.HotRegionsList.List.Count; index++)
1733                                         {
1734                                                 HotRegion region = (HotRegion)this.Common.HotRegionsList.List[index];
1735                                                 if(region.Type == ChartElementType.Annotation)
1736                                                 {
1737                                                         this.Common.HotRegionsList.List.RemoveAt(index);
1738                                                         --index;
1739                                                 }
1740                     }
1741                                 }
1742                                 else
1743                                 {
1744                                         // If repainting whole chart - clear all hot regions
1745                                         resetHotRegionList = true;
1746                                 }
1747                         }
1748                         else
1749                         {
1750                                 Common.HotRegionsList.ProcessChartMode = ProcessMode.Paint;
1751
1752                                 // If repainting whole chart - clear all hot regions
1753                                 resetHotRegionList = true;
1754                         }
1755
1756                         // Reset hot region list
1757                         if(resetHotRegionList)
1758                         {
1759                                 this.Common.HotRegionsList.Clear();
1760                         }
1761                         
1762 #else
1763                         if( this.IsMapEnabled )
1764                         {
1765                                 Common.HotRegionsList.ProcessChartMode |= ProcessMode.ImageMaps | ProcessMode.Paint;
1766                                 
1767                                 // Clear any existing non-custom image map areas
1768                                 for(int index = 0; index < this.MapAreas.Count; index++)
1769                                 {
1770                                         MapArea mapArea = this.MapAreas[index];
1771                                         if(!mapArea.IsCustom)
1772                                         {
1773                                                 this.MapAreas.RemoveAt(index);
1774                                                 --index;
1775                                         }
1776                                 }
1777                         }
1778
1779
1780 #endif  //#if Microsoft_CONTROL
1781
1782                         // Check if control was data bound
1783                         ChartImage chartImage = this as ChartImage;
1784                         if(chartImage != null && !chartImage.boundToDataSource)
1785                         {
1786                                 if(this.Common != null && this.Common.Chart != null && !this.Common.Chart.IsDesignMode())
1787                                 {
1788                                         this.Common.Chart.DataBind();
1789                                 }
1790                         }
1791
1792             // Connect Graphics object with Chart Graphics object
1793                         ChartGraph.Graphics = graph;
1794
1795                         Common.graph = ChartGraph;
1796
1797                         // Set anti alias mode
1798                         ChartGraph.AntiAliasing = _antiAliasing;
1799                         ChartGraph.softShadows = _isSoftShadows;
1800                         ChartGraph.TextRenderingHint = GetTextRenderingHint();
1801
1802                         try
1803                         {
1804                                 // Check if only chart area cursors and annotations must be redrawn
1805                                 if(!paintTopLevelElementOnly)
1806                                 {
1807                                         // Fire Before Paint event
1808                                         OnBeforePaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
1809
1810                                         // Flag indicates that resize method should be called 
1811                                         // after adjusting the intervals in 3D charts
1812                                         bool    resizeAfterIntervalAdjusting = false;
1813
1814                                         // RecalculateAxesScale paint chart areas
1815                                         foreach (ChartArea area in _chartAreas )
1816                                         {
1817
1818                                                 // Check if area is visible
1819                                                 if(area.Visible)
1820
1821                                                 {
1822                                                         area.Set3DAnglesAndReverseMode();
1823                                                         area.SetTempValues();
1824                                                         area.ReCalcInternal();
1825
1826                                                         // Resize should be called the second time
1827                                                         if( area.Area3DStyle.Enable3D && !area.chartAreaIsCurcular)
1828                                                         {
1829                                                                 resizeAfterIntervalAdjusting = true;
1830                                                         }
1831                                                 }
1832                                         }
1833
1834                                         // Call Customize event
1835                     this.Common.Chart.CallOnCustomize();
1836
1837                                         // Resize picture
1838                                         Resize(ChartGraph, resizeAfterIntervalAdjusting);
1839
1840                                 
1841                                         // This code is introduce because labels has to 
1842                                         // be changed when scene is rotated.
1843                     bool intervalReCalculated = false;
1844                                         foreach (ChartArea area in _chartAreas )
1845                                         {
1846                                                 if( area.Area3DStyle.Enable3D  && 
1847                                                         !area.chartAreaIsCurcular
1848
1849                                                         && area.Visible
1850
1851                                                         )
1852
1853                                                 {
1854                                                         // Make correction for interval in 3D space
1855                             intervalReCalculated = true;
1856                                                         area.Estimate3DInterval( ChartGraph );
1857                                                         area.ReCalcInternal();
1858                                                 }
1859                                         }
1860
1861                                         // Resize chart areas after updating 3D interval
1862                                         if(resizeAfterIntervalAdjusting)
1863                                         {
1864                         // NOTE: Fixes issue #6808.
1865                         // In 3D chart area interval will be changed to compenstae for the axis rotation angle.
1866                         // This will cause all standard labels to be changed. We need to call the customize event 
1867                         // the second time to give user a chance to modify those labels.
1868                         if (intervalReCalculated)
1869                         {
1870                             // Call Customize event
1871                             this.Common.Chart.CallOnCustomize();
1872                         }
1873
1874                         // Resize chart elements
1875                         Resize(ChartGraph);
1876                                         }
1877
1878
1879                                         //***********************************************************************
1880                                         //** Draw chart 3D border
1881                                         //***********************************************************************
1882                     if (GetBorderSkinVisibility())
1883                                         {
1884                                                 // Fill rectangle with page color
1885                                                 ChartGraph.FillRectangleAbs( new RectangleF( 0, 0, Width-1 , Height-1 ), 
1886                                                         _borderSkin.PageColor, 
1887                                                         ChartHatchStyle.None, 
1888                                                         "", 
1889                                                         ChartImageWrapMode.Tile,
1890                                                         Color.Empty,
1891                                                         ChartImageAlignmentStyle.Center,
1892                                                         GradientStyle.None, 
1893                                                         Color.Empty, 
1894                                                         _borderSkin.PageColor, 
1895                                                         1, 
1896                                                         ChartDashStyle.Solid,
1897                                                         PenAlignment.Inset );
1898
1899                                                 // Draw 3D border
1900                                                 ChartGraph.Draw3DBorderAbs(
1901                                                         _borderSkin,
1902                                                         this._chartBorderPosition, 
1903                                                         BackColor, 
1904                                                         BackHatchStyle, 
1905                                                         BackImage, 
1906                                                         BackImageWrapMode,
1907                                                         BackImageTransparentColor,
1908                                                         BackImageAlignment,
1909                                                         BackGradientStyle, 
1910                                                         BackSecondaryColor, 
1911                                                         BorderColor, 
1912                                                         BorderWidth, 
1913                                                         BorderDashStyle);
1914                                         }
1915
1916                                                 // Paint Background
1917                                         else
1918                                         {
1919                                                 ChartGraph.FillRectangleAbs( new RectangleF( 0, 0, Width-1 , Height-1 ), 
1920                                                         BackColor, 
1921                                                         BackHatchStyle, 
1922                                                         BackImage, 
1923                                                         BackImageWrapMode,
1924                                                         BackImageTransparentColor,
1925                                                         BackImageAlignment,
1926                                                         BackGradientStyle, 
1927                                                         BackSecondaryColor, 
1928                                                         BorderColor, 
1929                                                         BorderWidth, 
1930                                                         BorderDashStyle,
1931                                                         PenAlignment.Inset );
1932                                         }
1933
1934                                         // Call BackPaint event
1935                     this.Chart.CallOnPrePaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
1936
1937                                         // Call paint function for each chart area.
1938                                         foreach (ChartArea area in _chartAreas )
1939                                         {
1940
1941                                                 // Check if area is visible
1942                                                 if(area.Visible)
1943
1944                                                 {
1945                                                         area.Paint(ChartGraph);
1946                                                 }
1947                                         }
1948
1949                                         // This code is introduced because of GetPointsInterval method, 
1950                                         // which is very time consuming. There is no reason to calculate 
1951                                         // interval after painting.
1952                                         foreach (ChartArea area in _chartAreas )
1953                                         {
1954                                                 // Reset interval data
1955                                                 area.intervalData = double.NaN;
1956                                         }
1957
1958                                         // Draw Legends
1959                                         foreach(Legend legendCurrent in this.Legends)
1960                                         {
1961                                                 legendCurrent.Paint(ChartGraph);
1962                                         }
1963
1964                                         // Draw chart titles from the collection
1965                                         foreach(Title titleCurrent in this.Titles)
1966                                         {
1967                                                 titleCurrent.Paint(ChartGraph);
1968                                         }
1969
1970                                         // Call Paint event
1971                     this.Chart.CallOnPostPaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
1972                                 }
1973
1974                                 // Draw annotation objects 
1975                                 this.Annotations.Paint(ChartGraph, paintTopLevelElementOnly);
1976
1977                                 // Draw chart areas cursors in all areas.
1978                                 // Only if not in selection 
1979                                 if(!this.isSelectionMode)
1980                                 {
1981                                         foreach (ChartArea area in _chartAreas )
1982                                         {
1983
1984                                                 // Check if area is visible
1985                                                 if(area.Visible)
1986
1987                                                 {
1988                                                         area.PaintCursors(ChartGraph, paintTopLevelElementOnly);
1989                                                 }
1990                                         }
1991                                 }
1992
1993                                 // Return default values
1994                                 foreach (ChartArea area in _chartAreas )
1995                                 {
1996
1997                                         // Check if area is visible
1998                                         if(area.Visible)
1999
2000                                         {
2001                                                 area.Restore3DAnglesAndReverseMode();
2002                                                 area.GetTempValues();
2003                                         }
2004                                 }
2005             }
2006                         catch(System.Exception)
2007                         {
2008                                 throw;
2009                         }
2010                         finally
2011                         {
2012                                 // Fire After Paint event
2013                                 OnAfterPaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100)));
2014
2015                                 // Restore temp values for each chart area
2016                                 foreach (ChartArea area in _chartAreas )
2017                                 {
2018
2019                                         // Check if area is visible
2020                                         if(area.Visible)
2021
2022                                         {
2023                                                 area.Restore3DAnglesAndReverseMode();
2024                                                 area.GetTempValues();
2025                                         }
2026                                 }
2027
2028 #if !Microsoft_CONTROL
2029                 if (this.Chart.IsDesignMode())
2030                 {
2031                     this.Chart.MapAreas.RemoveNonCustom();
2032                 }
2033 #endif //!Microsoft_CONTROL
2034             }
2035                 }
2036
2037                 /// <summary>
2038                 /// Invoke before paint delegates.
2039                 /// </summary>
2040                 /// <param name="e">Event arguments.</param>
2041                 protected virtual void OnBeforePaint(ChartPaintEventArgs e) 
2042                 {
2043                         if (BeforePaint != null) 
2044                         {
2045                                 //Invokes the delegates.
2046                                 BeforePaint(this, e); 
2047                         }
2048                 }
2049
2050                 /// <summary>
2051                 /// Invoke after paint delegates.
2052                 /// </summary>
2053                 /// <param name="e">Event arguments.</param>
2054                 protected virtual void OnAfterPaint(ChartPaintEventArgs e) 
2055                 {
2056                         if (AfterPaint != null) 
2057                         {
2058                                 //Invokes the delegates.
2059                                 AfterPaint(this, e); 
2060                         }
2061                 }
2062
2063         internal override void Invalidate()
2064         {
2065             base.Invalidate();
2066
2067 #if Microsoft_CONTROL
2068             if (Chart!=null)
2069                 Chart.Invalidate();
2070 #endif
2071         }
2072                 #endregion
2073
2074                 #region Resizing methods
2075
2076                 /// <summary>
2077                 /// Resize the chart picture.
2078                 /// </summary>
2079                 /// <param name="chartGraph">Chart graphics.</param>
2080                 public void Resize(ChartGraphics chartGraph)
2081                 {
2082                         Resize(chartGraph, false);
2083                 }
2084
2085                 /// <summary>
2086                 /// Resize the chart picture.
2087                 /// </summary>
2088                 /// <param name="chartGraph">Chart graphics.</param>
2089                 /// <param name="calcAreaPositionOnly">Indicates that only chart area position is calculated.</param>
2090                 public void Resize(ChartGraphics chartGraph, bool calcAreaPositionOnly)
2091                 {
2092                         // Set the chart size for Common elements
2093                         Common.Width = _width;
2094                         Common.Height = _height;
2095
2096                         // Set the chart size for Chart graphics
2097                         chartGraph.SetPictureSize( _width, _height );
2098
2099                         // Initialize chart area(s) rectangle
2100                         RectangleF      chartAreasRectangle = new RectangleF(0, 0, _width - 1, _height - 1);
2101                         chartAreasRectangle = chartGraph.GetRelativeRectangle(chartAreasRectangle);
2102
2103                         //******************************************************
2104                         //** Get the 3D border interface
2105                         //******************************************************
2106                         _titlePosition = RectangleF.Empty;
2107                         IBorderType     border3D = null;
2108                         bool    titleInBorder = false;
2109
2110                         if(_borderSkin.SkinStyle != BorderSkinStyle.None)
2111                         {
2112                                 // Set border size
2113                                 this._chartBorderPosition = chartGraph.GetAbsoluteRectangle(chartAreasRectangle);
2114
2115                                 // Get border interface 
2116                                 border3D = Common.BorderTypeRegistry.GetBorderType(_borderSkin.SkinStyle.ToString());
2117                                 if(border3D != null)
2118                                 {
2119                     border3D.Resolution = chartGraph.Graphics.DpiX;
2120                                         // Check if title should be displayed in the border
2121                                         titleInBorder = border3D.GetTitlePositionInBorder() != RectangleF.Empty;
2122                                         _titlePosition = chartGraph.GetRelativeRectangle(border3D.GetTitlePositionInBorder());
2123                                         _titlePosition.Width = chartAreasRectangle.Width - _titlePosition.Width;
2124
2125                                         // Adjust are position to the border size
2126                                         border3D.AdjustAreasPosition(chartGraph, ref chartAreasRectangle);
2127                                 }
2128                         }
2129
2130                         //******************************************************
2131                         //** Calculate position of all titles in the collection
2132                         //******************************************************
2133                         RectangleF      frameTitlePosition  = RectangleF.Empty;
2134                         if(titleInBorder)
2135                         {
2136                                 frameTitlePosition = new RectangleF(_titlePosition.Location, _titlePosition.Size);
2137                         }
2138                         foreach(Title title in this.Titles)
2139                         {
2140                 if (title.DockedToChartArea == Constants.NotSetValue &&
2141                                         title.Position.Auto &&
2142                                         title.Visible)
2143                                 {
2144                                         title.CalcTitlePosition(chartGraph, ref chartAreasRectangle, ref frameTitlePosition, elementSpacing);
2145                                 }
2146                         }
2147
2148                         //******************************************************
2149                         //** Calculate position of all legends in the collection
2150                         //******************************************************
2151                         this.Legends.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing);
2152
2153                         //******************************************************
2154                         //** Calculate position of the chart area(s)
2155                         //******************************************************
2156                         chartAreasRectangle.Width -= elementSpacing;
2157                         chartAreasRectangle.Height -= elementSpacing;
2158                         RectangleF areaPosition = new RectangleF();
2159
2160
2161                         // Get number of chart areas that requeres automatic positioning
2162                         int     areaNumber = 0;
2163                         foreach (ChartArea area in _chartAreas )
2164                         {
2165
2166                                 // Check if area is visible
2167                                 if(area.Visible)
2168
2169                                 {
2170                                         if(area.Position.Auto)
2171                                         {
2172                                                 ++areaNumber;
2173                                         }
2174                                 }
2175                         }
2176
2177                         // Calculate how many columns & rows of areas we going to have
2178                         int     areaColumns = (int)Math.Floor(Math.Sqrt(areaNumber));
2179                         if(areaColumns < 1)
2180                         {
2181                                 areaColumns = 1;
2182                         }
2183                         int     areaRows = (int)Math.Ceiling(((float)areaNumber) / ((float)areaColumns));
2184
2185                         // Set position for all areas
2186                         int     column = 0;
2187                         int     row = 0;
2188                         foreach (ChartArea area in _chartAreas )
2189                         {
2190
2191                                 // Check if area is visible
2192                                 if(area.Visible)
2193
2194                                 {
2195                                         if(area.Position.Auto)
2196                                         {
2197                                                 // Calculate area position
2198                                                 areaPosition.Width = chartAreasRectangle.Width / areaColumns - elementSpacing;
2199                                                 areaPosition.Height = chartAreasRectangle.Height / areaRows - elementSpacing;
2200                                                 areaPosition.X = chartAreasRectangle.X + column * (chartAreasRectangle.Width / areaColumns) + elementSpacing; 
2201                                                 areaPosition.Y = chartAreasRectangle.Y + row * (chartAreasRectangle.Height / areaRows) + elementSpacing; 
2202
2203                                                 // Calculate position of all titles in the collection docked outside of the chart area
2204                                                 TitleCollection.CalcOutsideTitlePosition(this, chartGraph, area, ref areaPosition, elementSpacing);
2205
2206                                                 // Calculate position of the legend if it's docked outside of the chart area
2207                                                 this.Legends.CalcOutsideLegendPosition(chartGraph, area, ref areaPosition, elementSpacing);
2208
2209                                                 // Set area position without changing the Auto flag
2210                                                 area.Position.SetPositionNoAuto(areaPosition.X, areaPosition.Y, areaPosition.Width, areaPosition.Height);
2211
2212                                                 // Go to next area
2213                                                 ++row;
2214                                                 if(row >= areaRows)
2215                                                 {
2216                                                         row = 0;
2217                                                         ++column;
2218                                                 }
2219                                         }
2220                                         else
2221                                         {
2222                                                 RectangleF rect = area.Position.ToRectangleF();
2223
2224                                                 // Calculate position of all titles in the collection docked outside of the chart area
2225                                                 TitleCollection.CalcOutsideTitlePosition(this, chartGraph, area, ref rect, elementSpacing);
2226
2227                                                 // Calculate position of the legend if it's docked outside of the chart area
2228                                                 this.Legends.CalcOutsideLegendPosition(chartGraph, area, ref rect, elementSpacing);
2229                                         }
2230                                 }
2231                         }
2232
2233                         //******************************************************
2234                         //** Align chart areas Position if required
2235                         //******************************************************
2236                         AlignChartAreasPosition();
2237
2238                         //********************************************************
2239                         //** Check if only chart area position must be calculated.
2240                         //********************************************************
2241                         if(!calcAreaPositionOnly)
2242                         {
2243
2244                                 //******************************************************
2245                                 //** Call Resize function for each chart area.
2246                                 //******************************************************
2247                                 foreach (ChartArea area in _chartAreas )
2248                                 {
2249
2250                                         // Check if area is visible
2251                                         if(area.Visible)
2252
2253                                         {
2254                                                 area.Resize(chartGraph);
2255                                         }
2256                                 }
2257
2258                                 //******************************************************
2259                                 //** Align chart areas InnerPlotPosition if required
2260                                 //******************************************************
2261                                 AlignChartAreas(AreaAlignmentStyles.PlotPosition);
2262
2263                                 //******************************************************
2264                                 //** Calculate position of the legend if it's inside
2265                                 //** chart plotting area
2266                                 //******************************************************
2267
2268                                 // Calculate position of all titles in the collection docked outside of the chart area
2269                                 TitleCollection.CalcInsideTitlePosition(this, chartGraph, elementSpacing);
2270                                 
2271                                 this.Legends.CalcInsideLegendPosition(chartGraph, elementSpacing);
2272                         }
2273                 }
2274
2275                 /// <summary>
2276                 /// Minimum and maximum do not have to be calculated 
2277                 /// from data series every time. It is very time 
2278                 /// consuming. Minimum and maximum are buffered 
2279                 /// and only when this flags are set Minimum and 
2280                 /// Maximum are refreshed from data.
2281                 /// </summary>
2282                 internal void ResetMinMaxFromData()
2283                 {
2284             if (_chartAreas != null)
2285             {
2286                 // Call ResetMinMaxFromData function for each chart area.
2287                 foreach (ChartArea area in _chartAreas)
2288                 {
2289
2290                     // Check if area is visible
2291                     if (area.Visible)
2292                     {
2293                         area.ResetMinMaxFromData();
2294                     }
2295                 }
2296             }
2297                 }
2298
2299                 /// <summary>
2300                 /// RecalculateAxesScale the chart picture.
2301                 /// </summary>
2302                 public void Recalculate()
2303                 {
2304                         // Call ReCalc function for each chart area.
2305                         foreach (ChartArea area in _chartAreas )
2306                         {
2307
2308                                 // Check if area is visible
2309                                 if(area.Visible)
2310
2311                                 {
2312                                         area.ReCalcInternal();
2313                                 }
2314                         }
2315                 }
2316         
2317                 #endregion
2318                 
2319                 #region Chart picture properties
2320
2321         // VSTS 96787-Text Direction (RTL/LTR)  
2322 #if !Microsoft_CONTROL
2323         private RightToLeft rightToLeft = RightToLeft.No;
2324 #endif //!Microsoft_CONTROL
2325         /// <summary>
2326         /// Gets or sets the RightToLeft type.
2327         /// </summary>
2328         [
2329         DefaultValue(RightToLeft.No)
2330         ]
2331         public RightToLeft RightToLeft
2332         {
2333             get
2334             {
2335 #if Microsoft_CONTROL
2336                 return this.Common.Chart.RightToLeft;
2337 #else // !WIN_CONTROL
2338                 return this.rightToLeft;
2339 #endif // WIN_CONTROL
2340             }
2341             set
2342             {
2343 #if Microsoft_CONTROL
2344                 this.Common.Chart.RightToLeft = value;
2345 #else // !Microsoft_CONTROL
2346                 this.rightToLeft = value;
2347 #endif // Microsoft_CONTROL
2348             }
2349         }
2350
2351                 /// <summary>
2352                 /// Indicates that non-critical chart exceptions will be suppressed.
2353                 /// </summary>
2354                 [
2355                 SRCategory("CategoryAttributeMisc"),
2356                 DefaultValue(false),
2357                 SRDescription("DescriptionAttributeSuppressExceptions"),
2358                 ]
2359                 internal bool SuppressExceptions
2360                 {
2361                         set
2362                         {
2363                                 _suppressExceptions = value;
2364                         }
2365                         get
2366                         {
2367                                 return _suppressExceptions;
2368                         }
2369                 }
2370
2371                 /// <summary>
2372                 /// Chart border skin style.
2373                 /// </summary>
2374                 [
2375                 SRCategory("CategoryAttributeAppearance"),
2376                 Bindable(true),
2377                 DefaultValue(BorderSkinStyle.None),
2378                 SRDescription("DescriptionAttributeBorderSkin"),
2379 #if !Microsoft_CONTROL
2380         PersistenceMode(PersistenceMode.InnerProperty),
2381 #endif
2382                 ]
2383                 public BorderSkin BorderSkin
2384                 {
2385                         get
2386                         {
2387                                 return _borderSkin;
2388                         }
2389                         set
2390                         {
2391                                 _borderSkin = value;
2392                         }
2393                 }
2394
2395 #if ! Microsoft_CONTROL
2396
2397                 /// <summary>
2398                 /// Indicates that chart image map is enabled.
2399                 /// </summary>
2400                 [
2401                 SRCategory("CategoryAttributeMap"),
2402                 Bindable(true),
2403                 SRDescription("DescriptionAttributeMapEnabled"),
2404                 PersistenceMode(PersistenceMode.InnerProperty),
2405                 DefaultValue(true)
2406                 ]
2407                 public bool IsMapEnabled
2408                 {
2409                         get
2410                         {
2411                                 return _isMapEnabled;
2412                         }
2413                         set
2414                         {
2415                                 _isMapEnabled = value;
2416                         }
2417                 }
2418
2419                 /// <summary>
2420                 /// Chart map areas collection.
2421                 /// </summary>
2422                 [
2423                 SRCategory("CategoryAttributeMap"),
2424                 SRDescription("DescriptionAttributeMapAreas"),
2425                 PersistenceMode(PersistenceMode.InnerProperty),
2426         Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
2427                 ]
2428                 public MapAreasCollection MapAreas
2429                 {
2430                         get
2431                         {
2432                 return _mapAreas;
2433                         }
2434                 }
2435 #endif
2436
2437                 /// <summary>
2438                 /// Reference to chart area collection
2439                 /// </summary>
2440                 [
2441                 SRCategory("CategoryAttributeAppearance"),
2442                 Bindable(true),
2443                 SRDescription("DescriptionAttributeChartAreas"),
2444 #if !Microsoft_CONTROL
2445         PersistenceMode(PersistenceMode.InnerProperty),
2446 #endif
2447         Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
2448                 ]
2449                 public ChartAreaCollection ChartAreas
2450                 {
2451                         get
2452                         {
2453                                 return _chartAreas;
2454                         }
2455                 }
2456
2457                 /// <summary>
2458                 /// Chart legend collection.
2459                 /// </summary>
2460                 [
2461                 SRCategory("CategoryAttributeChart"),
2462                 SRDescription("DescriptionAttributeLegends"),
2463         Editor(Editors.LegendCollectionEditor.Editor, Editors.LegendCollectionEditor.Base),
2464 #if !Microsoft_CONTROL
2465                 PersistenceMode(PersistenceMode.InnerProperty),
2466 #endif
2467                 ]
2468                 public LegendCollection Legends
2469                 {
2470                         get
2471                         {
2472                                 return _legends;
2473                         }
2474                 }
2475
2476                 /// <summary>
2477                 /// Chart title collection.
2478                 /// </summary>
2479                 [
2480                 SRCategory("CategoryAttributeCharttitle"),
2481                 SRDescription("DescriptionAttributeTitles"),
2482         Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base),
2483 #if !Microsoft_CONTROL
2484                 PersistenceMode(PersistenceMode.InnerProperty),
2485 #endif
2486                 ]
2487                 public TitleCollection Titles
2488                 {
2489                         get
2490                         {
2491                                 return _titles;
2492                         }
2493                 }
2494
2495
2496
2497                 /// <summary>
2498                 /// Chart annotation collection.
2499                 /// </summary>
2500                 [
2501                 SRCategory("CategoryAttributeChart"),
2502                 SRDescription("DescriptionAttributeAnnotations3"),
2503         Editor(Editors.AnnotationCollectionEditor.Editor, Editors.AnnotationCollectionEditor.Base),
2504 #if !Microsoft_CONTROL
2505                 PersistenceMode(PersistenceMode.InnerProperty),
2506 #endif
2507                 ]
2508                 public AnnotationCollection Annotations
2509                 {
2510                         get
2511                         {
2512                                 return _annotations;
2513                         }
2514                 }
2515
2516
2517
2518                 /// <summary>
2519                 /// Background color for the Chart
2520                 /// </summary>
2521                 [
2522
2523                 SRCategory("CategoryAttributeAppearance"),
2524                 Bindable(true),
2525                 DefaultValue(typeof(Color), "White"),
2526         SRDescription("DescriptionAttributeBackColor"),
2527         TypeConverter(typeof(ColorConverter)),
2528         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
2529         #if !Microsoft_CONTROL
2530         PersistenceMode(PersistenceMode.Attribute)
2531         #endif
2532                 ]
2533                 public Color BackColor
2534                 {
2535                         get
2536                         {
2537                                 return _backColor;
2538                         }
2539                         set
2540                         {
2541 #if !Microsoft_CONTROL
2542                         if(value == Color.Empty  || value.A != 255 || value == Color.Transparent)
2543                         {
2544                                 // NOTE: Transparent colors are valid
2545                         }
2546 #endif
2547                 _backColor = value;
2548                         }
2549                 }
2550
2551                 /// <summary>
2552                 /// Border color for the Chart
2553                 /// </summary>
2554                 [
2555
2556                 SRCategory("CategoryAttributeAppearance"),
2557                 Bindable(true),
2558                 DefaultValue(typeof(Color), "White"),
2559                 SRDescription("DescriptionAttributeBorderColor"),
2560         TypeConverter(typeof(ColorConverter)),
2561         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
2562         #if !Microsoft_CONTROL
2563         PersistenceMode(PersistenceMode.Attribute)
2564         #endif
2565                 ]
2566                 public Color BorderColor
2567                 {
2568                         get
2569                         {
2570                 return _borderColor;
2571                         }
2572                         set
2573                         {
2574                 _borderColor = value;
2575                         }
2576                 }
2577
2578                 /// <summary>
2579                 /// Chart width
2580                 /// </summary>
2581                 [
2582                 SRCategory("CategoryAttributeAppearance"),
2583                 Bindable(true),
2584                 DefaultValue(300),
2585                 SRDescription("DescriptionAttributeWidth"),
2586         #if !Microsoft_CONTROL
2587         PersistenceMode(PersistenceMode.Attribute)
2588         #endif
2589                 ]
2590                 public int Width
2591                 {
2592                         get
2593                         {
2594                 return _width;
2595                         }
2596                         set
2597                         {
2598                 this.InspectChartDimensions(value, this.Height);
2599                 _width = value;
2600                 Common.Width = _width;
2601                         }
2602                 }
2603
2604                 /// <summary>
2605                 /// Series Data Manipulator
2606                 /// </summary>
2607                 [
2608                 SRCategory("CategoryAttributeData"),
2609                 SRDescription("DescriptionAttributeDataManipulator"),
2610                 Browsable(false),
2611                 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
2612                 SerializationVisibilityAttribute(SerializationVisibility.Hidden)
2613                 ]
2614                 public DataManipulator DataManipulator
2615                 {
2616                         get
2617                         {
2618                 return _dataManipulator;
2619                         }
2620                 }
2621
2622
2623
2624
2625                 /// <summary>
2626                 /// Chart height
2627                 /// </summary>
2628                 [
2629                 SRCategory("CategoryAttributeAppearance"),
2630                 Bindable(true),
2631                 DefaultValue(300),
2632                 SRDescription("DescriptionAttributeHeight3"),
2633         #if !Microsoft_CONTROL
2634         PersistenceMode(PersistenceMode.Attribute)
2635         #endif
2636                 ]
2637                 public int Height
2638                 {
2639                         get
2640                         {
2641                 return _height;
2642                         }
2643                         set
2644                         {
2645                 this.InspectChartDimensions(this.Width, value);
2646                 _height = value;
2647                                 Common.Height = value;
2648                         }
2649                 }
2650
2651                 /// <summary>
2652                 /// Back Hatch style
2653                 /// </summary>
2654                 [
2655
2656                 SRCategory("CategoryAttributeAppearance"),
2657                 Bindable(true),
2658                 DefaultValue(ChartHatchStyle.None),
2659         SRDescription("DescriptionAttributeBackHatchStyle"),
2660         #if !Microsoft_CONTROL
2661         PersistenceMode(PersistenceMode.Attribute),
2662         #endif
2663         Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
2664                 ]
2665                 public ChartHatchStyle BackHatchStyle
2666                 {
2667                         get
2668                         {
2669                 return _backHatchStyle;
2670                         }
2671                         set
2672                         {
2673                 _backHatchStyle = value;
2674                         }
2675                 }
2676
2677                 /// <summary>
2678                 /// Chart area background image
2679                 /// </summary>
2680                 [
2681                 SRCategory("CategoryAttributeAppearance"),
2682                 Bindable(true),
2683                 DefaultValue(""),
2684         SRDescription("DescriptionAttributeBackImage"),
2685         Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
2686             #if !Microsoft_CONTROL
2687                 PersistenceMode(PersistenceMode.Attribute),
2688             #endif
2689                 NotifyParentPropertyAttribute(true)
2690                 ]
2691                 public string BackImage
2692                 {
2693                         get
2694                         {
2695                 return _backImage;
2696                         }
2697                         set
2698                         {
2699                 _backImage = value;
2700                         }
2701                 }
2702
2703                 /// <summary>
2704                 /// Chart area background image drawing mode.
2705                 /// </summary>
2706                 [
2707                 SRCategory("CategoryAttributeAppearance"),
2708                 Bindable(true),
2709                 DefaultValue(ChartImageWrapMode.Tile),
2710                 NotifyParentPropertyAttribute(true),
2711         SRDescription("DescriptionAttributeImageWrapMode"),
2712         #if !Microsoft_CONTROL
2713         PersistenceMode(PersistenceMode.Attribute)
2714         #endif
2715                 ]
2716                 public ChartImageWrapMode BackImageWrapMode
2717                 {
2718                         get
2719                         {
2720                 return _backImageWrapMode;
2721                         }
2722                         set
2723                         {
2724                 _backImageWrapMode = value;
2725                         }
2726                 }
2727
2728                 /// <summary>
2729                 /// Background image transparent color.
2730                 /// </summary>
2731                 [
2732                 SRCategory("CategoryAttributeAppearance"),
2733                 Bindable(true),
2734                 DefaultValue(typeof(Color), ""),
2735                 NotifyParentPropertyAttribute(true),
2736         SRDescription("DescriptionAttributeImageTransparentColor"),
2737         TypeConverter(typeof(ColorConverter)),
2738         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
2739         #if !Microsoft_CONTROL
2740         PersistenceMode(PersistenceMode.Attribute)
2741         #endif
2742                 ]
2743                 public Color BackImageTransparentColor
2744                 {
2745                         get
2746                         {
2747                 return _backImageTransparentColor;
2748                         }
2749                         set
2750                         {
2751                 _backImageTransparentColor = value;
2752                         }
2753                 }
2754
2755                 /// <summary>
2756                 /// Background image alignment used by ClampUnscale drawing mode.
2757                 /// </summary>
2758                 [
2759                 SRCategory("CategoryAttributeAppearance"),
2760                 Bindable(true),
2761                 DefaultValue(ChartImageAlignmentStyle.TopLeft),
2762                 NotifyParentPropertyAttribute(true),
2763         SRDescription("DescriptionAttributeBackImageAlign"),
2764         #if !Microsoft_CONTROL
2765         PersistenceMode(PersistenceMode.Attribute)
2766         #endif
2767                 ]
2768                 public ChartImageAlignmentStyle BackImageAlignment
2769                 {
2770                         get
2771                         {
2772                 return _backImageAlign;
2773                         }
2774                         set
2775                         {
2776                 _backImageAlign = value;
2777                         }
2778                 }
2779
2780                 /// <summary>
2781                 /// Indicates that smoothing is applied while drawing shadows.
2782                 /// </summary>
2783                 [
2784                 SRCategory("CategoryAttributeImage"),
2785                 Bindable(true),
2786                 DefaultValue(true),
2787                 SRDescription("DescriptionAttributeSoftShadows3"),
2788         #if !Microsoft_CONTROL
2789         PersistenceMode(PersistenceMode.Attribute)
2790         #endif
2791                 ]
2792                 public bool IsSoftShadows
2793                 {
2794                         get
2795                         {
2796                 return _isSoftShadows;
2797                         }
2798                         set
2799                         {
2800                 _isSoftShadows = value;
2801                         }
2802                 }
2803
2804                 /// <summary>
2805                 /// Specifies whether smoothing (antialiasing) is applied while drawing chart.
2806                 /// </summary>
2807                 [
2808                 SRCategory("CategoryAttributeImage"),
2809                 Bindable(true),
2810                 DefaultValue(typeof(AntiAliasingStyles), "All"),
2811                 SRDescription("DescriptionAttributeAntiAlias"),
2812         #if !Microsoft_CONTROL
2813                 PersistenceMode(PersistenceMode.Attribute)
2814         #endif
2815                 ]
2816                 public AntiAliasingStyles AntiAliasing
2817                 {
2818                         get
2819                         {
2820                 return _antiAliasing;
2821                         }
2822                         set
2823                         {
2824                 _antiAliasing = value;
2825                         }
2826                 }
2827
2828                 /// <summary>
2829                 /// Specifies the quality of text antialiasing.
2830                 /// </summary>
2831                 [
2832                 SRCategory("CategoryAttributeImage"),
2833                 Bindable(true),
2834                 DefaultValue(typeof(TextAntiAliasingQuality), "High"),
2835                 SRDescription("DescriptionAttributeTextAntiAliasingQuality"),
2836 #if !Microsoft_CONTROL
2837                 PersistenceMode(PersistenceMode.Attribute)
2838 #endif
2839                 ]
2840                 public TextAntiAliasingQuality TextAntiAliasingQuality
2841                 {
2842                         get
2843                         {
2844                 return _textAntiAliasingQuality;
2845                         }
2846                         set
2847                         {
2848                 _textAntiAliasingQuality = value;
2849                         }
2850                 }
2851
2852                 /// <summary>
2853                 /// A type for the background gradient
2854                 /// </summary>
2855                 [
2856
2857                 SRCategory("CategoryAttributeAppearance"),
2858                 Bindable(true),
2859                 DefaultValue(GradientStyle.None),
2860         SRDescription("DescriptionAttributeBackGradientStyle"),
2861         #if !Microsoft_CONTROL
2862         PersistenceMode(PersistenceMode.Attribute),
2863         #endif
2864         Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
2865                 ]
2866                 public GradientStyle BackGradientStyle
2867                 {
2868                         get
2869                         {
2870                                 return _backGradientStyle;
2871                         }
2872                         set
2873                         {
2874                                 _backGradientStyle = value;
2875                         }
2876                 }
2877
2878                 /// <summary>
2879                 /// The second color which is used for a gradient
2880                 /// </summary>
2881                 [
2882
2883                 SRCategory("CategoryAttributeAppearance"),
2884                 Bindable(true),
2885                 DefaultValue(typeof(Color), ""),
2886         SRDescription("DescriptionAttributeBackSecondaryColor"),
2887         TypeConverter(typeof(ColorConverter)),
2888         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
2889         #if !Microsoft_CONTROL
2890         PersistenceMode(PersistenceMode.Attribute)
2891         #endif
2892                 ]
2893                 public Color BackSecondaryColor
2894                 {
2895                         get
2896                         {
2897                 return _backSecondaryColor;
2898                         }
2899                         set
2900                         {
2901 #if !Microsoft_CONTROL
2902                         if(value != Color.Empty && (value.A != 255 || value == Color.Transparent))
2903                         {
2904                                 throw (new ArgumentException( SR.ExceptionBackSecondaryColorIsTransparent));
2905                         }
2906 #endif
2907                 _backSecondaryColor = value;
2908                         }
2909                 }
2910
2911                 /// <summary>
2912                 /// The width of the border line
2913                 /// </summary>
2914                 [
2915
2916                 SRCategory("CategoryAttributeAppearance"),
2917                 Bindable(true),
2918                 DefaultValue(1),
2919                 SRDescription("DescriptionAttributeChart_BorderlineWidth"),
2920         #if !Microsoft_CONTROL
2921         PersistenceMode(PersistenceMode.Attribute)
2922         #endif
2923                 ]
2924                 public int BorderWidth
2925                 {
2926                         get
2927                         {
2928                 return _borderWidth;
2929                         }
2930                         set
2931                         {
2932                                 if(value < 0)
2933                                 {
2934                                         throw(new ArgumentOutOfRangeException("value", SR.ExceptionChartBorderIsNegative));
2935                                 }
2936                 _borderWidth = value;
2937                         }
2938                 }
2939
2940                 /// <summary>
2941                 /// The style of the border line
2942                 /// </summary>
2943                 [
2944
2945                 SRCategory("CategoryAttributeAppearance"),
2946                 Bindable(true),
2947                 DefaultValue(ChartDashStyle.NotSet),
2948         SRDescription("DescriptionAttributeBorderDashStyle"),
2949         #if !Microsoft_CONTROL
2950         PersistenceMode(PersistenceMode.Attribute)
2951         #endif
2952                 ]
2953                 public ChartDashStyle BorderDashStyle
2954                 {
2955                         get
2956                         {
2957                 return _borderDashStyle;
2958                         }
2959                         set
2960                         {
2961                 _borderDashStyle = value;
2962                         }
2963                 }
2964
2965         /// <summary>
2966         /// Gets the font cache.
2967         /// </summary>
2968         /// <value>The font cache.</value>
2969         internal FontCache FontCache 
2970         {
2971             get { return _fontCache; }
2972         }
2973
2974                 #endregion      
2975
2976                 #region Chart areas alignment methods
2977
2978                 /// <summary>
2979                 /// Checks if any of the chart areas are aligned.
2980                 /// Also checks if the chart ares name in AlignWithChartArea property is valid.
2981                 /// </summary>
2982                 /// <returns>True if at least one area requires alignment.</returns>
2983                 private bool IsAreasAlignmentRequired()
2984                 {
2985                         bool    alignmentRequired = false;
2986
2987                         // Loop through all chart areas
2988                         foreach(ChartArea area in this.ChartAreas)
2989                         {
2990
2991                                 // Check if chart area is visible
2992                                 if(area.Visible)
2993
2994                                 {
2995                                         // Check if area is aligned
2996                     if (area.AlignWithChartArea != Constants.NotSetValue)
2997                                         {
2998                                                 alignmentRequired = true;
2999
3000                                                 // Check the chart area used for alignment
3001                         if (this._chartAreas.IndexOf(area.AlignWithChartArea)<0)
3002                         {
3003                             throw (new InvalidOperationException(SR.ExceptionChartAreaNameReferenceInvalid(area.Name, area.AlignWithChartArea)));
3004                         }
3005                                         }
3006                                 }
3007                         }
3008
3009                         return alignmentRequired;
3010                 }
3011
3012                 /// <summary>
3013                 /// Creates a list of the aligned chart areas.
3014                 /// </summary>
3015                 /// <param name="masterArea">Master chart area.</param>
3016                 /// <param name="type">Alignment type.</param>
3017                 /// <param name="orientation">Vertical or Horizontal orientation.</param>
3018                 /// <returns>List of areas that area aligned to the master area.</returns>
3019                 private ArrayList GetAlignedAreasGroup(ChartArea masterArea, AreaAlignmentStyles type, AreaAlignmentOrientations orientation)
3020                 {
3021                         ArrayList       areaList = new ArrayList();
3022
3023                         // Loop throught the chart areas and get the ones aligned with specified master area
3024                         foreach(ChartArea area in this.ChartAreas)
3025                         {
3026
3027                                 // Check if chart area is visible
3028                                 if(area.Visible)
3029
3030                                 {
3031                                         if(area.Name != masterArea.Name && 
3032                                                 area.AlignWithChartArea == masterArea.Name && 
3033                                                 (area.AlignmentStyle & type) == type &&
3034                                                 (area.AlignmentOrientation & orientation) == orientation )
3035                                         {
3036                                                 // Add "slave" area into the list
3037                                                 areaList.Add(area);
3038                                         }
3039                                 }
3040                         }
3041
3042                         // If list is not empty insert "master" area in the beginning
3043                         if(areaList.Count > 0)
3044                         {
3045                                 areaList.Insert(0, masterArea);
3046                         }
3047
3048                         return areaList;
3049                 }
3050
3051                 /// <summary>
3052                 /// Performs specified type of alignment for the chart areas.
3053                 /// </summary>
3054                 /// <param name="type">Alignment type required.</param>
3055                 internal void AlignChartAreas(AreaAlignmentStyles type)
3056                 {
3057                         // Check if alignment required
3058                         if(IsAreasAlignmentRequired())
3059                         {
3060                                 // Loop through all chart areas
3061                                 foreach(ChartArea area in this.ChartAreas)
3062                                 {
3063
3064                                         // Check if chart area is visible
3065                                         if(area.Visible)
3066
3067                                         {
3068                                                 // Get vertical areas alignment group using current area as a master
3069                                                 ArrayList alignGroup = GetAlignedAreasGroup(
3070                                                         area, 
3071                                                         type, 
3072                                                         AreaAlignmentOrientations.Vertical);
3073
3074                                                 // Align each area in the group
3075                                                 if(alignGroup.Count > 0)
3076                                                 {
3077                                                         AlignChartAreasPlotPosition(alignGroup, AreaAlignmentOrientations.Vertical);
3078                                                 }
3079
3080                                                 // Get horizontal areas alignment group using current area as a master
3081                                                 alignGroup = GetAlignedAreasGroup(
3082                                                         area, 
3083                                                         type, 
3084                                                         AreaAlignmentOrientations.Horizontal);
3085
3086                                                 // Align each area in the group
3087                                                 if(alignGroup.Count > 0)
3088                                                 {
3089                                                         AlignChartAreasPlotPosition(alignGroup, AreaAlignmentOrientations.Horizontal);
3090                                                 }
3091                                         }
3092                                 }
3093                         }
3094                 }
3095
3096                 /// <summary>
3097                 /// Align inner plot position of the chart areas in the group.
3098                 /// </summary>
3099                 /// <param name="areasGroup">List of areas in the group.</param>
3100                 /// <param name="orientation">Group orientation.</param>
3101                 private void AlignChartAreasPlotPosition(ArrayList areasGroup, AreaAlignmentOrientations orientation)
3102                 {
3103                         //****************************************************************
3104                         //** Find the smalles size of the inner plot 
3105                         //****************************************************************
3106                         RectangleF      areaPlotPosition = ((ChartArea)areasGroup[0]).PlotAreaPosition.ToRectangleF();
3107                         foreach(ChartArea area in areasGroup)
3108                         {
3109                                 if(area.PlotAreaPosition.X > areaPlotPosition.X)
3110                                 {
3111                                         areaPlotPosition.X += area.PlotAreaPosition.X - areaPlotPosition.X;
3112                                         areaPlotPosition.Width -= area.PlotAreaPosition.X - areaPlotPosition.X;
3113                                 }
3114                                 if(area.PlotAreaPosition.Y > areaPlotPosition.Y)
3115                                 {
3116                                         areaPlotPosition.Y += area.PlotAreaPosition.Y - areaPlotPosition.Y;
3117                                         areaPlotPosition.Height -= area.PlotAreaPosition.Y - areaPlotPosition.Y;
3118                                 }
3119                                 if(area.PlotAreaPosition.Right < areaPlotPosition.Right)
3120                                 {
3121                                         areaPlotPosition.Width -= areaPlotPosition.Right - area.PlotAreaPosition.Right;
3122                                         if(areaPlotPosition.Width < 5)
3123                                         {
3124                                                 areaPlotPosition.Width = 5;
3125                                         }
3126                                 }
3127                                 if(area.PlotAreaPosition.Bottom < areaPlotPosition.Bottom)
3128                                 {
3129                                         areaPlotPosition.Height -= areaPlotPosition.Bottom - area.PlotAreaPosition.Bottom;
3130                                         if(areaPlotPosition.Height < 5)
3131                                         {
3132                                                 areaPlotPosition.Height = 5;
3133                                         }
3134                                 }
3135                         }
3136
3137                         //****************************************************************
3138                         //** Align inner plot position for all areas
3139                         //****************************************************************
3140                         foreach(ChartArea area in areasGroup)
3141                         {
3142                                 // Get curretn plot position of the area
3143                                 RectangleF      rect = area.PlotAreaPosition.ToRectangleF();
3144
3145                                 // Adjust area position
3146                                 if( (orientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical)
3147                                 {
3148                                         rect.X = areaPlotPosition.X;
3149                                         rect.Width = areaPlotPosition.Width;
3150                                 }
3151                                 if( (orientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal)
3152                                 {
3153                                         rect.Y = areaPlotPosition.Y;
3154                                         rect.Height = areaPlotPosition.Height;
3155                                 }
3156
3157                                 // Set new plot position in coordinates relative to chart picture
3158                                 area.PlotAreaPosition.SetPositionNoAuto(rect.X, rect.Y, rect.Width, rect.Height);
3159
3160                                 // Set new plot position in coordinates relative to chart area position
3161                                 rect.X = (rect.X - area.Position.X) / area.Position.Width * 100f;
3162                                 rect.Y = (rect.Y - area.Position.Y) / area.Position.Height * 100f;
3163                                 rect.Width = rect.Width / area.Position.Width * 100f;
3164                                 rect.Height = rect.Height / area.Position.Height * 100f;
3165                                 area.InnerPlotPosition.SetPositionNoAuto(rect.X, rect.Y, rect.Width, rect.Height);
3166
3167                                 if( (orientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical)
3168                                 {
3169                                         area.AxisX2.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
3170                                         area.AxisX.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
3171                                 }
3172                                 if( (orientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal)
3173                                 {
3174                                         area.AxisY2.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
3175                                         area.AxisY.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto);
3176                                 }
3177                         }
3178
3179                 }
3180
3181                 /// <summary>
3182                 /// Aligns positions of the chart areas.
3183                 /// </summary>
3184                 private void AlignChartAreasPosition()
3185                 {
3186                         // Check if alignment required
3187                         if(IsAreasAlignmentRequired())
3188                         {
3189                                 // Loop through all chart areas
3190                                 foreach(ChartArea area in this.ChartAreas)
3191                                 {
3192
3193                                         // Check if chart area is visible
3194                                         if(area.Visible)
3195
3196                                         {
3197                                                 // Check if area is alignd by Position to any other area
3198                         if (area.AlignWithChartArea != Constants.NotSetValue && (area.AlignmentStyle & AreaAlignmentStyles.Position) == AreaAlignmentStyles.Position)
3199                                                 {
3200                                                         // Get current area position
3201                                                         RectangleF      areaPosition = area.Position.ToRectangleF();
3202
3203                                                         // Get master chart area
3204                                                         ChartArea       masterArea = this.ChartAreas[area.AlignWithChartArea];
3205
3206                                                         // Vertical alignment
3207                                                         if((area.AlignmentOrientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical)
3208                                                         {
3209                                                                 // Align area position
3210                                                                 areaPosition.X = masterArea.Position.X;
3211                                                                 areaPosition.Width = masterArea.Position.Width;
3212                                                         }
3213
3214                                                         // Horizontal alignment
3215                                                         if((area.AlignmentOrientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal)
3216                                                         {
3217                                                                 // Align area position
3218                                                                 areaPosition.Y = masterArea.Position.Y;
3219                                                                 areaPosition.Height = masterArea.Position.Height;
3220                                                         }
3221
3222                                                         // Set new position
3223                                                         area.Position.SetPositionNoAuto(areaPosition.X, areaPosition.Y, areaPosition.Width, areaPosition.Height);
3224                                                 }
3225                                         }
3226                                 }
3227                         }
3228         }
3229
3230 #if Microsoft_CONTROL
3231
3232         /// <summary>
3233                 /// Align chart areas cursor.
3234                 /// </summary>
3235                 /// <param name="changedArea">Changed chart area.</param>
3236                 /// <param name="orientation">Orientation of the changed cursor.</param>
3237                 /// <param name="selectionChanged">AxisName of change cursor or selection.</param>
3238                 internal void AlignChartAreasCursor(ChartArea changedArea, AreaAlignmentOrientations orientation, bool selectionChanged)
3239                 {
3240                         // Check if alignment required
3241                         if(IsAreasAlignmentRequired())
3242                         {
3243                                 // Loop through all chart areas
3244                                 foreach(ChartArea area in this.ChartAreas)
3245                                 {
3246
3247                                 // Check if chart area is visible
3248                                         if(area.Visible)
3249
3250                                         {
3251                                                 // Get vertical areas alignment group using current area as a master
3252                                                 ArrayList alignGroup = GetAlignedAreasGroup(
3253                                                         area, 
3254                                                         AreaAlignmentStyles.Cursor, 
3255                                                         orientation);
3256
3257                                                 // Align each area in the group if it contains changed area
3258                                                 if(alignGroup.Contains(changedArea))
3259                                                 {
3260                                                         // Set cursor position for all areas in the group
3261                                                         foreach(ChartArea groupArea in alignGroup)
3262                                                         {
3263                                                                 groupArea.alignmentInProcess = true;
3264
3265                                                                 if(orientation == AreaAlignmentOrientations.Vertical)
3266                                                                 {
3267                                                                         if(selectionChanged)
3268                                                                         {
3269                                                                                 groupArea.CursorX.SelectionStart = changedArea.CursorX.SelectionStart;
3270                                                                                 groupArea.CursorX.SelectionEnd = changedArea.CursorX.SelectionEnd;
3271                                                                         }
3272                                                                         else
3273                                                                         {
3274                                                                                 groupArea.CursorX.Position = changedArea.CursorX.Position;
3275                                                                         }
3276                                                                 }
3277                                                                 if(orientation == AreaAlignmentOrientations.Horizontal)
3278                                                                 {
3279                                                                         if(selectionChanged)
3280                                                                         {
3281                                                                                 groupArea.CursorY.SelectionStart = changedArea.CursorY.SelectionStart;
3282                                                                                 groupArea.CursorY.SelectionEnd = changedArea.CursorY.SelectionEnd;
3283                                                                         }
3284                                                                         else
3285                                                                         {
3286                                                                                 groupArea.CursorY.Position = changedArea.CursorY.Position;
3287                                                                         }
3288                                                                 }
3289
3290                                                                 groupArea.alignmentInProcess = false;
3291                                                         }
3292                                                 }
3293                                         }
3294                                 }
3295                         }
3296         }
3297
3298         /// <summary>
3299                 /// One of the chart areas was zoomed by the user.
3300                 /// </summary>
3301                 /// <param name="changedArea">Changed chart area.</param>
3302                 /// <param name="orientation">Orientation of the changed scaleView.</param>
3303                 /// <param name="disposeBufferBitmap">Area double fuffer image must be disposed.</param>
3304                 internal void AlignChartAreasZoomed(ChartArea changedArea, AreaAlignmentOrientations orientation, bool disposeBufferBitmap)
3305                 {
3306                         // Check if alignment required
3307                         if(IsAreasAlignmentRequired())
3308                         {
3309                                 // Loop through all chart areas
3310                                 foreach(ChartArea area in this.ChartAreas)
3311                                 {
3312
3313                                 // Check if chart area is visible
3314                                         if(area.Visible)
3315
3316                                         {
3317                                                 // Get vertical areas alignment group using current area as a master
3318                                                 ArrayList alignGroup = GetAlignedAreasGroup(
3319                                                         area, 
3320                                                         AreaAlignmentStyles.AxesView, 
3321                                                         orientation);
3322
3323                                                 // Align each area in the group if it contains changed area
3324                                                 if(alignGroup.Contains(changedArea))
3325                                                 {
3326                                                         // Set cursor position for all areas in the group
3327                                                         foreach(ChartArea groupArea in alignGroup)
3328                                                         {
3329                                                                 // Clear image buffer
3330                                                                 if(groupArea.areaBufferBitmap != null && disposeBufferBitmap)
3331                                                                 {
3332                                                                         groupArea.areaBufferBitmap.Dispose();
3333                                                                         groupArea.areaBufferBitmap = null;
3334                                                                 }
3335
3336                                                                 if(orientation == AreaAlignmentOrientations.Vertical)
3337                                                                 {
3338                                                                         groupArea.CursorX.SelectionStart = double.NaN;
3339                                                                         groupArea.CursorX.SelectionEnd = double.NaN;
3340                                                                 }
3341                                                                 if(orientation == AreaAlignmentOrientations.Horizontal)
3342                                                                 {
3343                                                                         groupArea.CursorY.SelectionStart = double.NaN;
3344                                                                         groupArea.CursorY.SelectionEnd = double.NaN;
3345                                                                 }
3346                                                         }
3347                                                 }
3348                                         }
3349                                 }
3350                         }
3351         }
3352
3353 #endif //Microsoft_CONTROL
3354
3355         /// <summary>
3356                 /// Align chart areas axes views.
3357                 /// </summary>
3358                 /// <param name="changedArea">Changed chart area.</param>
3359                 /// <param name="orientation">Orientation of the changed scaleView.</param>
3360                 internal void AlignChartAreasAxesView(ChartArea changedArea, AreaAlignmentOrientations orientation)
3361                 {
3362                         // Check if alignment required
3363                         if(IsAreasAlignmentRequired())
3364                         {
3365                                 // Loop through all chart areas
3366                                 foreach(ChartArea area in this.ChartAreas)
3367                                 {
3368
3369                                         // Check if chart area is visible
3370                                         if(area.Visible)
3371
3372                                         {
3373                                                 // Get vertical areas alignment group using current area as a master
3374                                                 ArrayList alignGroup = GetAlignedAreasGroup(
3375                                                         area, 
3376                                                         AreaAlignmentStyles.AxesView, 
3377                                                         orientation);
3378
3379                                                 // Align each area in the group if it contains changed area
3380                                                 if(alignGroup.Contains(changedArea))
3381                                                 {
3382                                                         // Set cursor position for all areas in the group
3383                                                         foreach(ChartArea groupArea in alignGroup)
3384                                                         {
3385                                                                 groupArea.alignmentInProcess = true;
3386
3387                                                                 if(orientation == AreaAlignmentOrientations.Vertical)
3388                                                                 {
3389                                                                         groupArea.AxisX.ScaleView.Position = changedArea.AxisX.ScaleView.Position;
3390                                                                         groupArea.AxisX.ScaleView.Size = changedArea.AxisX.ScaleView.Size;
3391                                                                         groupArea.AxisX.ScaleView.SizeType = changedArea.AxisX.ScaleView.SizeType;
3392
3393                                                                         groupArea.AxisX2.ScaleView.Position = changedArea.AxisX2.ScaleView.Position;
3394                                                                         groupArea.AxisX2.ScaleView.Size = changedArea.AxisX2.ScaleView.Size;
3395                                                                         groupArea.AxisX2.ScaleView.SizeType = changedArea.AxisX2.ScaleView.SizeType;
3396                                                                 }
3397                                                                 if(orientation == AreaAlignmentOrientations.Horizontal)
3398                                                                 {
3399                                                                         groupArea.AxisY.ScaleView.Position = changedArea.AxisY.ScaleView.Position;
3400                                                                         groupArea.AxisY.ScaleView.Size = changedArea.AxisY.ScaleView.Size;
3401                                                                         groupArea.AxisY.ScaleView.SizeType = changedArea.AxisY.ScaleView.SizeType;
3402
3403                                                                         groupArea.AxisY2.ScaleView.Position = changedArea.AxisY2.ScaleView.Position;
3404                                                                         groupArea.AxisY2.ScaleView.Size = changedArea.AxisY2.ScaleView.Size;
3405                                                                         groupArea.AxisY2.ScaleView.SizeType = changedArea.AxisY2.ScaleView.SizeType;
3406                                                                 }
3407
3408                                                                 groupArea.alignmentInProcess = false;
3409                                                         }
3410                                                 }
3411                                         }
3412                                 }
3413                         }
3414                 }
3415
3416                 #endregion
3417
3418                 #region Helper methods
3419
3420         /// <summary>
3421         /// Inspects the chart dimensions.
3422         /// </summary>
3423         /// <param name="width">The width.</param>
3424         /// <param name="height">The height.</param>
3425         internal void InspectChartDimensions(int width, int height)
3426         {
3427             if (this.Chart.IsDesignMode() && ((width * height) > (100 * 1024 *1024)))
3428             {
3429                 throw new ArgumentException(SR.ExceptionChartOutOfLimits);
3430             }
3431             if (width < 0)
3432             {
3433                 throw new ArgumentException(SR.ExceptionValueMustBeGreaterThan("Width", "0px"));
3434             }
3435             if (height < 0)
3436             {
3437                 throw new ArgumentException(SR.ExceptionValueMustBeGreaterThan("Height", "0px"));
3438             }
3439         }
3440
3441                 /// <summary>
3442                 /// Loads chart appearance template from file.
3443                 /// </summary>
3444                 /// <param name="name">Template file name to load from.</param>
3445                 public void LoadTemplate(string name)
3446                 {
3447             // Check arguments
3448             if (name == null)
3449                 throw new ArgumentNullException("name");
3450
3451                         // Load template data into the stream
3452 #if Microsoft_CONTROL
3453                         Stream  stream = new FileStream(name, FileMode.Open, FileAccess.Read);
3454 #else   // Microsoft_CONTROL
3455                         Stream  stream = LoadTemplateData(name);
3456 #endif  // Microsoft_CONTROL
3457
3458                         // Load template from stream
3459                         LoadTemplate(stream);
3460
3461                         // Close tempate stream
3462                         stream.Close();
3463                 }
3464
3465                 /// <summary>
3466                 /// Loads chart appearance template from stream.
3467                 /// </summary>
3468                 /// <param name="stream">Template stream to load from.</param>
3469         public void LoadTemplate(Stream stream)
3470         {
3471             // Check arguments
3472             if (stream == null)
3473                 throw new ArgumentNullException("stream");
3474
3475             ChartSerializer serializer = (ChartSerializer)this.Common.container.GetService(typeof(ChartSerializer));
3476             if (serializer != null)
3477             {
3478                 // Save previous serializer properties
3479                 string oldSerializableContent = serializer.SerializableContent;
3480                 string oldNonSerializableContent = serializer.NonSerializableContent;
3481                 SerializationFormat oldFormat = serializer.Format;
3482                 bool oldIgnoreUnknownXmlAttributes = serializer.IsUnknownAttributeIgnored;
3483                 bool oldTemplateMode = serializer.IsTemplateMode;
3484
3485                 // Set serializer properties
3486                 serializer.Content = SerializationContents.Appearance;
3487                 serializer.SerializableContent += ",Chart.Titles,Chart.Annotations," +
3488                                                   "Chart.Legends,Legend.CellColumns,Legend.CustomItems,LegendItem.Cells," +
3489                                                   "Chart.Series,Series.*Style," +
3490                                                   "Chart.ChartAreas,ChartArea.Axis*," +
3491                                                   "Axis.*Grid,Axis.*TickMark, Axis.*Style," +
3492                                                   "Axis.StripLines, Axis.CustomLabels";
3493                 serializer.Format = SerializationFormat.Xml;
3494                 serializer.IsUnknownAttributeIgnored = true;
3495                 serializer.IsTemplateMode = true;
3496
3497                 try
3498                 {
3499                     // Load template
3500                     serializer.Load(stream);
3501                 }
3502                 catch (Exception ex)
3503                 {
3504                     throw (new InvalidOperationException(ex.Message));
3505                 }
3506                 finally
3507                 {
3508                     // Restore previous serializer properties
3509                     serializer.SerializableContent = oldSerializableContent;
3510                     serializer.NonSerializableContent = oldNonSerializableContent;
3511                     serializer.Format = oldFormat;
3512                     serializer.IsUnknownAttributeIgnored = oldIgnoreUnknownXmlAttributes;
3513                     serializer.IsTemplateMode = oldTemplateMode;
3514                 }
3515             }
3516         }
3517
3518 #if !Microsoft_CONTROL
3519
3520                 /// <summary>
3521                 /// Loads template data from the URL.
3522                 /// </summary>
3523                 /// <param name="url">Template URL.</param>
3524                 /// <returns>Stream with template data or null if error.</returns>
3525                 private Stream LoadTemplateData(string url)
3526                 {
3527             Debug.Assert(url != null, "LoadTemplateData: handed a null url string");
3528
3529                         Stream  dataStream = null;
3530
3531                         // Try to load as relative URL using the Control object
3532                         if(dataStream == null)
3533                         {
3534                 if (this.Common != null && 
3535                     this.Common.Chart != null &&
3536                     this.Common.Chart.Page != null)
3537                 {
3538                     try
3539                     {
3540                         dataStream = new FileStream(
3541                             this.Common.Chart.Page.MapPath(url),
3542                             FileMode.Open);
3543                     }
3544                     catch (NotSupportedException)
3545                     {
3546                         dataStream = null;
3547                     }
3548                     catch (SecurityException)
3549                     {
3550                         dataStream = null;
3551                     }
3552                     catch (FileNotFoundException)
3553                     {
3554                         dataStream = null;
3555                     }
3556                     catch (DirectoryNotFoundException)
3557                     {
3558                         dataStream = null;
3559                     }
3560                     catch (PathTooLongException)
3561                     {
3562                         dataStream = null;
3563                     }
3564                 }
3565                         }
3566
3567                         // Try to load image using the Web Request
3568                         if(dataStream == null)
3569                         {
3570                                 Uri     templateUri = null;
3571                 try
3572                 {
3573                     // Try to create URI directly from template URL (will work in case of absolute URL)
3574                     templateUri = new Uri(url);
3575                 }
3576                 catch (UriFormatException)
3577                 {
3578                     templateUri = null;
3579                 }
3580
3581                                 // Make absolute URL using web form document URL
3582                                 if(templateUri == null)
3583                                 {
3584                     if (this.Common != null && this.Common.Chart != null)
3585                                         {
3586                                                 string  webFormUrl = this.Common.Chart.webFormDocumentURL;
3587                                                 int slashIndex = webFormUrl.LastIndexOf('/');
3588                                                 if(slashIndex != -1)
3589                                                 {
3590                                                         webFormUrl = webFormUrl.Substring(0, slashIndex + 1);
3591                                                 }
3592
3593                         try
3594                         {
3595                             templateUri = new Uri(new Uri(webFormUrl), url);
3596                         }
3597                         catch (UriFormatException)
3598                         {
3599                             templateUri = null;
3600                         }
3601                                         }
3602                                 }
3603
3604                                 // Load image from file or web resource
3605                                 if(templateUri != null)
3606                                 {
3607                     try
3608                     {
3609                         WebRequest request = WebRequest.Create(templateUri);
3610                         dataStream = request.GetResponse().GetResponseStream();
3611                     }
3612                     catch (NotSupportedException)
3613                     {
3614                         dataStream = null;
3615                     }
3616                     catch (NotImplementedException)
3617                     {
3618                         dataStream = null;
3619                     }
3620                     catch (SecurityException)
3621                     {
3622                         dataStream = null;
3623                     }
3624                                 }
3625                         }
3626
3627                         // Try to load as file
3628                         if(dataStream == null)
3629                         {
3630                 dataStream = new FileStream(url, FileMode.Open);
3631                         }
3632
3633                         return dataStream;
3634                 }
3635
3636 #endif  // Microsoft_CONTROL
3637
3638
3639
3640 #if !Microsoft_CONTROL
3641
3642
3643         /// <summary>
3644         /// Writes chart map tag into the stream.
3645         /// </summary>
3646         /// <param name="output">Html writer to output the data to.</param>
3647         /// <param name="mapName">Chart map name.</param>
3648         internal void WriteChartMapTag(HtmlTextWriter output, string mapName)
3649                 {
3650             output.WriteLine();
3651             output.AddAttribute(HtmlTextWriterAttribute.Name, mapName);
3652             output.AddAttribute(HtmlTextWriterAttribute.Id, mapName);
3653             output.RenderBeginTag(HtmlTextWriterTag.Map);
3654
3655                         //****************************************************
3656                         //** Fire map areas customize event
3657                         //****************************************************
3658
3659                         // Make sure only non-custom items are passed into the event handler
3660                         MapAreasCollection      custCollection = new MapAreasCollection();
3661
3662                         // Move all non-custom items
3663             for (int index = 0; index < _mapAreas.Count; index++)
3664                         {
3665                 if (!_mapAreas[index].IsCustom)
3666                                 {
3667                     custCollection.Add(_mapAreas[index]);
3668                     _mapAreas.RemoveAt(index);
3669                                         --index;
3670                                 }
3671                         }
3672
3673                         // Call a notification event, so that area items collection can be modified by user
3674             Common.Chart.CallOnCustomizeMapAreas(custCollection);
3675
3676                         // Add customized items
3677                         foreach(MapArea area in custCollection)
3678                         {
3679                                 area.IsCustom = false;
3680                 _mapAreas.Add(area);
3681                         }
3682
3683                         //****************************************************
3684                         //** Add all map areas
3685                         //****************************************************
3686             foreach (MapArea area in _mapAreas)
3687                         {
3688                 area.RenderTag(output, this.Common.Chart);
3689                         }
3690             // if this procedure is enforced to run the image maps have to have at least one map area. 
3691             if (_mapAreas.Count == 0)
3692             {
3693                 output.Write("<area shape=\"rect\" coords=\"0,0,0,0\" alt=\"\" />");
3694             }
3695                         
3696             //****************************************************
3697                         //** End of the map
3698                         //****************************************************
3699             output.RenderEndTag();
3700             
3701                         return;
3702                 }
3703
3704 #endif
3705
3706                 /// <summary>
3707                 /// Returns the default title from Titles collection.
3708                 /// </summary>
3709                 /// <param name="create">Create title if it doesn't exists.</param>
3710                 /// <returns>Default title.</returns>
3711                 internal Title GetDefaultTitle(bool create)
3712                 {
3713                         // Check if default title exists
3714                         Title   defaultTitle = null;
3715                         foreach(Title title in this.Titles)
3716                         {
3717                                 if(title.Name == "Default Title")
3718                                 {
3719                                         defaultTitle = title;
3720                                 }
3721                         }
3722
3723                         // Create new default title
3724                         if(defaultTitle == null && create)
3725                         {
3726                                 defaultTitle = new Title();
3727                                 defaultTitle.Name = "Default Title";
3728                                 this.Titles.Insert(0, defaultTitle);
3729                         }
3730
3731                         return defaultTitle;
3732                 }
3733
3734                 /// <summary>
3735                 /// Checks if tooltips are enabled
3736                 /// </summary>
3737                 /// <returns>true if tooltips enabled</returns>
3738                 private bool IsToolTipsEnabled()
3739                 {
3740                         
3741                         // Data series loop
3742                         foreach( Series series in Common.DataManager.Series )
3743                         {
3744                                 // Check series tooltips
3745                                 if( series.ToolTip.Length > 0)
3746                                 {
3747                                         // ToolTips enabled
3748                                         return true;
3749                                 }
3750
3751                                 // Check series tooltips
3752                                 if( series.LegendToolTip.Length > 0 ||
3753                                         series.LabelToolTip.Length > 0)
3754                                 {
3755                                         // ToolTips enabled
3756                                         return true;
3757                                 }
3758
3759                                 // Check point tooltips only for "non-Fast" chart types
3760                                 if( !series.IsFastChartType() )
3761                                 {
3762                                         // Data point loop
3763                                         foreach( DataPoint point in series.Points )
3764                                         {
3765                                                 // ToolTip empty
3766                                                 if( point.ToolTip.Length > 0)
3767                                                 {
3768                                                         // ToolTips enabled
3769                                                         return true;
3770                                                 }
3771                                                 // ToolTip empty
3772                                                 if( point.LegendToolTip.Length > 0 ||
3773                                                         point.LabelToolTip.Length > 0)
3774                                                 {
3775                                                         // ToolTips enabled
3776                                                         return true;
3777                                                 }
3778                                         }
3779                                 }
3780                         }
3781
3782                         // Legend items loop
3783                         foreach( Legend legend in Legends )
3784                         {
3785                                 foreach( LegendItem legendItem in legend.CustomItems )
3786                                 {
3787                                         // ToolTip empty
3788                                         if( legendItem.ToolTip.Length > 0 )
3789                                         {
3790                                                 return true;
3791                                         }
3792                                 }
3793                         }
3794
3795                         // Title items loop
3796                         foreach( Title title in Titles )
3797                         {
3798                                 // ToolTip empty
3799                                 if( title.ToolTip.Length > 0 )
3800                                 {
3801                                         return true;
3802                                 }
3803                         }
3804
3805                         return false;
3806                 }
3807
3808                 #endregion
3809
3810         #region IDisposable Members
3811         /// <summary>
3812         /// Releases unmanaged and - optionally - managed resources
3813         /// </summary>
3814         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
3815         protected override void Dispose(bool disposing)
3816         {
3817             if (disposing)
3818             {   
3819                 // Dispose managed resources
3820                 if (ChartGraph != null)
3821                 {
3822                     ChartGraph.Dispose();
3823                     ChartGraph = null;
3824                 }
3825                 if (_legends != null)
3826                 {
3827                     _legends.Dispose();
3828                     _legends = null;
3829                 }
3830                 if (_titles != null)
3831                 {
3832                     _titles.Dispose();
3833                     _titles = null;
3834                 }
3835                 if (_chartAreas != null)
3836                 {
3837                     _chartAreas.Dispose();
3838                     _chartAreas = null;
3839                 }
3840                 if (_annotations != null)
3841                 {
3842                     _annotations.Dispose();
3843                     _annotations = null;
3844                 }
3845                 if (hotRegionsList != null)
3846                 {
3847                     hotRegionsList.Dispose();
3848                     hotRegionsList = null;
3849                 }
3850                 if (_fontCache != null)
3851                 {
3852                     _fontCache.Dispose();
3853                     _fontCache = null;
3854                 }
3855                 if (_borderSkin != null)
3856                 {
3857                     _borderSkin.Dispose();
3858                     _borderSkin = null;
3859                 }
3860 #if ! Microsoft_CONTROL
3861                 if (_mapAreas != null)
3862                 {
3863                     _mapAreas.Dispose();
3864                     _mapAreas = null;
3865                 }
3866 #endif
3867
3868 #if Microsoft_CONTROL
3869                 if (nonTopLevelChartBuffer != null)
3870                 {
3871                     nonTopLevelChartBuffer.Dispose();
3872                     nonTopLevelChartBuffer = null;
3873                 }
3874 #endif
3875             }
3876             base.Dispose(disposing);
3877         }
3878
3879         #endregion
3880     }
3881
3882         /// <summary>
3883         /// Event arguments of Chart paint event.
3884         /// </summary>
3885 #if ASPPERM_35
3886         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
3887     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
3888 #endif
3889     public class ChartPaintEventArgs : EventArgs
3890         {
3891                 #region Fields
3892
3893                 // Private fields
3894         private object          _chartElement = null;
3895         private ChartGraphics   _chartGraph = null;
3896                 private CommonElements  _common = null;
3897                 private Chart                   _chart = null;
3898                 private ElementPosition _position = null;
3899
3900                 #endregion
3901
3902                 #region Properties
3903
3904
3905         /// <summary>
3906         /// Gets the chart element of the event.
3907         /// </summary>
3908         /// <value>The chart element.</value>
3909         public object ChartElement
3910         {
3911             get
3912             {
3913                 return _chartElement;
3914             }
3915         } 
3916
3917
3918                 /// <summary>
3919                 /// Gets the ChartGraphics object of the event.
3920                 /// </summary>
3921                 public ChartGraphics ChartGraphics
3922                 {
3923                         get
3924                         {
3925                                 return _chartGraph;
3926                         }
3927                 } 
3928
3929                 /// <summary>
3930                 /// Chart Common elements.
3931                 /// </summary>
3932                 internal CommonElements CommonElements
3933                 {
3934                         get
3935                         {
3936                                 return _common;
3937                         }
3938                 } 
3939
3940                 /// <summary>
3941                 /// Chart element position in relative coordinates of the event.
3942                 /// </summary>
3943                 public ElementPosition Position
3944                 {
3945                         get
3946                         {
3947                 return _position;
3948                         }
3949                 } 
3950
3951                 /// <summary>
3952                 /// Chart object of the event.
3953                 /// </summary>
3954             public  Chart Chart
3955                 {
3956                         get
3957                         {
3958                 if (_chart == null && _common != null)
3959                                 {
3960                     _chart = _common.Chart;
3961                                 }
3962
3963                 return _chart;
3964                         }
3965                 } 
3966
3967                 #endregion
3968
3969                 #region Methods
3970
3971                 /// <summary>
3972                 /// Default constructor is not accessible
3973                 /// </summary>
3974                 private ChartPaintEventArgs()
3975                 {
3976                 }
3977
3978         /// <summary>
3979         /// Paint event arguments constructor.
3980         /// </summary>
3981         /// <param name="chartElement">Chart element.</param>
3982         /// <param name="chartGraph">Chart graphics.</param>
3983         /// <param name="common">Common elements.</param>
3984         /// <param name="position">Position.</param>
3985         internal ChartPaintEventArgs(object chartElement, ChartGraphics chartGraph, CommonElements common, ElementPosition position)
3986                 {
3987             this._chartElement = chartElement;
3988             this._chartGraph = chartGraph;
3989             this._common = common;
3990             this._position = position;
3991                 }
3992
3993                 #endregion
3994         }
3995
3996     /// <summary>
3997     /// Event arguments of localized numbers formatting event.
3998     /// </summary>
3999 #if ASPPERM_35
4000         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
4001     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
4002 #endif
4003     public class FormatNumberEventArgs : EventArgs
4004     {
4005         #region Fields
4006
4007         // Private fields
4008         private double _value;
4009         private string _format;
4010         private string _localizedValue;
4011         private ChartValueType _valueType = ChartValueType.Auto;
4012         private object _senderTag;
4013         private ChartElementType _elementType = ChartElementType.Nothing;
4014
4015         #endregion
4016
4017         #region Properties
4018
4019         /// <summary>
4020         /// Value to be formatted.
4021         /// </summary>
4022         public double Value
4023         {
4024             get { return this._value; }
4025         }
4026
4027         /// <summary>
4028         /// Localized text.
4029         /// </summary>
4030         public string LocalizedValue
4031         {
4032             get { return _localizedValue; }
4033             set { _localizedValue = value; }
4034         }
4035
4036         /// <summary>
4037         /// Format string.
4038         /// </summary>
4039         public string Format
4040         {
4041             get { return _format; }
4042         }
4043
4044         /// <summary>
4045         /// Value type.
4046         /// </summary>
4047         public ChartValueType ValueType
4048         {
4049             get { return _valueType; }
4050         }
4051
4052         /// <summary>
4053         /// The sender object of the event.
4054         /// </summary>
4055         public object SenderTag
4056         {
4057             get { return _senderTag; }
4058         }
4059
4060         /// <summary>
4061         /// Chart element type.
4062         /// </summary>
4063         public ChartElementType ElementType
4064         {
4065             get { return _elementType; }
4066         }
4067
4068         #endregion
4069
4070         #region Methods
4071
4072         /// <summary>
4073         /// Default constructor is not accessible
4074         /// </summary>
4075         private FormatNumberEventArgs()
4076         {
4077         }
4078
4079         /// <summary>
4080         /// Object constructor.
4081         /// </summary>
4082         /// <param name="value">Value to be formatted.</param>
4083         /// <param name="format">Format string.</param>
4084         /// <param name="valueType">Value type..</param>
4085         /// <param name="localizedValue">Localized value.</param>
4086         /// <param name="senderTag">Chart element object tag.</param>
4087         /// <param name="elementType">Chart element type.</param>
4088         internal FormatNumberEventArgs(double value, string format, ChartValueType valueType, string localizedValue, object senderTag, ChartElementType elementType)
4089         {
4090             this._value = value;
4091             this._format = format;
4092             this._valueType = valueType;
4093             this._localizedValue = localizedValue;
4094             this._senderTag = senderTag;
4095             this._elementType = elementType;
4096         }
4097
4098         #endregion
4099     }
4100
4101     #region FontCache
4102     /// <summary>
4103     /// Font cache class helps ChartElements to reuse the Font instances
4104     /// </summary>
4105     internal class FontCache : IDisposable
4106     {
4107         #region Static
4108
4109         // Default font family name
4110         private static string _defaultFamilyName;
4111
4112         /// <summary>
4113         /// Gets the default font family name.
4114         /// </summary>
4115         /// <value>The default font family name.</value>
4116         public static string DefaultFamilyName
4117         {
4118             get
4119             {
4120                 if (_defaultFamilyName == null)
4121                 {
4122                     // Find the "Microsoft Sans Serif" font
4123                     foreach (FontFamily fontFamily in FontFamily.Families)
4124                     {
4125                         if (fontFamily.Name == "Microsoft Sans Serif")
4126                         {
4127                             _defaultFamilyName = fontFamily.Name;
4128                             break;
4129                         }
4130                     }
4131                     // Not found - use the default Sans Serif font
4132                     if (_defaultFamilyName == null)
4133                     {
4134                         _defaultFamilyName = FontFamily.GenericSansSerif.Name;
4135                     }
4136                 }
4137                 return _defaultFamilyName;
4138             }
4139         }
4140         #endregion
4141
4142         #region Fields
4143
4144         // Cached fonts dictionary 
4145         private Dictionary<KeyInfo, Font> _fontCache = new Dictionary<KeyInfo, Font>(new KeyInfo.EqualityComparer());
4146
4147         #endregion // Fields
4148
4149         #region Properties
4150         /// <summary>
4151         /// Gets the default font.
4152         /// </summary>
4153         /// <value>The default font.</value>
4154         public Font DefaultFont 
4155         { 
4156             get { return this.GetFont(DefaultFamilyName, 8);  }
4157         }
4158
4159         /// <summary>
4160         /// Gets the default font.
4161         /// </summary>
4162         /// <value>The default font.</value>
4163         public Font DefaultBoldFont
4164         {
4165             get { return this.GetFont(DefaultFamilyName, 8, FontStyle.Bold); }
4166         }
4167         #endregion
4168
4169         #region Methods
4170
4171         /// <summary>
4172         /// Gets the font.
4173         /// </summary>
4174         /// <param name="familyName">Name of the family.</param>
4175         /// <param name="size">The size.</param>
4176         /// <returns>Font instance</returns>
4177         public Font GetFont(string familyName, int size)
4178         {
4179             KeyInfo key = new KeyInfo(familyName, size);
4180             if (!this._fontCache.ContainsKey(key))
4181             {
4182                 this._fontCache.Add(key, new Font(familyName, size));
4183             }
4184             return this._fontCache[key];
4185         }
4186
4187         /// <summary>
4188         /// Gets the font.
4189         /// </summary>
4190         /// <param name="familyName">Name of the family.</param>
4191         /// <param name="size">The size.</param>
4192         /// <param name="style">The style.</param>
4193         /// <returns>Font instance</returns>
4194         public Font GetFont(string familyName, float size, FontStyle style)
4195         {
4196             KeyInfo key = new KeyInfo(familyName, size, style);
4197             if (!this._fontCache.ContainsKey(key))
4198             {
4199                 this._fontCache.Add(key, new Font(familyName, size, style));
4200             }
4201             return this._fontCache[key];
4202         }
4203
4204         /// <summary>
4205         /// Gets the font.
4206         /// </summary>
4207         /// <param name="family">The family.</param>
4208         /// <param name="size">The size.</param>
4209         /// <param name="style">The style.</param>
4210         /// <returns>Font instance</returns>
4211         public Font GetFont(FontFamily family, float size, FontStyle style)
4212         {
4213             KeyInfo key = new KeyInfo(family, size, style);
4214             if (!this._fontCache.ContainsKey(key))
4215             {
4216                 this._fontCache.Add(key, new Font(family, size, style));
4217             }
4218             return this._fontCache[key];
4219         }
4220
4221         /// <summary>
4222         /// Gets the font.
4223         /// </summary>
4224         /// <param name="family">The family.</param>
4225         /// <param name="size">The size.</param>
4226         /// <param name="style">The style.</param>
4227         /// <param name="unit">The unit.</param>
4228         /// <returns>Font instance</returns>
4229         public Font GetFont(FontFamily family, float size, FontStyle style, GraphicsUnit unit)
4230         {
4231             KeyInfo key = new KeyInfo(family, size, style, unit);
4232             if (!this._fontCache.ContainsKey(key))
4233             {
4234                 this._fontCache.Add(key, new Font(family, size, style, unit));
4235             }
4236             return this._fontCache[key];
4237         }
4238
4239         #endregion
4240
4241         #region IDisposable Members
4242
4243         /// <summary>
4244         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
4245         /// </summary>
4246         public void Dispose()
4247         {
4248             foreach (Font font in _fontCache.Values)
4249             {
4250                 font.Dispose();
4251             }
4252             _fontCache.Clear();
4253             GC.SuppressFinalize(this);
4254         }
4255
4256         #endregion
4257
4258         #region FontKeyInfo struct
4259         /// <summary>
4260         /// Font key info
4261         /// </summary>
4262         private class KeyInfo 
4263         { 
4264             string          _familyName;
4265             float           _size = 8;
4266             GraphicsUnit    _unit = GraphicsUnit.Point;
4267             FontStyle       _style = FontStyle.Regular;
4268             int             _gdiCharSet = 1;
4269
4270             /// <summary>
4271             /// Initializes a new instance of the <see cref="KeyInfo"/> class.
4272             /// </summary>
4273             /// <param name="familyName">Name of the family.</param>
4274             /// <param name="size">The size.</param>
4275             public KeyInfo(string familyName, float size)
4276             {
4277                 this._familyName = familyName;
4278                 this._size = size;
4279             }
4280             /// <summary>
4281             /// Initializes a new instance of the <see cref="KeyInfo"/> class.
4282             /// </summary>
4283             /// <param name="familyName">Name of the family.</param>
4284             /// <param name="size">The size.</param>
4285             /// <param name="style">The style.</param>
4286             public KeyInfo(string familyName, float size, FontStyle style)
4287             {
4288                 this._familyName = familyName;
4289                 this._size = size;
4290                 this._style = style;
4291             }
4292             /// <summary>
4293             /// Initializes a new instance of the <see cref="KeyInfo"/> class.
4294             /// </summary>
4295             /// <param name="family">The family.</param>
4296             /// <param name="size">The size.</param>
4297             /// <param name="style">The style.</param>
4298             public KeyInfo(FontFamily family, float size, FontStyle style)
4299             {
4300                 this._familyName = family.ToString();
4301                 this._size = size;
4302                 this._style = style;
4303             }
4304             /// <summary>
4305             /// Initializes a new instance of the <see cref="KeyInfo"/> class.
4306             /// </summary>
4307             /// <param name="family">The family.</param>
4308             /// <param name="size">The size.</param>
4309             /// <param name="style">The style.</param>
4310             /// <param name="unit">The unit.</param>
4311             public KeyInfo(FontFamily family, float size, FontStyle style, GraphicsUnit unit)
4312             {
4313                 this._familyName = family.ToString();
4314                 this._size = size;
4315                 this._style = style;
4316                 this._unit = unit;
4317             }
4318
4319             #region IEquatable<FontKeyInfo> Members
4320             /// <summary>
4321             /// KeyInfo equality comparer
4322             /// </summary>
4323             internal class EqualityComparer : IEqualityComparer<KeyInfo> 
4324             {
4325                 /// <summary>
4326                 /// Determines whether the specified objects are equal.
4327                 /// </summary>
4328                 /// <param name="x">The first object of type <paramref name="x"/> to compare.</param>
4329                 /// <param name="y">The second object of type <paramref name="y"/> to compare.</param>
4330                 /// <returns>
4331                 /// true if the specified objects are equal; otherwise, false.
4332                 /// </returns>
4333                 public bool Equals(KeyInfo x, KeyInfo y)
4334                 {
4335                     return
4336                         x._size == y._size &&
4337                         x._familyName == y._familyName &&
4338                         x._unit == y._unit &&
4339                         x._style == y._style &&
4340                         x._gdiCharSet == y._gdiCharSet;
4341                 }
4342
4343                 /// <summary>
4344                 /// Returns a hash code for the specified object.
4345                 /// </summary>
4346                 /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
4347                 /// <returns>A hash code for the specified object.</returns>
4348                 /// <exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception>
4349                 public int GetHashCode(KeyInfo obj)
4350                 {
4351                     return obj._familyName.GetHashCode() ^ obj._size.GetHashCode();
4352                 }
4353             }
4354             #endregion
4355         }
4356         #endregion
4357     }
4358     #endregion
4359
4360
4361 }