using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using FastReport.Utils;
namespace FastReport.Data
{
///
/// Represents a datasource based on business object of IEnumerable type.
///
///
/// Do not use this class directly. To register a business object, use the
/// Report.RegisterData method.
///
public class BusinessObjectDataSource : DataSourceBase
{
#region Fields
#endregion
#region Properties
///
/// Occurs when FastReport engine loads data source with data from a business object.
///
///
/// Use this event if you want to implement load-on-demand. Event handler must load the data into
/// your business object.
///
public event LoadBusinessObjectEventHandler LoadBusinessObject;
#endregion
#region Private Methods
private void LoadData(IEnumerable enumerable, ArrayList rows)
{
if (enumerable == null)
return;
OnLoadBusinessObject();
IEnumerator enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
rows.Add(enumerator.Current);
}
}
private void OnLoadBusinessObject()
{
if (LoadBusinessObject != null)
LoadBusinessObject(this, new LoadBusinessObjectEventArgs(this.Value));
}
#endregion
#region Protected Methods
///
protected override object GetValue(string alias)
{
string[] colAliases = alias.Split('.');
Column column = this;
foreach (string colAlias in colAliases)
{
column = column.Columns.FindByAlias(colAlias);
if (column == null)
return null;
}
return GetValue(column);
}
///
protected override object GetValue(Column column)
{
if (column == null)
return null;
// check if column is a list value
if (column.PropDescriptor == null && column.PropName == "Value")
return CurrentRow;
// get nested columns in right order
List columns = new List();
while (column != this)
{
columns.Insert(0, column);
column = column.Parent as Column;
}
object obj = CurrentRow;
foreach (Column c in columns)
{
if (obj == null)
return null;
obj = c.PropDescriptor.GetValue(obj);
}
return obj;
}
#endregion
#region Public Methods
///
public override void InitSchema()
{
// do nothing; the schema was initialized when we register a business object.
}
///
public override void LoadData(ArrayList rows)
{
rows.Clear();
// custom load data via Load event
OnLoad();
DataSourceBase parent = ParentDataSource;
bool isMasterDetail = parent != null && parent.RowCount > 0;
if (isMasterDetail)
{
LoadData(this.Value as IEnumerable, rows);
}
else
{
// ensure that parent is loaded
if (parent != null && parent.InternalRows.Count == 0)
parent.Init();
if (parent == null)
{
// this is a root business object, its Reference property contains IEnumerable.
LoadData(Reference as IEnumerable, rows);
}
else
{
// enumerate parent rows to fill this data source completely
parent.First();
while (parent.HasMoreRows)
{
LoadData(this.Value as IEnumerable, rows);
parent.Next();
}
// bug fix - two-pass report shows empty data
parent.ClearData();
}
}
}
///
public override void Deserialize(FRReader reader)
{
base.Deserialize(reader);
// compatibility with old reports: try to use last part of ReferenceName as a value for PropName
if (!String.IsNullOrEmpty(ReferenceName) && ReferenceName.Contains("."))
{
string[] names = ReferenceName.Split('.');
PropName = names[names.Length - 1];
ReferenceName = "";
}
// gather all nested datasource names (PropName properties)
List dataSourceNames = new List();
foreach (Column column in Columns)
{
if (column is BusinessObjectDataSource)
dataSourceNames.Add(column.PropName);
}
// delete simple columns that have the same name as a datasource. In old version,
// there was an invisible column used to support BO infrastructure
for (int i = 0; i < Columns.Count; i++)
{
Column column = Columns[i];
if (!(column is BusinessObjectDataSource) && dataSourceNames.Contains(column.PropName))
{
column.Dispose();
i--;
}
}
}
#endregion
}
///
/// Represents the method that will handle the LoadBusinessObject event.
///
/// The source of the event.
/// The event data.
public delegate void LoadBusinessObjectEventHandler(object sender, LoadBusinessObjectEventArgs e);
///
/// Provides data for event.
///
public class LoadBusinessObjectEventArgs
{
///
/// Parent object for this data source.
///
public object parent;
internal LoadBusinessObjectEventArgs(object parent)
{
this.parent = parent;
}
}
}