GroupHeaderBand.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. using System.ComponentModel;
  2. using FastReport.Utils;
  3. using FastReport.Data;
  4. using System.Drawing.Design;
  5. namespace FastReport
  6. {
  7. /// <summary>
  8. /// Specifies a sort order.
  9. /// </summary>
  10. /// <remarks>
  11. /// This enumeration is used in the group header and in the "Matrix" object.
  12. /// </remarks>
  13. public enum SortOrder
  14. {
  15. /// <summary>
  16. /// Specifies no sort (natural order).
  17. /// </summary>
  18. None,
  19. /// <summary>
  20. /// Specifies an ascending sort order.
  21. /// </summary>
  22. Ascending,
  23. /// <summary>
  24. /// Specifies a descending sort order.
  25. /// </summary>
  26. Descending
  27. }
  28. /// <summary>
  29. /// Represents a group header band.
  30. /// </summary>
  31. /// <remarks>
  32. /// A simple group consists of one <b>GroupHeaderBand</b> and the <b>DataBand</b> that is set
  33. /// to the <see cref="Data"/> property. To create the nested groups, use the <see cref="NestedGroup"/> property.
  34. /// <note type="caution">
  35. /// Only the last nested group can have data band.
  36. /// </note>
  37. /// <para/>Use the <see cref="Condition"/> property to set the group condition. The <see cref="SortOrder"/>
  38. /// property can be used to set the sort order for group's data rows. You can also use the <b>Sort</b>
  39. /// property of the group's <b>DataBand</b> to specify additional sort.
  40. /// </remarks>
  41. /// <example>This example shows how to create nested groups.
  42. /// <code>
  43. /// ReportPage page = report.Pages[0] as ReportPage;
  44. ///
  45. /// // create the main group
  46. /// GroupHeaderBand mainGroup = new GroupHeaderBand();
  47. /// mainGroup.Height = Units.Millimeters * 10;
  48. /// mainGroup.Name = "MainGroup";
  49. /// mainGroup.Condition = "[Orders.CustomerName]";
  50. /// // add a group to the page
  51. /// page.Bands.Add(mainGroup);
  52. ///
  53. /// // create the nested group
  54. /// GroupHeaderBand nestedGroup = new GroupHeaderBand();
  55. /// nestedGroup.Height = Units.Millimeters * 10;
  56. /// nestedGroup.Name = "NestedGroup";
  57. /// nestedGroup.Condition = "[Orders.OrderDate]";
  58. /// // add it to the main group
  59. /// mainGroup.NestedGroup = nestedGroup;
  60. ///
  61. /// // create a data band
  62. /// DataBand dataBand = new DataBand();
  63. /// dataBand.Height = Units.Millimeters * 10;
  64. /// dataBand.Name = "GroupData";
  65. /// dataBand.DataSource = report.GetDataSource("Orders");
  66. /// // connect the databand to the nested group
  67. /// nestedGroup.Data = dataBand;
  68. /// </code>
  69. /// </example>
  70. public partial class GroupHeaderBand : HeaderFooterBandBase
  71. {
  72. #region Fields
  73. private GroupHeaderBand nestedGroup;
  74. private DataBand data;
  75. private GroupFooterBand groupFooter;
  76. private DataHeaderBand header;
  77. private DataFooterBand footer;
  78. private string condition;
  79. private SortOrder sortOrder;
  80. private bool keepTogether;
  81. private bool resetPageNumber;
  82. private object groupValue;
  83. #endregion
  84. #region Properties
  85. /// <summary>
  86. /// Gets or sets a nested group.
  87. /// </summary>
  88. /// <remarks>
  89. /// Use this property to create nested groups.
  90. /// <note type="caution">
  91. /// Only the last nested group can have data band.
  92. /// </note>
  93. /// </remarks>
  94. /// <example>
  95. /// This example demonstrates how to create a group with nested group.
  96. /// <code>
  97. /// ReportPage page;
  98. /// GroupHeaderBand group = new GroupHeaderBand();
  99. /// group.NestedGroup = new GroupHeaderBand();
  100. /// group.NestedGroup.Data = new DataBand();
  101. /// page.Bands.Add(group);
  102. /// </code>
  103. /// </example>
  104. [Browsable(false)]
  105. public GroupHeaderBand NestedGroup
  106. {
  107. get { return nestedGroup; }
  108. set
  109. {
  110. SetProp(nestedGroup, value);
  111. nestedGroup = value;
  112. }
  113. }
  114. /// <summary>
  115. /// Gets or sets the group data band.
  116. /// </summary>
  117. /// <remarks>
  118. /// Use this property to add a data band to a group. Note: only the last nested group can have Data band.
  119. /// </remarks>
  120. /// <example>
  121. /// This example demonstrates how to add a data band to a group.
  122. /// <code>
  123. /// ReportPage page;
  124. /// GroupHeaderBand group = new GroupHeaderBand();
  125. /// group.Data = new DataBand();
  126. /// page.Bands.Add(group);
  127. /// </code>
  128. /// </example>
  129. [Browsable(false)]
  130. public DataBand Data
  131. {
  132. get { return data; }
  133. set
  134. {
  135. SetProp(data, value);
  136. data = value;
  137. }
  138. }
  139. /// <summary>
  140. /// Gets or sets a group footer.
  141. /// </summary>
  142. [Browsable(false)]
  143. public GroupFooterBand GroupFooter
  144. {
  145. get { return groupFooter; }
  146. set
  147. {
  148. SetProp(groupFooter, value);
  149. groupFooter = value;
  150. }
  151. }
  152. /// <summary>
  153. /// Gets or sets a header band.
  154. /// </summary>
  155. [Browsable(false)]
  156. public DataHeaderBand Header
  157. {
  158. get { return header; }
  159. set
  160. {
  161. SetProp(header, value);
  162. header = value;
  163. }
  164. }
  165. /// <summary>
  166. /// Gets or sets a footer band.
  167. /// </summary>
  168. /// <remarks>
  169. /// To access a group footer band, use the <see cref="GroupFooter"/> property.
  170. /// </remarks>
  171. [Browsable(false)]
  172. public DataFooterBand Footer
  173. {
  174. get { return footer; }
  175. set
  176. {
  177. SetProp(footer, value);
  178. footer = value;
  179. }
  180. }
  181. /// <summary>
  182. /// Gets or sets the group condition.
  183. /// </summary>
  184. /// <remarks>
  185. /// This property can contain any valid expression. When running a report, this expression is calculated
  186. /// for each data row. When the value of this condition is changed, FastReport starts a new group.
  187. /// </remarks>
  188. [Category("Data")]
  189. [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
  190. public string Condition
  191. {
  192. get { return condition; }
  193. set { condition = value; }
  194. }
  195. /// <summary>
  196. /// Gets or sets the sort order.
  197. /// </summary>
  198. /// <remarks>
  199. /// FastReport can sort data rows automatically using the <see cref="Condition"/> value.
  200. /// </remarks>
  201. [DefaultValue(SortOrder.Ascending)]
  202. [Category("Behavior")]
  203. public SortOrder SortOrder
  204. {
  205. get { return sortOrder; }
  206. set { sortOrder = value; }
  207. }
  208. /// <summary>
  209. /// Gets or sets a value indicating that the group should be printed together on one page.
  210. /// </summary>
  211. [DefaultValue(false)]
  212. [Category("Behavior")]
  213. public bool KeepTogether
  214. {
  215. get { return keepTogether; }
  216. set { keepTogether = value; }
  217. }
  218. /// <summary>
  219. /// Gets or sets a value that determines whether to reset the page numbers when this group starts print.
  220. /// </summary>
  221. /// <remarks>
  222. /// Typically you should set the <see cref="BandBase.StartNewPage"/> property to <b>true</b> as well.
  223. /// </remarks>
  224. [DefaultValue(false)]
  225. [Category("Behavior")]
  226. public bool ResetPageNumber
  227. {
  228. get { return resetPageNumber; }
  229. set { resetPageNumber = value; }
  230. }
  231. internal DataSourceBase DataSource
  232. {
  233. get
  234. {
  235. DataBand dataBand = GroupDataBand;
  236. return dataBand == null ? null : dataBand.DataSource;
  237. }
  238. }
  239. internal DataBand GroupDataBand
  240. {
  241. get
  242. {
  243. GroupHeaderBand group = this;
  244. while (group != null)
  245. {
  246. if (group.Data != null)
  247. return group.Data;
  248. group = group.NestedGroup;
  249. }
  250. return null;
  251. }
  252. }
  253. #endregion
  254. #region IParent
  255. /// <inheritdoc/>
  256. public override void GetChildObjects(ObjectCollection list)
  257. {
  258. base.GetChildObjects(list);
  259. if (!IsRunning)
  260. {
  261. list.Add(header);
  262. list.Add(nestedGroup);
  263. list.Add(data);
  264. list.Add(groupFooter);
  265. list.Add(footer);
  266. }
  267. }
  268. /// <inheritdoc/>
  269. public override bool CanContain(Base child)
  270. {
  271. return base.CanContain(child) ||
  272. (child is DataBand && nestedGroup == null && data == null) ||
  273. (child is GroupHeaderBand && (nestedGroup == null || nestedGroup is GroupHeaderBand) && data == null) ||
  274. child is GroupFooterBand || child is DataHeaderBand || child is DataFooterBand;
  275. }
  276. /// <inheritdoc/>
  277. public override void AddChild(Base child)
  278. {
  279. if (IsRunning)
  280. {
  281. base.AddChild(child);
  282. return;
  283. }
  284. if (child is GroupHeaderBand)
  285. NestedGroup = child as GroupHeaderBand;
  286. else if (child is DataBand)
  287. Data = child as DataBand;
  288. else if (child is GroupFooterBand)
  289. GroupFooter = child as GroupFooterBand;
  290. else if (child is DataHeaderBand)
  291. Header = child as DataHeaderBand;
  292. else if (child is DataFooterBand)
  293. Footer = child as DataFooterBand;
  294. else
  295. base.AddChild(child);
  296. }
  297. /// <inheritdoc/>
  298. public override void RemoveChild(Base child)
  299. {
  300. base.RemoveChild(child);
  301. if (IsRunning)
  302. return;
  303. if (child is GroupHeaderBand && nestedGroup == child)
  304. NestedGroup = null;
  305. if (child is DataBand && data == child as DataBand)
  306. Data = null;
  307. if (child is GroupFooterBand && groupFooter == child)
  308. GroupFooter = null;
  309. if (child is DataHeaderBand && header == child)
  310. Header = null;
  311. if (child is DataFooterBand && footer == child)
  312. Footer = null;
  313. }
  314. #endregion
  315. #region Public Methods
  316. /// <inheritdoc/>
  317. public override void Assign(Base source)
  318. {
  319. base.Assign(source);
  320. GroupHeaderBand src = source as GroupHeaderBand;
  321. Condition = src.Condition;
  322. SortOrder = src.SortOrder;
  323. KeepTogether = src.KeepTogether;
  324. ResetPageNumber = src.ResetPageNumber;
  325. }
  326. /// <inheritdoc/>
  327. public override void Serialize(FRWriter writer)
  328. {
  329. GroupHeaderBand c = writer.DiffObject as GroupHeaderBand;
  330. base.Serialize(writer);
  331. if (writer.SerializeTo == SerializeTo.Preview)
  332. return;
  333. if (Condition != c.Condition)
  334. writer.WriteStr("Condition", Condition);
  335. if (SortOrder != c.SortOrder)
  336. writer.WriteValue("SortOrder", SortOrder);
  337. if (KeepTogether != c.KeepTogether)
  338. writer.WriteBool("KeepTogether", KeepTogether);
  339. if (ResetPageNumber != c.ResetPageNumber)
  340. writer.WriteBool("ResetPageNumber", ResetPageNumber);
  341. }
  342. /// <inheritdoc/>
  343. public override string[] GetExpressions()
  344. {
  345. return new string[] { Condition };
  346. }
  347. internal override bool IsEmpty()
  348. {
  349. if (NestedGroup != null)
  350. return NestedGroup.IsEmpty();
  351. else if (Data != null)
  352. return Data.IsEmpty();
  353. return base.IsEmpty();
  354. }
  355. internal void InitDataSource()
  356. {
  357. DataBand dataBand = GroupDataBand;
  358. GroupHeaderBand group = this;
  359. int index = 0;
  360. // insert group sort to the databand
  361. while (group != null)
  362. {
  363. if (group.SortOrder != SortOrder.None)
  364. {
  365. dataBand.Sort.Insert(index, new Sort(group.Condition, group.SortOrder == SortOrder.Descending));
  366. index++;
  367. }
  368. group = group.NestedGroup;
  369. }
  370. dataBand.InitDataSource();
  371. }
  372. internal void FinalizeDataSource()
  373. {
  374. DataBand dataBand = GroupDataBand;
  375. GroupHeaderBand group = this;
  376. // remove group sort from the databand
  377. while (group != null)
  378. {
  379. if (group.SortOrder != SortOrder.None)
  380. dataBand.Sort.RemoveAt(0);
  381. group = group.NestedGroup;
  382. }
  383. }
  384. internal void ResetGroupValue()
  385. {
  386. if (!string.IsNullOrEmpty(Condition))
  387. {
  388. groupValue = Report.Calc(Condition);
  389. }
  390. else
  391. {
  392. throw new GroupHeaderHasNoGroupCondition(Name);
  393. }
  394. }
  395. internal bool GroupValueChanged()
  396. {
  397. object value = null;
  398. if (!string.IsNullOrEmpty(Condition))
  399. {
  400. value = Report.Calc(Condition);
  401. }
  402. else
  403. {
  404. throw new GroupHeaderHasNoGroupCondition(Name);
  405. }
  406. if (groupValue == null)
  407. {
  408. if (value == null)
  409. return false;
  410. return true;
  411. }
  412. return !groupValue.Equals(value);
  413. }
  414. #endregion
  415. /// <summary>
  416. /// Initializes a new instance of the <see cref="GroupHeaderBand"/> class with default settings.
  417. /// </summary>
  418. public GroupHeaderBand()
  419. {
  420. condition = "";
  421. sortOrder = SortOrder.Ascending;
  422. }
  423. }
  424. }