Dynamically add rows of data to a *.rpt file (C#) - c#

I am using vs2008 with CrystalReports and I'm wandering how can i dynamically add rows of data to a *.rpt file?(using c#).
In more detail i want to create a a function that populates a *.rpt file with data that might contain lists(for example "FirstName", "LastName", List<"Friend"> ;..Friend beeing an object that contains multiple fields like "FriendNr", "Address",....).
the code that i used so far is:
ReportDocument rpt = new ReportDocument();
MemoryStream stream = new MemoryStream();
string filename = filepath + "/myRpt.rpt";
rpt.Load(filename);
rpt.SetParameterValue(0, myObject.FirstName);
rpt.SetParameterValue(1, myObject.LastName);
Inside the rpt file i have placed FieldObjects(Parameter Fields), and i populate the file with data by assigning the desired values to these objects (" rpt.SetParameterValue(0, myObject.FirstName);" )
Please help me find a way to populate the report with the rows of data contained in the List also.
Thanks a lot for your time.

I don't think it is possible to add data rows to a report this way. I suggest using a Typed DataSet as your report data source. The report can then display as many Friend objects as you require.

Dynamic 'rows' approaches:
1). You could add more items to the parameter's CurrentValues collection. Not sure how you are using this in the report, but it may work for your purposes. Look at the ParameterFieldDefinition class for more information.
2). Create a DataSet, modify as necessary, then assign it to the report. Use the ReportDocument.SetDataSource() method to bind a report to data programmatically.
3). Another approach is to build a report that uses XML data, then programmatically modify the XML, then refresh the report.

Related

Add new fields using c # code to crystal report (rpt)

I have a crystal report rpt report created with some fixed fields that fill with a datatable, the fields obtained in the datatable may vary depending on the SQL statement of the fields in a form. Therefore, the question is whether in the design of the rpt form I can add, by code, new fields obtained in the datatable. For example, in the datatable I get the First and Last Name fields, and I show them in the report (in the design I have inserted the First and Last Name fields). Now in the datatable I get Name, Surname and Telephone, if I call the same report, it will fill in only Name and Surname, the Telephone field, not being inserted in the report will not appear, the idea is to add it. I am filling the dataset in such a way:
DataSet ds = new dsDataSet();
ds.Tables.Add(new DataTable());
foreach (DataColumn column in dtBusqueda.Columns)
{
ds.Tables[0].Columns.Add(column.ColumnName);
}
Now it would be those dataset fields to insert into the report as I explained before. The report is loaded as follows:
ReportDocument Report = new ReportDocument();
Report.Load("../../crReporte.rpt");
Report.SetDataSource(dtDataTable);
frmReportes form = new frmReportes(Report);
form.Show();
Thanks.
Crystal work only with pre-defined data object to display the data in a specified format. So if you pass a different data object then it will give you errors that it cannot locate your column.
I can offer :
1) Use same dataTable source for all (put tel column in original). So set visibility on Crystal Report for your special column. with supress.
2) You can create individual 2 different report And in your If Case you can load another report template if you want.
if it is only tel number not for complex requirement. use way 1. just set visibility.
But if you have complex requirement. I think you should use 2 different report template.

How to make a Crystal report with data from classes?

I am new to this tool, so I do not know how I can get the data of a class and show in a report.
I don't have a database, my info is stored inside variables inside classes. Like this (Folder Objetos):
My program does: Read a XML, validate with XSD, serialize in this classes.
What I want: Take that information and show in a report.
It is possible to put my data from variables in a Crystal report? Where I start?
well crystal report can take many things as " DataSource" ranging from object, datatable, dataset etc etc. without looking at the code it is hard to figure out where you are having issue.
basic syntax for crystalreport load datasource is
CrystalDecisions.CrystalReports.Engine.ReportDocument reportDoc = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
reportDoc.Load("your RPT file");
reportDoc.SetDataSource(object)
here instead of object you can use dataset, datatable etc.\
Is this what you were looking for ?
Added
reportDoc.SetDataSource(ds.Tables["YourTableName"])
Also one more thing to note is if you report requires lets say 20 fields they all must be preset in the datatable. or else it will not work. if it has any extra fields in dataset it will just ignore those

