BusinessObjectDataSource.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Collections;
  5. using System.Reflection;
  6. using System.ComponentModel;
  7. using FastReport.Utils;
  8. namespace FastReport.Data
  9. {
  10. /// <summary>
  11. /// Represents a datasource based on business object of <b>IEnumerable</b> type.
  12. /// </summary>
  13. /// <remarks>
  14. /// Do not use this class directly. To register a business object, use the
  15. /// <b>Report.RegisterData</b> method.
  16. /// </remarks>
  17. public class BusinessObjectDataSource : DataSourceBase
  18. {
  19. #region Fields
  20. #endregion
  21. #region Properties
  22. /// <summary>
  23. /// Occurs when FastReport engine loads data source with data from a business object.
  24. /// </summary>
  25. /// <remarks>
  26. /// Use this event if you want to implement load-on-demand. Event handler must load the data into
  27. /// your business object.
  28. /// </remarks>
  29. public event LoadBusinessObjectEventHandler LoadBusinessObject;
  30. #endregion
  31. #region Private Methods
  32. private void LoadData(IEnumerable enumerable, ArrayList rows)
  33. {
  34. if (enumerable == null)
  35. return;
  36. OnLoadBusinessObject();
  37. IEnumerator enumerator = enumerable.GetEnumerator();
  38. while (enumerator.MoveNext())
  39. {
  40. rows.Add(enumerator.Current);
  41. }
  42. }
  43. private void OnLoadBusinessObject()
  44. {
  45. if (LoadBusinessObject != null)
  46. LoadBusinessObject(this, new LoadBusinessObjectEventArgs(this.Value));
  47. }
  48. #endregion
  49. #region Protected Methods
  50. /// <inheritdoc/>
  51. protected override object GetValue(string alias)
  52. {
  53. string[] colAliases = alias.Split('.');
  54. Column column = this;
  55. foreach (string colAlias in colAliases)
  56. {
  57. column = column.Columns.FindByAlias(colAlias);
  58. if (column == null)
  59. return null;
  60. }
  61. return GetValue(column);
  62. }
  63. /// <inheritdoc/>
  64. protected override object GetValue(Column column)
  65. {
  66. if (column == null)
  67. return null;
  68. // check if column is a list value
  69. if (column.PropDescriptor == null && column.PropName == "Value")
  70. return CurrentRow;
  71. // get nested columns in right order
  72. List<Column> columns = new List<Column>();
  73. while (column != this)
  74. {
  75. columns.Insert(0, column);
  76. column = column.Parent as Column;
  77. }
  78. object obj = CurrentRow;
  79. foreach (Column c in columns)
  80. {
  81. if (obj == null)
  82. return null;
  83. obj = c.PropDescriptor.GetValue(obj);
  84. }
  85. return obj;
  86. }
  87. #endregion
  88. #region Public Methods
  89. /// <inheritdoc/>
  90. public override void InitSchema()
  91. {
  92. // do nothing; the schema was initialized when we register a business object.
  93. }
  94. /// <inheritdoc/>
  95. public override void LoadData(ArrayList rows)
  96. {
  97. rows.Clear();
  98. // custom load data via Load event
  99. OnLoad();
  100. DataSourceBase parent = ParentDataSource;
  101. bool isMasterDetail = parent != null && parent.RowCount > 0;
  102. if (isMasterDetail)
  103. {
  104. LoadData(this.Value as IEnumerable, rows);
  105. }
  106. else
  107. {
  108. // ensure that parent is loaded
  109. if (parent != null && parent.InternalRows.Count == 0)
  110. parent.Init();
  111. if (parent == null)
  112. {
  113. // this is a root business object, its Reference property contains IEnumerable.
  114. LoadData(Reference as IEnumerable, rows);
  115. }
  116. else
  117. {
  118. // enumerate parent rows to fill this data source completely
  119. parent.First();
  120. while (parent.HasMoreRows)
  121. {
  122. LoadData(this.Value as IEnumerable, rows);
  123. parent.Next();
  124. }
  125. // bug fix - two-pass report shows empty data
  126. parent.ClearData();
  127. }
  128. }
  129. }
  130. /// <inheritdoc/>
  131. public override void Deserialize(FRReader reader)
  132. {
  133. base.Deserialize(reader);
  134. // compatibility with old reports: try to use last part of ReferenceName as a value for PropName
  135. if (!String.IsNullOrEmpty(ReferenceName) && ReferenceName.Contains("."))
  136. {
  137. string[] names = ReferenceName.Split('.');
  138. PropName = names[names.Length - 1];
  139. ReferenceName = "";
  140. }
  141. // gather all nested datasource names (PropName properties)
  142. List<string> dataSourceNames = new List<string>();
  143. foreach (Column column in Columns)
  144. {
  145. if (column is BusinessObjectDataSource)
  146. dataSourceNames.Add(column.PropName);
  147. }
  148. // delete simple columns that have the same name as a datasource. In old version,
  149. // there was an invisible column used to support BO infrastructure
  150. for (int i = 0; i < Columns.Count; i++)
  151. {
  152. Column column = Columns[i];
  153. if (!(column is BusinessObjectDataSource) && dataSourceNames.Contains(column.PropName))
  154. {
  155. column.Dispose();
  156. i--;
  157. }
  158. }
  159. }
  160. #endregion
  161. }
  162. /// <summary>
  163. /// Represents the method that will handle the LoadBusinessObject event.
  164. /// </summary>
  165. /// <param name="sender">The source of the event.</param>
  166. /// <param name="e">The event data.</param>
  167. public delegate void LoadBusinessObjectEventHandler(object sender, LoadBusinessObjectEventArgs e);
  168. /// <summary>
  169. /// Provides data for <see cref="LoadBusinessObjectEventHandler"/> event.
  170. /// </summary>
  171. public class LoadBusinessObjectEventArgs
  172. {
  173. /// <summary>
  174. /// Parent object for this data source.
  175. /// </summary>
  176. public object parent;
  177. internal LoadBusinessObjectEventArgs(object parent)
  178. {
  179. this.parent = parent;
  180. }
  181. }
  182. }