MSChartObject.cs 26 KB

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