Better way to use data set in C#

We have created a custom dataset and populating it with some data.
Before adding data, we are adding columns in the data set as follows
DataSet archiveDataset = new DataSet("Archive");
DataTable dsTable = archiveDataset.Tables.Add("Data");
dsTable.Columns.Add("Id", typeof(int));
dsTable.Columns.Add("Name", typeof(string));
dsTable.Columns.Add("LastOperationBy", typeof(int));
dsTable.Columns.Add("Time", typeof(DateTime))
Once the Dataset is create, we are filling values as follows
DataRow dataRow = dsTable.NewRow();
dataRow["Id"] = source.Id;
dataRow["Name"] = source.Name;
dataRow["LastOperationBy"] = source.LastOperationBy;
dataRow["Time"] = source.LaunchTime;
Is there any better and managed way of doing this. can I make the code more easy to write using enum or anything else to reduce the efforts?
You could try using a Typed Dataset.
This should get rid of the ["<column_name>"] ugliness.
If the dataset has a structure similar to tables in a database, then Visual Studio makes it really easy to create one: just click Add -> New Item somewhere in the solution and choose DataSet. VS will show a designer where you can drag tables from your server explorer.
Update (after response to Simon's comment):
A typed dataset is in fact an XSD (XML Schema Definition).
What I did in a similar case was:
created an empty DataSet (using Add -> New Item -> DataSet)
opened the newly created file with a text editor (by dafault, in VS it shows the XSD designer)
paste the XSD that I had created manually
You could also choose to use the designer to create the schema.
Considering your comment "I am using Dataset to export data to a XML file" I recommend using a different technology such as
Linq to XML http://msdn.microsoft.com/en-us/library/bb387061.aspx or
Xml Serialzation http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
Or better yet of is doesnt have to be XML (and you only want hierarchical readable text consider JSON instead http://james.newtonking.com/pages/json-net.aspx
You can bind dataset in two way first one is using database second one is add manually.
After create column for dataset you can add using Loops you can add it if you have 10000 of entries.
You can use Reflection. Another option is to use EntityFramework or NHibernate to map the columnnames and datastructure columns and then avoid these code to fill each field manually. But they will add more complexity. Also Performance wise the your code is better.

How to create an unbound subreport in another unbound report

I have an unbound XtraReport that has a subreport control which contains another report. I call "unbound" to a report that has the definition of the fields using a schema but not actually bound to any DataSet, I create a DataTable using a Data Access Layer and then pass that object to the DataSource property of the report.
So, I have the following code:
// (...) Get the data from the db and fill a DataTable
if (table.Rows.Count > 0)
{
report.DataSource = table;
// (...) Get the data from the db and fill a DataTable for the subreport
report.SubPurchaseOrder.Report.DataSource = tableSubReport;
report.ShowPreviewDialog();
}
else
{
MessageBox.Show("No data to show.");
}
But what I get using this approach is the subreport printed very oddly (take a look at the attached pdf, sorry it's in spanish but I think you get the idea).
I've read the DevExpress documentation and maybe I'm not getting the approach right, so my question to you is how to create a report that has one or more subreports but I have to provide the data to fill them using some process external to the reports, such as a Data Access Layer?
Please let me know if the question is not stated correctly or lacks of more info.
EDIT:
I uploaded a sample project with the report with problem here.
I've tried to use parameters of some kind. In the BeforePrint event of the subreport control, I tried:
((XRSubreport)sender).ReportSource.FilterString = "[IdPO_RO] = " + _idPurchaseOrder;
and
((XRSubreport)sender).ReportSource.Parameters["Id"].Value = _idPurchaseOrder;
Of course, for the second, I added a parameter and the filter string the same as the first but using the parameter.
I could solve the problem.
The cause for this was that I was assigning to the wrong object. This line:
report.SubPurchaseOrder.Report.DataSource = tableSubReport;
should be:
report.SubPurchaseOrder.ReportSource.DataSource = tableSubReport;
So the brief explanation is that I was using another property to refer to the report contained in the subreport control (XRSubreport).

Microsoft Reporting: Setting subreport parameters in code

How can I set a parameter of a sub-report? I have successfully hooked myself up to the SubreportProcessing event, I can find the correct sub-report through e.ReportPath, and I can add datasources through e.DataSources.Add. But I find no way of adding report parameters??
I have found people suggesting to add them to the master report, but I don't really want to do that, since the master report shouldn't have to be connected to the sub-report at all, other than that it is wrapping the sub-report.
I am using one report as a master template, printing name of the report, page numbers etc. And the subreport is going to be the report itself. And if I could only find a way to set those report parameters of the sub-report I would be good to go...
Clarification: Creating/Defining the parameters is not the problem. The problem is to set their values. I thought the natural thing to do was to do it in the SubreportProcessing event. And the SubreportProcessingEventArgs do in fact have a Parameters property. But it is read only! So how do you use that? How can I set their value?
It does work but it sure is persnickety.
First thing I recommend is to develop your reports as .rdl. Much easier to test the reports this way. You can also get the subreport parameters set up and tested as rdl, making sure each parameter of the subreport is also defined as a parameter of the parent report. Once you get the reports - including the subreports - working that way you can rename the .rdl to rdlc and add the rdlc files to your ReportViewer Project. No further changes required. Use the names of the rdl datasources as the data source names in your code to provide data to the report in the SubreportProcessing event handler.
You don't assign values to the passed parameter. The subreport will use them as is. (Sounds like the step you are missing is adding the parameters to the parent report as well as the the subreport as mentioned above.) You can evaluate the parameters and use them as query parameters to get the datasource you will add.
You have to think about the datasource like its on an undiscovered dimension for a subreport. You will have to poke around while debugging in the event handler to see what I mean. Some of the values in your application will be readily available, others that you use easily elsewhere will throw object not found exceptions. For example I create a dataset in a instance of a class created on my applications main form. I use the data set throughout my application. In the SubreportProcessing event handler I cannot use the common dataset, so I must create a new instance of the table I need for the report and populate it. In the main report I would be able to access the common dataset. There are other limitations like this. Just have to wade your way through.
Here is the SubreportProcessing event handler from a working VB.NET ReportViewer application. Shows a few different ways to get the datasource for a subreport. subreport1 builds a one row datatable from application business objects, subreport2 provides data the report requires without a parameter, subreport3 is lie subreport2 but evaluates one of the parameters passed to the subreport for use in date value required by the query that creates the ReportDataSource.
Public Sub SubreportProcessingEventHandler(ByVal sender As Object, _
ByVal e As SubreportProcessingEventArgs)
Select Case e.ReportPath
Case "subreport1"
Dim tbl As DataTable = New DataTable("TableName")
Dim Status As DataColumn = New DataColumn
Status.DataType = System.Type.GetType("System.String")
Status.ColumnName = "Status"
tbl.Columns.Add(Status)
Dim Account As DataColumn = New DataColumn
Account.DataType = System.Type.GetType("System.String")
Account.ColumnName = "Account"
tbl.Columns.Add(Account)
Dim rw As DataRow = tbl.NewRow()
rw("Status") = core.GetStatus
rw("Account") = core.Account
tbl.Rows.Add(rw)
e.DataSources.Add(New ReportDataSource("ReportDatasourceName", tbl))
Case "subreport2"
core.DAL.cnStr = My.Settings.cnStr
core.DAL.LoadSchedule()
e.DataSources.Add(New ReportDataSource("ScheduledTasks", _
My.Forms.Mother.DAL.dsSQLCfg.tSchedule))
Case "subreport3"
core.DAL.cnStr = My.Settings.cnStr
Dim dt As DataTable = core.DAL.GetNodesForDateRange(DateAdd("d", _
-1 * CInt(e.Parameters("NumberOfDays").Values(0)), _
Today), _
Now)
e.DataSources.Add(New ReportDataSource("Summary", dt))
End Select
End Sub
Recently I had the same problem and with all the search I didn't find anything helpful but finally I came to a solution for this.
I created a class having all the parameteres in the subreport as it's properties(we can call it a DTO)
public class MyDto
{
public string EmployeeFirstName{get; set;}
public string EmployeeLastName{get; set;}
// and so on
}
Then used a list of this type as another datasource in the main report and then in 'Subreport properties' added a parameter for each parameter in the actual subreport and chose the corresponding fields from the datasource as their values.
then when loading the report convert the input(list of Employees) to a list of MyDto and set it as the reports's datasource :
private void LoadReport(List<Employee> employees)
{
reportviewerMain.ProcessingMode = ProcessingMode.Local;
reportviewerMain.LocalReport.ReportPath = Application.StartupPath + "\\Reports\\PayChecksReport.rdlc";
List<MyDto> employeesDataSource = employees.ConvertAll<MyDto>(emp => new MyDto { EmployeeFirstName = emp.FirstName, EmployeeLastName = emp.LastName}).ToList();
reportviewerMain.LocalReport.DataSources.Add(new ReportDataSource("EmployeesDataSet", employeesDataSource));
Organization myOrganization = new OranizationFacade().GetOrganizationInfo();
reportviewerMain.LocalReport.SetParameters(new ReportParameter("OrganizationName", myOrganization.Name));
this.reportviewerMain.RefreshReport();
}
And...
It did the trick for me :) I hope it helps somebody.
I know this is an old question which has been marked as answered, but since I was just searching for this today and I saw that it had been commented on within the last few months I thought I'd throw a follow up answer in.
In order to render the subreport in the context of each record on the main report, you need to declare a SubreportProcessingEventHandler and then inside that handler load the DataSet for each instance of the subreport as it occurs. SubreportProcessingEventArgs has a parameters collection which is passed from the parent report when the event fires.
So if you have configured the subreport parameters on the main report with like named parameters bound to fields on the main report, the values are accessible as the subreport is rendered.
Here is a very good write up that explains far more clearly.
I had a similar problem in that I needed to pass a Properties.Settings.... value to prepend to the path in the database. To do this I had to set a property in the main report and use that property to set the second property in the subreport. Setting the main property then in turn sets the subreport property. YOU CAN set the main property in code as follows:
Suppose you have a ReportViewer name rv, then we would code:
var rp = new ReportParameter("MainReportParamName", Properties.Settings....);
rv.LocalReport.SetParameters(new ReportParameters[] { rp });
You could add them via the xml definition. I use xml to create an entire report based on selected sub-reports and other options. I can paste some code in here come Monday if you would like to look at this as a possible solution.
Edit: You can set values on the sub-report in the XML before you deploy the report. This is not very flexible and I am making the assumption that if you want to prompt for these values, you will most likely need them on the parent report.
If you want to see what the XML looks like, add a sub-report, enter values for it in the sub-report properties > parameters, then do a view code.
<Subreport Name="subreport1">
<Parameters>
<Parameter Name="StartDate">
<Value>=Parameters!StartDate.Value</Value>
</Parameter>
<Parameter Name="EndDate">
<Value>1/1/2009</Value>
</Parameter>
Instead of using the =Parameters!StartDate.Value I'm guessing you would want to put an actual value like on the EndDate.
After looking and looking, I have come to the conclusion that setting the parameters of a sub-report, in code, is not possible. Unless you do something fancy like start editing the xml of the report definition before you load it or something like that.
(But if someone else should know that I am wrong, please do answer, cause I am still very curious to know!)
Svish - I'm not sure which side of the plumbing you're having trouble with.
To add parameters to the parent report open it then right click on the subreport and select Properties > Parameters.
You can then define parameter names and assign them a value, e.g.
Parameter Name | Parameter Value
---------------+---------------------
MyParameter | =Fields!Params.Value
So on this side of the plumbing the parameters get their value from the parent report data source.
To add parameters to a subreport open the subreport and from the toolbar select Report > Report Parameters
Here you define a parameter to receive the parameter from the parent report, e.g.
Name | myParameter
----------+---------------------
Data Type | String
For what it sounds like you want to do can't you do away with a subreport and just have the one report anyway? The information you're trying to wrap around the report sounds ideal for just including in the headers and footers of the report.

Categories

Resources