MSChartObject.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. using System;
  2. using System.Collections.Generic;
  3. using FastReport.DataVisualization.Charting;
  4. using System.IO;
  5. using System.Drawing;
  6. using System.ComponentModel;
  7. using FastReport.Utils;
  8. using FastReport.Data;
  9. using System.Drawing.Drawing2D;
  10. using System.Drawing.Design;
  11. namespace FastReport.MSChart
  12. {
  13. /// <summary>
  14. /// Represents the chart object based on Microsoft Chart control.
  15. /// </summary>
  16. /// <remarks>
  17. /// FastReport uses Microsoft Chart library to display charts. This library is included
  18. /// in .Net Framework 4.0. For .Net 3.5 it is available as a separate download here:
  19. /// http://www.microsoft.com/downloads/details.aspx?FamilyID=130f7986-bf49-4fe5-9ca8-910ae6ea442c
  20. /// <para/><note type="caution">This library requires .Net Framework 3.5 SP1.</note>
  21. /// <para/>To access Microsoft Chart object, use the <see cref="Chart"/> property. It allows you
  22. /// to set up chart appearance. For more information on available properties, refer to the
  23. /// MS Chart documentation.
  24. /// <para/>Chart object may contain one or several <i>series</i>. Each series is represented by two objects:
  25. /// <list type="bullet">
  26. /// <item>
  27. /// <description>the <b>Series</b> that is handled by MS Chart. It is stored in the
  28. /// <b>Chart.Series</b> collection;</description>
  29. /// </item>
  30. /// <item>
  31. /// <description>the <see cref="MSChartSeries"/> object that provides data for MS Chart series.
  32. /// It is stored in the <see cref="Series"/> collection.</description>
  33. /// </item>
  34. /// </list>
  35. /// <para/>Do not operate series objects directly. To add or remove series, use
  36. /// the <see cref="AddSeries"/> and <see cref="DeleteSeries"/> methods. These methods
  37. /// handle <b>Series</b> and <b>MSChartSeries</b> in sync.
  38. /// <para/>If you have a chart object on your Form and want to print it in FastReport, use
  39. /// the <see cref="AssignChart"/> method.
  40. /// </remarks>
  41. public partial class MSChartObject : ReportComponentBase, IParent
  42. {
  43. #region Fields
  44. private SeriesCollection series;
  45. private Chart chart;
  46. private DataSourceBase dataSource;
  47. private string filter;
  48. private bool alignXValues;
  49. private string autoSeriesColumn;
  50. private string autoSeriesColor;
  51. private SortOrder autoSeriesSortOrder;
  52. private bool startAutoSeries;
  53. private MemoryStream originalChartStream;
  54. private DataPoint hotPoint;
  55. private bool autoSeriesForce;
  56. private bool isPainting;
  57. #endregion
  58. #region Properties
  59. /// <summary>
  60. /// Gets the collection of <see cref="MSChartSeries"/> objects.
  61. /// </summary>
  62. [Browsable(false)]
  63. public SeriesCollection Series
  64. {
  65. get { return series; }
  66. }
  67. /// <summary>
  68. /// Gets a reference to the MS Chart object.
  69. /// </summary>
  70. [Category("Appearance")]
  71. public Chart Chart
  72. {
  73. get { return chart; }
  74. }
  75. /// <summary>
  76. /// Gets or set Force automatically created series.
  77. /// </summary>
  78. [Category("Data")]
  79. [DefaultValue(false)]
  80. public bool AutoSeriesForce
  81. {
  82. get { return autoSeriesForce; }
  83. set { autoSeriesForce = value; }
  84. }
  85. /// <summary>
  86. /// Gets or sets the data source.
  87. /// </summary>
  88. [Category("Data")]
  89. public DataSourceBase DataSource
  90. {
  91. get { return dataSource; }
  92. set { dataSource = value; }
  93. }
  94. /// <summary>
  95. /// Gets or sets the filter expression.
  96. /// </summary>
  97. /// <remarks>
  98. /// This filter will be applied to all series in chart. You may also use the series'
  99. /// <see cref="MSChartSeries.Filter"/> property to filter each series individually.
  100. /// </remarks>
  101. [Category("Data")]
  102. [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
  103. public string Filter
  104. {
  105. get { return filter; }
  106. set { filter = value; }
  107. }
  108. /// <summary>
  109. /// Gets or sets a value indicating that all series' data point should be aligned by its X value.
  110. /// </summary>
  111. /// <remarks>
  112. /// Using this property is necessary to print stacked type series. These series must have
  113. /// equal number of data points, and the order of data points must be the same for all series.
  114. /// </remarks>
  115. [Category("Data")]
  116. [DefaultValue(false)]
  117. public bool AlignXValues
  118. {
  119. get { return alignXValues; }
  120. set { alignXValues = value; }
  121. }
  122. /// <summary>
  123. /// Gets or set the data column or expression for automatically created series.
  124. /// </summary>
  125. /// <remarks>
  126. /// In order to create auto-series, you need to define one series that will be used as a
  127. /// template for new series, and set up the <see cref="AutoSeriesColumn"/> property.
  128. /// The value of this property will be a name of new series. If there is no series
  129. /// with such name yet, the new series will be added.
  130. /// </remarks>
  131. [Category("Data")]
  132. [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
  133. public string AutoSeriesColumn
  134. {
  135. get { return autoSeriesColumn; }
  136. set { autoSeriesColumn = value; }
  137. }
  138. /// <summary>
  139. /// Gets or set the color for auto-series.
  140. /// </summary>
  141. /// <remarks>
  142. /// If no color is specified, the new series will use the palette defined in the chart.
  143. /// </remarks>
  144. [Category("Data")]
  145. [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
  146. public string AutoSeriesColor
  147. {
  148. get { return autoSeriesColor; }
  149. set { autoSeriesColor = value; }
  150. }
  151. /// <summary>
  152. /// Gets or sets sort order for auto-series.
  153. /// </summary>
  154. [Category("Data")]
  155. [DefaultValue(SortOrder.None)]
  156. public SortOrder AutoSeriesSortOrder
  157. {
  158. get { return autoSeriesSortOrder; }
  159. set { autoSeriesSortOrder = value; }
  160. }
  161. private DataPoint HotPoint
  162. {
  163. get { return hotPoint; }
  164. set
  165. {
  166. if (hotPoint != value)
  167. {
  168. if (Page != null)
  169. Page.Refresh();
  170. }
  171. hotPoint = value;
  172. }
  173. }
  174. private BandBase ParentBand
  175. {
  176. get
  177. {
  178. BandBase parentBand = this.Band;
  179. if (parentBand is ChildBand)
  180. parentBand = (parentBand as ChildBand).GetTopParentBand;
  181. return parentBand;
  182. }
  183. }
  184. private bool IsOnFooter
  185. {
  186. get { return ParentBand is GroupFooterBand || ParentBand is DataFooterBand; }
  187. }
  188. #endregion
  189. #region Private Methods
  190. private void SetChartDefaults()
  191. {
  192. ChartArea area = new ChartArea("Default");
  193. chart.ChartAreas.Add(area);
  194. area.AxisX.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
  195. area.AxisY.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
  196. area.AxisX2.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
  197. area.AxisY2.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
  198. Legend legend = new Legend("Default");
  199. chart.Legends.Add(legend);
  200. Title title = new Title();
  201. chart.Titles.Add(title);
  202. title.Visible = false;
  203. chart.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
  204. chart.BorderlineColor = Color.DarkGray;
  205. chart.BorderlineDashStyle = ChartDashStyle.Solid;
  206. chart.BorderlineWidth = 2;
  207. }
  208. private void ClearAutoSeries()
  209. {
  210. startAutoSeries = true;
  211. if (!String.IsNullOrEmpty(autoSeriesColumn) && !autoSeriesForce)
  212. {
  213. for (int i = 1; i < Chart.Series.Count; i++)
  214. {
  215. DeleteSeries(i);
  216. }
  217. }
  218. }
  219. private MSChartSeries CloneSeries(MSChartSeries source, int number)
  220. {
  221. MSChartSeries series = AddSeries(source.SeriesSettings.ChartType);
  222. series.Assign(source);
  223. Chart tempChart = new Chart();
  224. originalChartStream.Position = 0;
  225. tempChart.Serializer.Content = SerializationContents.All;
  226. tempChart.Serializer.Load(originalChartStream);
  227. Series tempSeries = tempChart.Series[number];
  228. tempChart.Series.Remove(tempSeries);
  229. tempSeries.Name = "";
  230. Series tempSeries1 = chart.Series[chart.Series.Count - 1];
  231. chart.Series.Remove(tempSeries1);
  232. chart.Series.Add(tempSeries);
  233. tempSeries.Points.Clear();
  234. tempChart.Dispose();
  235. tempSeries1.Dispose();
  236. return series;
  237. }
  238. private IEnumerable<MSChartSeries> MakeAutoSeries(object autoSeriesKey, MSChartSeries[] serieses)
  239. {
  240. if (serieses == null)
  241. {
  242. string seriesName = autoSeriesKey.ToString();
  243. MSChartSeries series = null;
  244. if (startAutoSeries)
  245. series = Series[0];
  246. else
  247. {
  248. bool found = false;
  249. foreach (MSChartSeries s in Series)
  250. {
  251. if (s.SeriesSettings.Name == seriesName)
  252. {
  253. series = s;
  254. found = true;
  255. break;
  256. }
  257. }
  258. if (!found)
  259. {
  260. series = CloneSeries(Series[0], 0);
  261. if (!String.IsNullOrEmpty(AutoSeriesColor))
  262. {
  263. object color = Report.Calc(AutoSeriesColor);
  264. if (color is Color)
  265. series.SeriesSettings.Color = (Color)color;
  266. }
  267. }
  268. }
  269. series.SeriesSettings.Name = seriesName;
  270. startAutoSeries = false;
  271. yield return series;
  272. }
  273. else
  274. {
  275. for (int i = 0; i < serieses.Length; i++)
  276. {
  277. string seriesName = autoSeriesKey.ToString();
  278. if (!String.IsNullOrEmpty(Series[i].AutoSeriesColumn))
  279. seriesName = Report.Calc(Series[i].AutoSeriesColumn).ToString();
  280. MSChartSeries series = null;
  281. if (startAutoSeries || !serieses[i].AutoSeriesForce)
  282. series = serieses[i];
  283. else
  284. {
  285. bool found = false;
  286. foreach (MSChartSeries s in Series)
  287. {
  288. if (s.SeriesSettings.Name == seriesName)
  289. {
  290. series = s;
  291. found = true;
  292. break;
  293. }
  294. }
  295. if (!found)
  296. {
  297. series = CloneSeries(serieses[i], i);
  298. if (!String.IsNullOrEmpty(AutoSeriesColor))
  299. {
  300. object color = Report.Calc(AutoSeriesColor);
  301. if (color is Color)
  302. series.SeriesSettings.Color = (Color)color;
  303. }
  304. }
  305. }
  306. if (serieses[i].AutoSeriesForce)
  307. series.SeriesSettings.Name = seriesName;
  308. yield return series;
  309. }
  310. startAutoSeries = false;
  311. }
  312. }
  313. private void SortAutoSeries()
  314. {
  315. // create a list of series
  316. List<SeriesInfo> sortedList = new List<SeriesInfo>();
  317. foreach (MSChartSeries series in Series)
  318. {
  319. sortedList.Add(new SeriesInfo(series));
  320. }
  321. sortedList.Sort(new SeriesComparer(AutoSeriesSortOrder));
  322. // delete original series
  323. while (Series.Count > 0)
  324. {
  325. Series.RemoveAt(0);
  326. chart.Series.RemoveAt(0);
  327. }
  328. // add them in correct order
  329. foreach (SeriesInfo info in sortedList)
  330. {
  331. Series.Add(info.Series);
  332. chart.Series.Add(info.ChartSeries);
  333. }
  334. }
  335. private void WireEvents(bool wire)
  336. {
  337. DataBand dataBand = null;
  338. if (ParentBand is GroupFooterBand)
  339. dataBand = ((ParentBand as GroupFooterBand).Parent as GroupHeaderBand).GroupDataBand;
  340. else if (ParentBand is DataFooterBand)
  341. dataBand = ParentBand.Parent as DataBand;
  342. // wire/unwire events
  343. if (dataBand != null)
  344. {
  345. if (wire)
  346. dataBand.BeforePrint += new EventHandler(dataBand_BeforePrint);
  347. else
  348. dataBand.BeforePrint -= new EventHandler(dataBand_BeforePrint);
  349. }
  350. }
  351. private void dataBand_BeforePrint(object sender, EventArgs e)
  352. {
  353. bool firstRow = (sender as DataBand).IsFirstRow;
  354. if (firstRow)
  355. Series.ResetData();
  356. object match = true;
  357. if (!String.IsNullOrEmpty(Filter))
  358. match = Report.Calc(Filter);
  359. if (match is bool && (bool)match == true)
  360. Series.ProcessData();
  361. }
  362. #endregion
  363. #region Protected Methods
  364. /// <inheritdoc/>
  365. protected override void Dispose(bool disposing)
  366. {
  367. if (disposing && chart != null)
  368. {
  369. chart.OnModifing -= Chart_OnModifing;
  370. chart.Dispose();
  371. chart = null;
  372. }
  373. base.Dispose(disposing);
  374. }
  375. #endregion
  376. #region Public Methods
  377. /// <summary>
  378. /// Adds a new series.
  379. /// </summary>
  380. /// <param name="chartType">The type of series.</param>
  381. /// <returns>The new <b>MSChartSeries</b> object.</returns>
  382. public MSChartSeries AddSeries(SeriesChartType chartType)
  383. {
  384. if (chart.ChartAreas.Count == 0)
  385. SetChartDefaults();
  386. Series chartSeries = new Series();
  387. chartSeries.ChartType = chartType;
  388. chart.Series.Add(chartSeries);
  389. MSChartSeries series = new MSChartSeries();
  390. Series.Add(series);
  391. series.CreateUniqueName();
  392. return series;
  393. }
  394. /// <summary>
  395. /// Deletes a series at a specified index.
  396. /// </summary>
  397. /// <param name="index">Index of series.</param>
  398. public void DeleteSeries(int index)
  399. {
  400. if (index >= 0 && index < chart.Series.Count)
  401. {
  402. Series series = chart.Series[index];
  403. chart.Series.RemoveAt(index);
  404. series.Dispose();
  405. }
  406. if (index >= 0 && index < Series.Count)
  407. {
  408. Series.RemoveAt(index);
  409. }
  410. }
  411. /// <summary>
  412. /// Assigns chart appearance, series and data from the
  413. /// <b>System.Windows.Forms.DataVisualization.Charting.Chart</b> object.
  414. /// </summary>
  415. /// <param name="sourceChart">Chart object to assign data from.</param>
  416. /// <remarks>
  417. /// Use this method if you have a chart in your application and want to print it in FastReport.
  418. /// To do this, put an empty MSChartObject in your report and execute the following code:
  419. /// <code>
  420. /// report.Load("...");
  421. /// MSChartObject reportChart = report.FindObject("MSChart1") as MSChartObject;
  422. /// reportChart.AssignChart(applicationChart);
  423. /// report.Show();
  424. /// </code>
  425. /// </remarks>
  426. public void AssignChart(Chart sourceChart)
  427. {
  428. using (MemoryStream ms = new MemoryStream())
  429. {
  430. sourceChart.Serializer.Content = SerializationContents.All;
  431. sourceChart.Serializer.Save(ms);
  432. ms.Position = 0;
  433. Chart.Serializer.Load(ms);
  434. }
  435. }
  436. /// <inheritdoc/>
  437. public override void Assign(Base source)
  438. {
  439. base.Assign(source);
  440. MSChartObject src = source as MSChartObject;
  441. DataSource = src.DataSource;
  442. Filter = src.Filter;
  443. AlignXValues = src.AlignXValues;
  444. AutoSeriesForce = src.AutoSeriesForce;
  445. AutoSeriesColumn = src.AutoSeriesColumn;
  446. AutoSeriesColor = src.AutoSeriesColor;
  447. AutoSeriesSortOrder = src.AutoSeriesSortOrder;
  448. using (MemoryStream stream = new MemoryStream())
  449. {
  450. src.Chart.Serializer.Content = SerializationContents.All;
  451. src.Chart.Serializer.Save(stream);
  452. stream.Position = 0;
  453. Chart.Serializer.Reset();
  454. Chart.Serializer.Load(stream);
  455. }
  456. }
  457. private Font NewFontDpi(Font prototype)
  458. {
  459. return new Font(prototype.Name, prototype.Size * 96f / DrawUtils.ScreenDpi, prototype.Style);
  460. }
  461. private Font OldFontDpi(Font prototype)
  462. {
  463. return new Font(prototype.Name, prototype.Size * DrawUtils.ScreenDpi / 96f, prototype.Style);
  464. }
  465. /// <inheritdoc/>
  466. public override void Draw(FRPaintEventArgs e)
  467. {
  468. isPainting = true;
  469. base.Draw(e);
  470. Rectangle chartRect = new Rectangle((int)Math.Round(AbsLeft), (int)Math.Round(AbsTop),
  471. (int)Math.Round(Width), (int)Math.Round(Height));
  472. IGraphicsState state = e.Graphics.Save();
  473. try
  474. {
  475. if (IsPrinting)
  476. {
  477. /* chartRect = new Rectangle((int)Math.Round(AbsLeft * e.ScaleX), (int)Math.Round(AbsTop * e.ScaleY),
  478. (int)Math.Round(Width * e.ScaleX), (int)Math.Round(Height * e.ScaleY));
  479. // workaround the MS Chart bug - series border is not scaled properly
  480. int[] borderWidths = new int[Series.Count];
  481. for (int i = 0; i < Series.Count; i++)
  482. {
  483. int borderWidth = Series[i].SeriesSettings.BorderWidth;
  484. borderWidths[i] = borderWidth;
  485. Series[i].SeriesSettings.BorderWidth = (int)Math.Round(borderWidth * e.ScaleX);
  486. }
  487. FChart.Printing.PrintPaint(e.Graphics, chartRect);
  488. for (int i = 0; i < Series.Count; i++)
  489. {
  490. Series[i].SeriesSettings.BorderWidth = borderWidths[i];
  491. }*/
  492. // PrintPaint method is buggy when printing directly on printer's canvas.
  493. // We use temp bitmap instead.
  494. using (Bitmap bmp = new Bitmap((int)Math.Round(Width * e.ScaleX), (int)Math.Round(Height * e.ScaleY)))
  495. using (GdiGraphics g = new GdiGraphics(bmp))
  496. {
  497. g.ScaleTransform(e.ScaleX, e.ScaleY);
  498. chart.Printing.PrintPaint(g, new Rectangle(0, 0, (int)Math.Round(Width), (int)Math.Round(Height)));
  499. e.Graphics.DrawImage(bmp, new RectangleF((int)Math.Round(AbsLeft * e.ScaleX), (int)Math.Round(AbsTop * e.ScaleY),
  500. (int)Math.Round(Width * e.ScaleX), (int)Math.Round(Height * e.ScaleY)),
  501. new RectangleF(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
  502. }
  503. }
  504. else
  505. {
  506. bool needScaleFont = DrawUtils.ScreenDpi != 96 && chart.Titles.Count > 0 && chart.Legends.Count > 0 && chart.ChartAreas.Count > 0 && chart.Series.Count > 0;
  507. e.Graphics.ScaleTransform(e.ScaleX, e.ScaleY);
  508. Color saveBackSecondaryColor = Color.Empty;
  509. ChartHatchStyle saveBackHatchStyle = ChartHatchStyle.None;
  510. Color saveBorderColor = Color.Empty;
  511. ChartDashStyle saveBorderStyle = ChartDashStyle.NotSet;
  512. int saveBorderWidth = 0;
  513. if (HotPoint != null)
  514. {
  515. saveBackSecondaryColor = HotPoint.BackSecondaryColor;
  516. saveBackHatchStyle = HotPoint.BackHatchStyle;
  517. saveBorderColor = HotPoint.BorderColor;
  518. saveBorderStyle = HotPoint.BorderDashStyle;
  519. saveBorderWidth = HotPoint.BorderWidth;
  520. HotPoint.BackHatchStyle = ChartHatchStyle.LightUpwardDiagonal;
  521. HotPoint.BackSecondaryColor = Color.White;
  522. HotPoint.BorderColor = Color.Orange;
  523. HotPoint.BorderDashStyle = ChartDashStyle.Solid;
  524. HotPoint.BorderWidth = 2;
  525. }
  526. // scale chart fonts
  527. if (needScaleFont)
  528. {
  529. foreach (Title t in chart.Titles) t.Font = NewFontDpi(t.Font);
  530. foreach (Legend l in chart.Legends) { l.Font = NewFontDpi(l.Font); l.TitleFont = NewFontDpi(l.TitleFont); }
  531. foreach (ChartArea a in chart.ChartAreas) foreach (Axis ax in a.Axes) { ax.LabelStyle.Font = NewFontDpi(ax.LabelStyle.Font); ax.TitleFont = NewFontDpi(ax.TitleFont); }
  532. foreach (Series s in chart.Series) s.Font = NewFontDpi(s.Font);
  533. }
  534. chart.Printing.PrintPaint(e.Graphics, chartRect);
  535. // set chart fonts back
  536. if (needScaleFont)
  537. {
  538. foreach (Title t in chart.Titles) t.Font = OldFontDpi(t.Font);
  539. foreach (Legend l in chart.Legends) { l.Font = OldFontDpi(l.Font); l.TitleFont = OldFontDpi(l.TitleFont); }
  540. foreach (ChartArea a in chart.ChartAreas) foreach (Axis ax in a.Axes) { ax.LabelStyle.Font = OldFontDpi(ax.LabelStyle.Font); ax.TitleFont = OldFontDpi(ax.TitleFont); }
  541. foreach (Series s in chart.Series) s.Font = OldFontDpi(s.Font);
  542. }
  543. if (HotPoint != null)
  544. {
  545. HotPoint.BackSecondaryColor = saveBackSecondaryColor;
  546. HotPoint.BackHatchStyle = saveBackHatchStyle;
  547. HotPoint.BorderColor = saveBorderColor;
  548. HotPoint.BorderDashStyle = saveBorderStyle;
  549. HotPoint.BorderWidth = saveBorderWidth;
  550. }
  551. }
  552. }
  553. catch (Exception ex)
  554. {
  555. using (StringFormat sf = new StringFormat())
  556. {
  557. sf.Alignment = StringAlignment.Center;
  558. sf.LineAlignment = StringAlignment.Center;
  559. e.Graphics.DrawString(ex.Message, DrawUtils.DefaultFont, Brushes.Red, chartRect, sf);
  560. }
  561. }
  562. finally
  563. {
  564. e.Graphics.Restore(state);
  565. DrawMarkers(e);
  566. Border.Draw(e, chartRect);
  567. isPainting = false;
  568. }
  569. }
  570. /// <inheritdoc/>
  571. public override void Serialize(FRWriter writer)
  572. {
  573. MSChartObject c = writer.DiffObject as MSChartObject;
  574. base.Serialize(writer);
  575. if (DataSource != null)
  576. writer.WriteRef("DataSource", DataSource);
  577. if (Filter != c.Filter)
  578. writer.WriteStr("Filter", Filter);
  579. if (AlignXValues != c.AlignXValues)
  580. writer.WriteBool("AlignXValues", AlignXValues);
  581. if (AutoSeriesColumn != c.AutoSeriesColumn)
  582. writer.WriteStr("AutoSeriesColumn", AutoSeriesColumn);
  583. if (AutoSeriesColor != c.AutoSeriesColor)
  584. writer.WriteStr("AutoSeriesColor", AutoSeriesColor);
  585. if (AutoSeriesSortOrder != c.AutoSeriesSortOrder)
  586. writer.WriteValue("AutoSeriesSortOrder", AutoSeriesSortOrder);
  587. if (AutoSeriesForce)
  588. writer.WriteBool("AutoSeriesForce", AutoSeriesForce);
  589. using (MemoryStream stream = new MemoryStream())
  590. {
  591. chart.Serializer.Content = SerializationContents.All;
  592. chart.Serializer.Save(stream);
  593. stream.Position = 0;
  594. writer.WriteValue("ChartData", stream);
  595. }
  596. }
  597. /// <inheritdoc/>
  598. public override void Deserialize(FRReader reader)
  599. {
  600. base.Deserialize(reader);
  601. if (reader.HasProperty("ChartData"))
  602. {
  603. string streamStr = reader.ReadStr("ChartData");
  604. using (MemoryStream stream = Converter.FromString(typeof(Stream), streamStr) as MemoryStream)
  605. {
  606. chart.Serializer.Reset();
  607. chart.Serializer.Load(stream);
  608. }
  609. }
  610. }
  611. #endregion
  612. #region Report Engine
  613. /// <inheritdoc/>
  614. public override void InitializeComponent()
  615. {
  616. base.InitializeComponent();
  617. WireEvents(true);
  618. }
  619. /// <inheritdoc/>
  620. public override void FinalizeComponent()
  621. {
  622. base.FinalizeComponent();
  623. WireEvents(false);
  624. }
  625. /// <inheritdoc/>
  626. public override string[] GetExpressions()
  627. {
  628. List<string> expressions = new List<string>();
  629. expressions.AddRange(base.GetExpressions());
  630. if (!String.IsNullOrEmpty(Filter))
  631. expressions.Add(Filter);
  632. return expressions.ToArray();
  633. }
  634. /// <inheritdoc/>
  635. public override void SaveState()
  636. {
  637. base.SaveState();
  638. if (!String.IsNullOrEmpty(AutoSeriesColumn))
  639. {
  640. ClearAutoSeries();
  641. originalChartStream = new MemoryStream();
  642. chart.Serializer.Content = SerializationContents.All;
  643. chart.Serializer.Save(originalChartStream);
  644. }
  645. }
  646. /// <inheritdoc/>
  647. public override void RestoreState()
  648. {
  649. base.RestoreState();
  650. ClearAutoSeries();
  651. if (originalChartStream != null)
  652. {
  653. originalChartStream.Dispose();
  654. originalChartStream = null;
  655. }
  656. }
  657. /// <inheritdoc/>
  658. public override void GetData()
  659. {
  660. base.GetData();
  661. MSChartSeries[] serieses = null;
  662. if (AutoSeriesForce)
  663. {
  664. serieses = new MSChartSeries[Series.Count];
  665. for (int i = 0; i < Series.Count; i++)
  666. serieses[i] = Series[i];
  667. }
  668. if (DataSource != null && !IsOnFooter)
  669. {
  670. Series.ResetData();
  671. DataSource.Init(Filter);
  672. DataSource.First();
  673. while (DataSource.HasMoreRows)
  674. {
  675. if (!String.IsNullOrEmpty(AutoSeriesColumn))
  676. {
  677. object autoSeriesKey = Report.Calc(AutoSeriesColumn);
  678. if (autoSeriesKey != null)
  679. {
  680. foreach (MSChartSeries series in MakeAutoSeries(autoSeriesKey, serieses))
  681. series.ProcessData();
  682. }
  683. }
  684. else
  685. Series.ProcessData();
  686. DataSource.Next();
  687. }
  688. }
  689. Series.FinishData();
  690. if (AlignXValues)
  691. Chart.AlignDataPointsByAxisLabel();
  692. if (!String.IsNullOrEmpty(AutoSeriesColumn) && AutoSeriesSortOrder != SortOrder.None)
  693. SortAutoSeries();
  694. }
  695. #endregion
  696. #region IParent Members
  697. /// <inheritdoc/>
  698. public bool CanContain(Base child)
  699. {
  700. return child is MSChartSeries;
  701. }
  702. /// <inheritdoc/>
  703. public void GetChildObjects(ObjectCollection list)
  704. {
  705. foreach (MSChartSeries series in Series)
  706. {
  707. list.Add(series);
  708. }
  709. }
  710. /// <inheritdoc/>
  711. public void AddChild(Base child)
  712. {
  713. if (child is MSChartSeries)
  714. Series.Add(child as MSChartSeries);
  715. }
  716. /// <inheritdoc/>
  717. public void RemoveChild(Base child)
  718. {
  719. if (child is MSChartSeries)
  720. Series.Remove(child as MSChartSeries);
  721. }
  722. /// <inheritdoc/>
  723. public int GetChildOrder(Base child)
  724. {
  725. if (child is MSChartSeries)
  726. return Series.IndexOf(child as MSChartSeries);
  727. return 0;
  728. }
  729. /// <inheritdoc/>
  730. public void SetChildOrder(Base child, int order)
  731. {
  732. }
  733. /// <inheritdoc/>
  734. public void UpdateLayout(float dx, float dy)
  735. {
  736. }
  737. #endregion
  738. /// <summary>
  739. /// Initializes a new instance of the <see cref="MSChartObject"/> with default settings.
  740. /// </summary>
  741. public MSChartObject()
  742. {
  743. series = new SeriesCollection(this);
  744. chart = new Chart();
  745. FlagProvidesHyperlinkValue = true;
  746. chart.OnModifing += Chart_OnModifing;
  747. }
  748. private void Chart_OnModifing(object sender, EventArgs e)
  749. {
  750. #if !FRCORE
  751. if (Report != null && Report.Designer != null && IsDesigning && !isPainting)
  752. Report.Designer.SetModified();
  753. #endif
  754. }
  755. }
  756. /// <summary>
  757. /// Represents the small chart object (called sparkline) fully based on MSChartObject.
  758. /// </summary>
  759. public partial class SparklineObject : MSChartObject
  760. {
  761. /// <summary>
  762. /// Initializes a new instance of the <see cref="SparklineObject"/> with default settings.
  763. /// </summary>
  764. public SparklineObject()
  765. {
  766. }
  767. }
  768. }