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