DataBand.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using FastReport.Utils;
  5. using FastReport.Data;
  6. using System.Drawing.Design;
  7. namespace FastReport
  8. {
  9. /// <summary>
  10. /// This class represents the Data band.
  11. /// </summary>
  12. /// <remarks>
  13. /// Use the <see cref="DataSource"/> property to connect the band to a datasource. Set the
  14. /// <see cref="Filter"/> property if you want to filter data rows. The <see cref="Sort"/>
  15. /// property can be used to sort data rows.
  16. /// </remarks>
  17. public partial class DataBand : BandBase
  18. {
  19. #region Fields
  20. private DataHeaderBand header;
  21. private DataFooterBand footer;
  22. private BandCollection bands;
  23. private DataSourceBase dataSource;
  24. private SortCollection sort;
  25. private string filter;
  26. private BandColumns columns;
  27. private bool printIfDetailEmpty;
  28. private bool printIfDatasourceEmpty;
  29. private bool keepTogether;
  30. private bool keepDetail;
  31. private string idColumn;
  32. private string parentIdColumn;
  33. private float indent;
  34. private bool keepSummary;
  35. private Relation relation;
  36. private bool collectChildRows;
  37. private int rowCount;
  38. private int maxRows;
  39. private bool resetPageNumber;
  40. #endregion
  41. #region Properties
  42. /// <summary>
  43. /// Gets or sets a header band.
  44. /// </summary>
  45. [Browsable(false)]
  46. public DataHeaderBand Header
  47. {
  48. get { return header; }
  49. set
  50. {
  51. SetProp(header, value);
  52. header = value;
  53. }
  54. }
  55. /// <summary>
  56. /// Gets a collection of detail bands.
  57. /// </summary>
  58. [Browsable(false)]
  59. public BandCollection Bands
  60. {
  61. get { return bands; }
  62. }
  63. /// <summary>
  64. /// Gets or sets a footer band.
  65. /// </summary>
  66. [Browsable(false)]
  67. public DataFooterBand Footer
  68. {
  69. get { return footer; }
  70. set
  71. {
  72. SetProp(footer, value);
  73. footer = value;
  74. }
  75. }
  76. /// <summary>
  77. /// Gets or sets a data source.
  78. /// Please note: data source have to be enabled.
  79. /// </summary>
  80. [Category("Data")]
  81. public DataSourceBase DataSource
  82. {
  83. get
  84. {
  85. if (dataSource != null && !dataSource.Enabled)
  86. return null;
  87. return dataSource;
  88. }
  89. set
  90. {
  91. if (dataSource != value)
  92. {
  93. if (dataSource != null)
  94. dataSource.Disposed -= new EventHandler(DataSource_Disposed);
  95. if (value != null)
  96. value.Disposed += new EventHandler(DataSource_Disposed);
  97. }
  98. dataSource = value;
  99. }
  100. }
  101. /// <summary>
  102. /// Gets or sets a number of rows in the virtual data source.
  103. /// </summary>
  104. /// <remarks>
  105. /// Use this property if your data band is not connected to any data source. In this case
  106. /// the virtual data source with the specified number of rows will be used.
  107. /// </remarks>
  108. [Category("Data")]
  109. [DefaultValue(1)]
  110. public int RowCount
  111. {
  112. get { return rowCount; }
  113. set { rowCount = value; }
  114. }
  115. /// <summary>
  116. /// Limits the maximum number of rows in a datasource. 0 means no limit.
  117. /// </summary>
  118. [Category("Data")]
  119. [DefaultValue(0)]
  120. public int MaxRows
  121. {
  122. get { return maxRows; }
  123. set { maxRows = value; }
  124. }
  125. /// <summary>
  126. /// Gets or sets a relation used to establish a master-detail relationship between
  127. /// this band and its parent.
  128. /// </summary>
  129. /// <remarks>
  130. /// Use this property if there are several relations exist between two data sources.
  131. /// If there is only one relation (in most cases it is), you can leave this property empty.
  132. /// </remarks>
  133. [Category("Data")]
  134. [Editor("FastReport.TypeEditors.RelationEditor, FastReport", typeof(UITypeEditor))]
  135. public Relation Relation
  136. {
  137. get { return relation; }
  138. set { relation = value; }
  139. }
  140. /// <summary>
  141. /// Gets the collection of sort conditions.
  142. /// </summary>
  143. [Browsable(false)]
  144. public SortCollection Sort
  145. {
  146. get { return sort; }
  147. }
  148. /// <summary>
  149. /// Gets the row filter expression.
  150. /// </summary>
  151. /// <remarks>
  152. /// This property can contain any valid boolean expression. If the expression returns <b>false</b>,
  153. /// the corresponding data row will not be printed.
  154. /// </remarks>
  155. [Category("Data")]
  156. [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
  157. public string Filter
  158. {
  159. get { return filter; }
  160. set { filter = value; }
  161. }
  162. /// <summary>
  163. /// Gets the band columns.
  164. /// </summary>
  165. [Category("Appearance")]
  166. [Editor("FastReport.TypeEditors.DataBandColumnEditor, FastReport", typeof(UITypeEditor))]
  167. public BandColumns Columns
  168. {
  169. get { return columns; }
  170. }
  171. /// <summary>
  172. /// Gets or sets a value that determines whether to print a band if all its detail rows are empty.
  173. /// </summary>
  174. [DefaultValue(false)]
  175. [Category("Behavior")]
  176. public bool PrintIfDetailEmpty
  177. {
  178. get { return printIfDetailEmpty; }
  179. set { printIfDetailEmpty = value; }
  180. }
  181. /// <summary>
  182. /// Gets or sets a value that determines whether to print a band if its datasource is empty.
  183. /// </summary>
  184. [DefaultValue(false)]
  185. [Category("Behavior")]
  186. public bool PrintIfDatasourceEmpty
  187. {
  188. get { return printIfDatasourceEmpty; }
  189. set { printIfDatasourceEmpty = value; }
  190. }
  191. /// <summary>
  192. /// Gets or sets a value indicating that all band rows should be printed together on one page.
  193. /// </summary>
  194. [DefaultValue(false)]
  195. [Category("Behavior")]
  196. public bool KeepTogether
  197. {
  198. get { return keepTogether; }
  199. set { keepTogether = value; }
  200. }
  201. /// <summary>
  202. /// Gets or sets a value indicating that the band should be printed together with all its detail rows.
  203. /// </summary>
  204. [DefaultValue(false)]
  205. [Category("Behavior")]
  206. public bool KeepDetail
  207. {
  208. get { return keepDetail; }
  209. set { keepDetail = value; }
  210. }
  211. /// <summary>
  212. /// Gets or sets the key column that identifies the data row.
  213. /// </summary>
  214. /// <remarks>
  215. /// <para>This property is used when printing a hierarchic list.</para>
  216. /// <para>To print the hierarchic list, you have to setup three properties: <b>IdColumn</b>,
  217. /// <b>ParentIdColumn</b> and <b>Indent</b>. First two properties are used to identify the data
  218. /// row and its parent; the <b>Indent</b> property specifies the indent that will be used to shift
  219. /// the databand according to its hierarchy level.</para>
  220. /// <para/>When printing hierarchy, FastReport shifts the band to the right
  221. /// (by value specified in the <see cref="Indent"/> property), and also decreases the
  222. /// width of the band by the same value. You may use the <b>Anchor</b> property of the
  223. /// objects on a band to indicate whether the object should move with the band, or stay
  224. /// on its original position, or shrink.
  225. /// </remarks>
  226. [Category("Hierarchy")]
  227. [Editor("FastReport.TypeEditors.DataColumnEditor, FastReport", typeof(UITypeEditor))]
  228. public string IdColumn
  229. {
  230. get { return idColumn; }
  231. set { idColumn = value; }
  232. }
  233. /// <summary>
  234. /// Gets or sets the column that identifies the parent data row.
  235. /// </summary>
  236. /// <remarks>
  237. /// This property is used when printing a hierarchic list. See description of the
  238. /// <see cref="IdColumn"/> property for more details.
  239. /// </remarks>
  240. [Category("Hierarchy")]
  241. [Editor("FastReport.TypeEditors.DataColumnEditor, FastReport", typeof(UITypeEditor))]
  242. public string ParentIdColumn
  243. {
  244. get { return parentIdColumn; }
  245. set { parentIdColumn = value; }
  246. }
  247. /// <summary>
  248. /// Gets or sets the indent that will be used to shift the databand according to its hierarchy level.
  249. /// </summary>
  250. /// <remarks>
  251. /// This property is used when printing a hierarchic list. See description of the
  252. /// <see cref="IdColumn"/> property for more details.
  253. /// </remarks>
  254. [DefaultValue(37.8f)]
  255. [Category("Hierarchy")]
  256. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  257. public float Indent
  258. {
  259. get { return indent; }
  260. set { indent = value; }
  261. }
  262. /// <summary>
  263. /// Gets or sets a value indicating that the databand should collect child data rows.
  264. /// </summary>
  265. /// <remarks>
  266. /// This property determines how the master-detail report is printed. Default behavior is:
  267. /// <para/>MasterData row1
  268. /// <para/>-- DetailData row1
  269. /// <para/>-- DetailData row2
  270. /// <para/>-- DetailData row3
  271. /// <para/>MasterData row2
  272. /// <para/>-- DetailData row1
  273. /// <para/>-- DetailData row2
  274. /// <para/>When you set this property to <b>true</b>, the master databand will collect all child data rows
  275. /// under a single master data row:
  276. /// <para/>MasterData row1
  277. /// <para/>-- DetailData row1
  278. /// <para/>-- DetailData row2
  279. /// <para/>-- DetailData row3
  280. /// <para/>-- DetailData row4
  281. /// <para/>-- DetailData row5
  282. /// </remarks>
  283. [DefaultValue(false)]
  284. [Category("Behavior")]
  285. public bool CollectChildRows
  286. {
  287. get { return collectChildRows; }
  288. set { collectChildRows = value; }
  289. }
  290. /// <summary>
  291. /// Gets or sets a value that determines whether to reset the page numbers when this band starts print.
  292. /// </summary>
  293. /// <remarks>
  294. /// Typically you should set the <see cref="BandBase.StartNewPage"/> property to <b>true</b> as well.
  295. /// </remarks>
  296. [DefaultValue(false)]
  297. [Category("Behavior")]
  298. public bool ResetPageNumber
  299. {
  300. get { return resetPageNumber; }
  301. set { resetPageNumber = value; }
  302. }
  303. internal bool IsDeepmostDataBand
  304. {
  305. get { return Bands.Count == 0; }
  306. }
  307. internal bool KeepSummary
  308. {
  309. get { return keepSummary; }
  310. set { keepSummary = value; }
  311. }
  312. internal bool IsHierarchical
  313. {
  314. get
  315. {
  316. return !String.IsNullOrEmpty(IdColumn) && !String.IsNullOrEmpty(ParentIdColumn);
  317. }
  318. }
  319. internal bool IsDatasourceEmpty
  320. {
  321. get { return DataSource == null || DataSource.RowCount == 0; }
  322. }
  323. #endregion
  324. #region Private Methods
  325. private void DataSource_Disposed(object sender, EventArgs e)
  326. {
  327. dataSource = null;
  328. }
  329. #endregion
  330. #region Protected Methods
  331. /// <inheritdoc/>
  332. protected override void DeserializeSubItems(FRReader reader)
  333. {
  334. if (String.Compare(reader.ItemName, "Sort", true) == 0)
  335. reader.Read(Sort);
  336. else
  337. base.DeserializeSubItems(reader);
  338. }
  339. #endregion
  340. #region IParent
  341. /// <inheritdoc/>
  342. public override void GetChildObjects(ObjectCollection list)
  343. {
  344. base.GetChildObjects(list);
  345. if (IsRunning)
  346. return;
  347. list.Add(header);
  348. foreach (BandBase band in bands)
  349. {
  350. list.Add(band);
  351. }
  352. list.Add(footer);
  353. }
  354. /// <inheritdoc/>
  355. public override bool CanContain(Base child)
  356. {
  357. return base.CanContain(child) || (child is DataHeaderBand || child is DataFooterBand ||
  358. child is DataBand || child is GroupHeaderBand);
  359. }
  360. /// <inheritdoc/>
  361. public override void AddChild(Base child)
  362. {
  363. if (IsRunning)
  364. {
  365. base.AddChild(child);
  366. return;
  367. }
  368. if (child is DataHeaderBand)
  369. Header = child as DataHeaderBand;
  370. else if (child is DataFooterBand)
  371. Footer = child as DataFooterBand;
  372. else if (child is DataBand || child is GroupHeaderBand)
  373. bands.Add(child as BandBase);
  374. else
  375. base.AddChild(child);
  376. }
  377. /// <inheritdoc/>
  378. public override void RemoveChild(Base child)
  379. {
  380. base.RemoveChild(child);
  381. if (IsRunning)
  382. return;
  383. if (child is DataHeaderBand && header == child as DataHeaderBand)
  384. Header = null;
  385. if (child is DataFooterBand && footer == child as DataFooterBand)
  386. Footer = null;
  387. if (child is DataBand || child is GroupHeaderBand)
  388. bands.Remove(child as BandBase);
  389. }
  390. /// <inheritdoc/>
  391. public override int GetChildOrder(Base child)
  392. {
  393. if (child is BandBase && !IsRunning)
  394. return bands.IndexOf(child as BandBase);
  395. return base.GetChildOrder(child);
  396. }
  397. /// <inheritdoc/>
  398. public override void SetChildOrder(Base child, int order)
  399. {
  400. if (child is BandBase && !IsRunning)
  401. {
  402. if (order > bands.Count)
  403. order = bands.Count;
  404. int oldOrder = child.ZOrder;
  405. if (oldOrder != -1 && order != -1 && oldOrder != order)
  406. {
  407. if (oldOrder <= order)
  408. order--;
  409. bands.Remove(child as BandBase);
  410. bands.Insert(order, child as BandBase);
  411. }
  412. }
  413. else
  414. base.SetChildOrder(child, order);
  415. }
  416. #endregion
  417. #region Public Methods
  418. /// <inheritdoc/>
  419. public override void Assign(Base source)
  420. {
  421. base.Assign(source);
  422. DataBand src = source as DataBand;
  423. DataSource = src.DataSource;
  424. RowCount = src.RowCount;
  425. MaxRows = src.MaxRows;
  426. Relation = src.Relation;
  427. Sort.Assign(src.Sort);
  428. Filter = src.Filter;
  429. Columns.Assign(src.Columns);
  430. PrintIfDetailEmpty = src.PrintIfDetailEmpty;
  431. PrintIfDatasourceEmpty = src.PrintIfDatasourceEmpty;
  432. KeepTogether = src.KeepTogether;
  433. KeepDetail = src.KeepDetail;
  434. IdColumn = src.IdColumn;
  435. ParentIdColumn = src.ParentIdColumn;
  436. Indent = src.Indent;
  437. CollectChildRows = src.CollectChildRows;
  438. ResetPageNumber = src.ResetPageNumber;
  439. }
  440. internal override void UpdateWidth()
  441. {
  442. if (Columns.Count > 1)
  443. {
  444. Width = Columns.ActualWidth;
  445. }
  446. else if (!String.IsNullOrEmpty(IdColumn) && !String.IsNullOrEmpty(ParentIdColumn))
  447. {
  448. if (PageWidth != 0)
  449. Width = PageWidth - Left;
  450. }
  451. else
  452. base.UpdateWidth();
  453. }
  454. /// <inheritdoc/>
  455. public override void Serialize(FRWriter writer)
  456. {
  457. DataBand c = writer.DiffObject as DataBand;
  458. base.Serialize(writer);
  459. if (writer.SerializeTo == SerializeTo.Preview)
  460. return;
  461. if (DataSource != c.DataSource)
  462. writer.WriteRef("DataSource", DataSource);
  463. if (RowCount != c.RowCount)
  464. writer.WriteInt("RowCount", RowCount);
  465. if (MaxRows != c.MaxRows)
  466. writer.WriteInt("MaxRows", MaxRows);
  467. if (Relation != c.Relation)
  468. writer.WriteRef("Relation", Relation);
  469. if (Sort.Count > 0)
  470. writer.Write(Sort);
  471. if (Filter != c.Filter)
  472. writer.WriteStr("Filter", Filter);
  473. Columns.Serialize(writer, c.Columns);
  474. if (PrintIfDetailEmpty != c.PrintIfDetailEmpty)
  475. writer.WriteBool("PrintIfDetailEmpty", PrintIfDetailEmpty);
  476. if (PrintIfDatasourceEmpty != c.PrintIfDatasourceEmpty)
  477. writer.WriteBool("PrintIfDatasourceEmpty", PrintIfDatasourceEmpty);
  478. if (KeepTogether != c.KeepTogether)
  479. writer.WriteBool("KeepTogether", KeepTogether);
  480. if (KeepDetail != c.KeepDetail)
  481. writer.WriteBool("KeepDetail", KeepDetail);
  482. if (IdColumn != c.IdColumn)
  483. writer.WriteStr("IdColumn", IdColumn);
  484. if (ParentIdColumn != c.ParentIdColumn)
  485. writer.WriteStr("ParentIdColumn", ParentIdColumn);
  486. if (FloatDiff(Indent, c.Indent))
  487. writer.WriteFloat("Indent", Indent);
  488. if (CollectChildRows != c.CollectChildRows)
  489. writer.WriteBool("CollectChildRows", CollectChildRows);
  490. if (ResetPageNumber != c.ResetPageNumber)
  491. writer.WriteBool("ResetPageNumber", ResetPageNumber);
  492. }
  493. /// <inheritdoc/>
  494. public override string[] GetExpressions()
  495. {
  496. List<string> list = new List<string>();
  497. foreach (Sort sort in Sort)
  498. {
  499. list.Add(sort.Expression);
  500. }
  501. list.Add(Filter);
  502. return list.ToArray();
  503. }
  504. /// <summary>
  505. /// Initializes the data source connected to this band.
  506. /// </summary>
  507. public void InitDataSource()
  508. {
  509. if (DataSource == null)
  510. {
  511. DataSource = new VirtualDataSource();
  512. DataSource.SetReport(Report);
  513. }
  514. if (DataSource is VirtualDataSource)
  515. (DataSource as VirtualDataSource).VirtualRowsCount = RowCount;
  516. DataSourceBase parentDataSource = ParentDataBand == null ? null : ParentDataBand.DataSource;
  517. bool collectChildRows = ParentDataBand == null ? false : ParentDataBand.CollectChildRows;
  518. if (Relation != null)
  519. DataSource.Init(Relation, Filter, Sort, collectChildRows);
  520. else
  521. DataSource.Init(parentDataSource, Filter, Sort, collectChildRows);
  522. }
  523. internal bool IsDetailEmpty()
  524. {
  525. if (PrintIfDetailEmpty || Bands.Count == 0)
  526. return false;
  527. foreach (BandBase band in Bands)
  528. {
  529. if (!band.IsEmpty())
  530. return false;
  531. }
  532. return true;
  533. }
  534. internal override bool IsEmpty()
  535. {
  536. InitDataSource();
  537. if (IsDatasourceEmpty)
  538. return !PrintIfDatasourceEmpty;
  539. DataSource.First();
  540. while (DataSource.HasMoreRows)
  541. {
  542. if (!IsDetailEmpty())
  543. return false;
  544. DataSource.Next();
  545. }
  546. return true;
  547. }
  548. /// <inheritdoc/>
  549. public override void InitializeComponent()
  550. {
  551. base.InitializeComponent();
  552. KeepSummary = false;
  553. }
  554. #endregion
  555. /// <summary>
  556. /// Initializes a new instance of the <see cref="DataBand"/> class.
  557. /// </summary>
  558. public DataBand()
  559. {
  560. bands = new BandCollection(this);
  561. sort = new SortCollection();
  562. filter = "";
  563. columns = new BandColumns(this);
  564. idColumn = "";
  565. parentIdColumn = "";
  566. indent = 37.8f;
  567. rowCount = 1;
  568. SetFlags(Flags.HasSmartTag, true);
  569. }
  570. }
  571. }