Bind Section Based Report to Nested IList Collection
ActiveReports supports different types of data sources. And, it is quite common to use an IList or a collection of objects as the data source for a report. A sample is included with ActiveReports 7 installer which demonstrates this. Default location for the sample is "My Documents\ComponentOne Samples\ActiveReports Developer 7\Section Reports\C#\IListBindingSample ". However, in this article I would like to talk more about a complex/nested IList. To bind a report to a nested IList we can use subreports to handle the inner list objects. For example lets consider that we are planning for a games event and different teams are participating. Now for each team there would be multiple players. This is a very basic example of nested collection of objects where the top level contains the details of the teams and then in the next level each team has its own players. Considering the above example, when binding it to the report we can show the team names in the main report and the player names in the subreport. Separate classes and properties can be created for the team and the players to ensure that the data is displayed correctly and in a simple fashion. Here is a output of the report which we will get:
The first thing which we need to do is to create two classes which will hold name of players and the teams. Let us call them Player.cs and Team.cs. Now we need to populate them with data, so we will write a function GetData() something like below:
public IList<Team> GetData()
{
List<Player> listOfPlayer1 = new List<Player>()
{
new Player{pName="Jon"},
new Player{pName="Rosh"},
new Player{pName="Tim"},
};
List<Player> listOfPlayer2 = new List<Player>()
{
new Player{pName="Thomas"},
new Player{pName="Jack"},
new Player{pName ="Paul"}
};
List<Player> listOfPlayer3 = new List<Player>()
{
new Player{pName="Gatim"},
new Player{pName="Aashish"},
new Player{pName="Subodh"}
};
List<Player> listOfPlayer4 = new List<Player>()
{
new Player{pName="Josh"},
new Player{pName="Albert"},
new Player{pName="Charles"}
};
//Add the teams and their corresponding players
List<Team> listOfTeam = new List<Team>()
{
new Team{name="U.S.A", players=listOfPlayer1},
new Team {name="U.K", players=listOfPlayer2},
new Team{name ="India",players=listOfPlayer3},
new Team{name="Australia", players=listOfPlayer4}
};
return listOfTeam;
}
To set the datasource for main report and the subreport we will use the ReportStart, Detail_Format and the FetchData events in the following way:
//Create the sub report object
rptPlayer report = new rptPlayer();
private void NewActiveReport1_ReportStart(object sender, EventArgs e)
{
this.DataSource = GetData();
//To show the team name on the main report
textBox1.DataField = "name";
counter = 0;
}
int count;
private void rptTeam_FetchData(object sender, FetchEventArgs eArgs)
{
count++;
}
private void detail_Format(object sender, EventArgs e)
{
this.picture1.SizeMode = SizeModes.Stretch;
if (count == 1)
{
this.picture1.Image = System.Drawing.Image.FromFile(@"..\\..\\Flags\\USA.jpg");
}
else if (count == 2)
{
this.picture1.Image = System.Drawing.Image.FromFile(@"..\\..\\Flags\\UK.jpg");
}
else if (count == 3)
{
this.picture1.Image = System.Drawing.Image.FromFile(@"..\\..\\Flags\\India.jpg");
}
else if (count == 4)
{
this.picture1.Image = System.Drawing.Image.FromFile(@"..\\..\\Flags\\Australia.jpg");
}
//Assign the datasource to the subreport
report.DataSource = GetData()[counter].players;
report.DataMember = "pName";
subReport1.Report = report;
counter++;
}
Sample application demonstrating this implementation can be downloaded in both C# and VB.NET using the following links. Sample C# Sanmple VB