Posts Tagged ‘Reporting’

Using powerful report generator in WPF applications.

Friday, April 17th, 2009

Attachment: RSSforWPFWithUserControl.zip

At the moment new programming technologies appear almost every day. New technologies provide developers with wider abilities designed to create applications with more sophisticated user interface and extended functionality. One of such technologies is WPF. Its main advantages are:

  1. Use of DirectX as a technology for displaying graphics instead of used in Windows Forms and out of date GDI. It allows displaying of effects and complicated animation with quite high performance.
  2. Work can be easily divided between designers and developers. WPF has less limitation for designers who can quickly setup all interface elements: from buttons to tables.
  3. New class structure, dynamic properties and events.
  4. Ability to develop applications using markup and code of the programming part. Markup (XAML language) is used to implement application appearance and functional part is described in any .Net compatible programming language.
  5. WPF contains a rich set of panels, and it helps to reduce time and effort required to position elements on the form, as they cover almost all necessary variants.

But in spite of all advantages, there are some problems in using WPF; a lot of convenient controls and tools are designed for Windows and the use of these tools streamlines development of high-quality applications. And developers can’t use these tools in WPF by just placing them on the form. Creation of controls with similar features takes quite a lot of time as their development for Windows Forms could have taken several years. On the other hand it isn’t reasonable to refuse using them at all. That is why it is possible to use any Windows Forms controls (Control shall mean classes inherited from System.Windows.Forms.Control in WPF along with new technology features. There is a special container System.Windows.Forms.Integration.WindowsFormsHost designated to use Windows Forms controls on WPF pages. In order to use this element, you need to do the following steps:

  1. Create new WPF application
  2. Add to the project a reference to the WindowsFormsIntegration dll. It will allow you to get access to the WindowsFormsHost container
  3. Add to the project a reference to the dll containing Windows Forms control.
  4. Place WindowsFormsHost element onto WPF page.
  5. Add WindowsForms element into the child elements of the WindowsFormsHost.

After you go through all the steps, you will be able to use any WinForms control on the WPF page delivering the same functionality as on Windows forms, probably with slight limitations. To have an ability to apply to this control from the window code-behind file it is necessary to know its x:Name attribute. After that you will be able to apply to the control by its name from code.

Let us consider using controls from the .Net ModelKit Suite library on WPF pages. The library provides wide abilities to create reports, charts, pivot tables, gauges, etc. It is developed for Windows Forms and it is also possible to use it in Web and Silverlight applications, but none of the components can be used directly in WPF. So, let’s see how to use WindowsFormsHost for some of the components included in the suite.

We will create a simple report with the use of component included into the .Net ModelKit Suite library. The report will be displayed on the WPF page. To fulfill this task you need to make the following steps:

Create WPF project

Add references to PerpetuumSoft.Reporting and PerpetuumSoft.Framework dlls

Add the UserControl element to the project. This element will be a wrapper for report elements.

Place the DataSet onto the UserControl. This element will store report data.

Run DataSet.Tabels property editor, add a new table to the DataSet and set its name, for example, “Customers”.

Run Tabels.Columns property editor, add 2 columns to the table: “Name” and “Phone”.

Place ReportManager onto the form. This element is used to store information on report templates. It is possible to set data sources using this element.

Double click on the ReportManager to run its editor. Go to the Data sources tab.

It is necessary to add a data source. Click the “Add” button. In the appeared window, you need to set data source name and select the data source itself from the list. Select dataSet1.Customers table as a data source value.

Go to Reports tab, add new InlineReportSlot and click the “Run Designer” button to run report   template designer.

Click the “New document” button in the report designer and in the appeared window select “Standard report”. Report wizard will run.

Press the “Add data” button to add a new section, select Customers.Table as a data source and       move all available fields from All fields to Visible fields. After all the actions are done, wizard should  look as it is shown in the picture.

Add to the handler of OnLoad event of the UserControl code of filling report data source. For example, you can use the following code:

DataRow row = dataTable1.NewRow();

row["Name"] = “Johnson Leslie”;

row["Phone"] = “613-442-7654″;

dataTable1.Rows.Add(row);

row = dataTable1.NewRow();

row["Name"] = “Fisher Pete”;

row["Phone"] = “401-609-7623″;

dataTable1.Rows.Add(row);

row = dataTable1.NewRow();

row["Name"] = “Brown Kelly”;

row["Phone"] = “803-438-2771″;

dataTable1.Rows.Add(row);

After you added this code, you need to add code to prepare the report. You can do it using  ReportSlot.Prepare method.

inlineReportSlot1.Prepare();

Place ReportViewer onto the UserControl. This element is used to display reports. It is necessary to set its Source property to the required InlineReportSlot.

Add namespace containing UserControl to the XAML markup of the xml window:

xmlns:userControl=”clr-namespace:RSSforWPFWithUserControl”

Add the WindowsFormsHost element to the form by placing the following code into the container body:

<WindowsFormsHost

HorizontalAlignment=”Stretch”

VerticalAlignment=”Stretch”>

</WindowsFormsHost>

Add UserControl to its content:

<userControl:ReportUserControl/>

Run application and see the result.

It is preferable to execute data preparation and report building on the UserControl. It allows using all available report functionality, such as DesignTime Designer, automatic saving of reports in the application code, binding to data sources, etc.

But besides this solution, there is another way to use Windows controls in WPF. It is possible to place such elements directly in WindowsFormsHost. There are some limitations using this approach.

In order to view reports, it is necessary to place ReportViewer onto WPF page. You can do it using WindowsFormsHost element. But here you will face a problem of how to create and edit report templates and connect to data sources. It is impossible to place ReportManager onto WPF page as we placed ReportViewer, as it is a descendant from the System.ComponentModel.Component class. The problem can be solved in the following way.

In spite it is impossible to run ReportDesigner in design time to edit reports, there is always an ability to run it in runtime, using the ReportSlot.DesignTemplate method. ReportSlot is created dynamically in this case. After you made all necessary changes to the report template, it is possible to save it to a file. The file represents a usual xml file. There are two way of how to use it. The first one is to use InlineReportSlot. In this case you can just copy xml string from the template file and set this string as a DocumentStream property value. It is possible to use FileReportSlot and in this case it is just necessary to specify path to the file.

There is also a problem with data sources. If you use data sources built into a template, there are no problems; you can work with them as you did it on Windows forms. If it is impossible to set data source in this way, you can create ReportManager dynamically and add data sources there. Data source can be added using the Add function of the ReportManager.DataSources collection. You can use the following code:

reportManager.DataSources.Add(“dataSourceName”, dataSourceObject);

So, using the solutions described in the article provides the ability to use any Windows Forms control in WPF projects sometimes with slight limitations. But in spite of all limitations, this ability is actual and it will stay actual until equivalent controls are designed completely on WPF.


Download Report Sharp-Shooter…

How To: Report Sharp-Shooter - Connecting to a data source directly in a report template.

Thursday, December 18th, 2008

Very often we get questions from our customers like “Where in the report template can I set data source connection string?”, “Where can I set a command to fetch data for my report?”, “How to set fields of the database table for selected report elements to get data from?”, etc.

Today I decided to post an article to answer all these questions at once.

The matter is that Report Sharp-Shooter uses different mechanism of getting data for reports.
Report Sharp-Shooter stores reports in a special component – Report Manager. It contains report slots, which in their turn get report templates.

Report Manager has a DataSource property, and this very property sets data sources that can be used to build reports by templates contained in all report slots.

Thus, you see that report templates are tightly connected to the application and when you create a template you need to consider that data is propagated to the report from the application.
This mechanism is very convenient, when you have a lot of reports using a single data source. Then you just need to load data once and use it to generate multiple reports of different types; it significantly increases performance.

At the same time sometimes it is more convenient to have reports that are not based on application data. In other words, to set database connection string or command for fetching data directly in the report template and to get data right before the report is rendered (most similar products work in this way).

Unfortunately, Report Sharp-Shooter doesn’t provide complete mechanism of designing reports that are not based on the application data. There is no doubt that this function is very important and we are working add it to our product, but I can offer you an alternative solution of this problem right now.

Report Sharp-Shooter templates feature GenerateScript. It is executed right before report generation, that is why you can easily use it to set database connection code and get data.
Find below a sample of such Generate Script code:

try

{

DataObjects.Remove(“Persons”);

}

catch

{ }

OleDbConnection cn = new
OleDbConnection
(“Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\”database.mdb\”");


cn.Open();


string sqlCmd = “select id_person, surname, name from persons”;

OleDbDataAdapter adapt = new OleDbDataAdapter(sqlCmd, cn);

DataSet dataSet = new DataSet();

dataSet.Tables.Add(“Persons”);

dataSet.Tables["Persons"].Columns.Add(new DataColumn(“Id_person”, typeof(System.Int32)));

dataSet.Tables["Persons"].Columns.Add(new DataColumn(“Surname”, typeof(System.String)));

dataSet.Tables["Persons"].Columns.Add(new DataColumn(“Name”, typeof(System.String)));

try

{

adapt.Fill(dataSet.Tables["Persons"]);

}

catch ( Exception exc)

{

MessageBox.Show(exc.Message, “Report Sharp-Shooter”, MessageBoxButtons.OK, MessageBoxIcon.Error);

}

finally

{

cn.Close();

}

DataObjects.Add(“Persons”, dataSet.Tables["Persons"]);

The last line adds report data sources to a table.

But it is not simple, as it may seem from the first sight. The script is executed right before report generation; and it means that nothing is known about data structure when the template is generated.

That is why you need write the following code in order to get value from the table:

GetData(“”)

So, you need to remember field names, and you see that it is absolutely impossible if have a lot of them.
Let’s do as follows.

Let’s create a simple sample application. Add a DataSet and create the Persons table there. Add 3 columns: Id_person, Surname, Name. So you will get a table that is absolutely equal to to the Persons table structure that is got in the script.

Add reportManager to the application. Add the table you got to the reportManager.DataSource property.

In this way data structure will be known when designing a template.

Add report slot the reportManager – slot1; it will store edited document.

To make it more convenient to debug the template, add the “Design Template” button to our application.
Set the Click event handler:

private
void
button1_Click(object sender,
EventArgs
e)

{

slot1.DesignTemplate();

}

Run the designed application and click the “Design Template” button.

Create a report.

Copy the aforesaid code to the Generate Script.

Check the created template by generating report.

So, what we get? In fact, application propagates only data structure to the template, but the code for getting data itself is set directly in the template and is executed before it is generated. Moreover, when report is rendered we remove a data source set in the application:

DataObjects.Remove(Persons);

And add a new one got in the script instead:

DataObjects.Add(“Persons”, dataSet.Tables["Persons"]);

Then, the data source we added at the very beginning can be removed and it won’t affect report in any way.

In this way you will get report template independent from the application.

Let’s open it in the Report Designer and try to generate a report.

As you see, we get the same result.

kick it on DotNetKicks.com