![]() |
Desktop Development »
Printing »
General
Beginner
License: The GNU Lesser General Public License
Object-oriented Printing with Inka, Part 1By Artem SmirnovThe basics of Inka, an open source printing component |
VB 9.0.NET 3.5, WinForms, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This is the first part of a series of articles about Inka, an open source reporting and printing engine for the .NET platform. This part is about getting started with Inka, and preparing and printing a basic report using your custom objects.
Most reporting engines follow the database-oriented approach to printing. Typically, you print data that is fetched from a database, sorted, formatted, grouped, or shaped in some other way in order to become more usable. In the .NET world, you can use data coming from a dataset, but the basic idea is the same. You take a relational database (or its snapshot), and you move your data straight to the presentation layer. Although it might seem convenient from the dran-n-drop perspective, this approach has several unpleasant side effects:
This might be an acceptable way of doing things for a Microsoft Access report, or even for a .NET hobbyist, but violating such core design principles is not an option for any serious project. As I couldn't find any open source project for printing, I decided to write my own.
Inka is different. Inka doesn't care where you get your data from: a database, a Web service, or created manually. What she cares about is your domain structure: objects, properties, collections, and relationships.
You can download Inka from the SourceForge site.
To print your data:
Inka.Report object or (better) inherit from this class. Inka.WinForms.ReportPrinter object using the prepared Report object. Print method. Let's print a HelloWorld string.
Each report should have one or more sections, each having one or more elements, including other sections. So, in order to display a string, which corresponds to a LabelElement, we have to create at least one section, add it to our report, and add a label to it:
Public Class HelloReport
Inherits Report
Dim mainSection As New Section
'It makes sense to create the report structure in the constructor
Public Sub New()
mainSection.AddElement(New LabelElement With {.Text = "Hello world"})
Me.Sections.Add(mainSection)
End Sub
End Class
Obviously, this report doesn't need any data sources.
It would be tempting to just add a Print method to the Report class, or even inherit from System.Drawing.Printing.PrintDocument, as it is recommended in most tutorials. However, it would introduce an unnecessary dependency, at the same time making it harder to test and extend. What I really wanted is to make the Report class merely a structure that holds sections, services, and other vital data. In other words, it should be passive.
So, I added another class whose sole responsibility is printing reports. The code required to print a report is this:
Dim report As New HelloReport
Dim printer As New Inka.WinForms.ReportPrinter(report)
printer.Print()
You might consider adding a Print method to the Report class as an extension method.
Now, let's modify our requirements. Suppose the text should say «Hello name», where name should be set at runtime. The most straightforward way of achieving this is to set the DataSource property of the container section to an appropriate object, and use a DataElement to display the data. Let's review these steps in more detail.
The most obvious way would be to set the DataSource property to the string that contains the name we need. This approach works with other objects, but fails with strings. Why? Remember that String is IEnumerable, so the layout engine will produce several sections. For example, if the name is «Bob», we'll have three sections containing «Hello B», «Hello o», «Hello b». So, we have two choices: either encapsulate the name in a custom object, or create a string array of one element.
The DataElement is the base class for all elements displaying data bound text. Its DataObject property is the object used in calculating the actually printed text. The Text property serves as the formatting string. So, suppose we have an object whose Name property is the name we need, then we should set the Text property of our element to «Hello [Name]». Note that the property name should be put in square brackets. You can also use several fields in a single element, like «Hello [Name] [LastName]».
If, however, we decided to use a string array for the data source, we should have set the Text to «Hello []». Here the square brackets without a field name indicate that we should use the object itself (more precisely, its ToString method) rather than its property.
Putting it all together, we have:
Public Class HelloReport
Inherits Report
Dim mainSection As New Section
Public Sub New()
mainSection.AddElement(New DataElement With {.Text = "Hello [Name]"})
Me.Sections.Add(mainSection)
End Sub
Sub SetData(ByVal data As Object)
mainSection.DataSource = data
End Sub
End Class
Usage:
Dim report As New HelloReport
report.SetData(New With {.Name = "Bob"})
Dim printer As New Inka.WinForms.ReportPrinter(report)
printer.Print()
Finally, let's see a more realistic example, in which we have several «rows» of data. We'll be using a list of custom objects as our data source:
Dim dataSource() As Object = {New With {.Name = "Bob"}, _
New With {.Name = "Fyodor"}, _
New With {.Name = "Abdullah"}}
report.SetData(dataSource)
We don't make any modifications to the report source. However, when we print our report, we notice that the rows are superimposed. So, we set the Size property for the section:
Dim mainSection As New Section With _
{.Size = New Utils.Rectangle(0, 20), _
.KeepTogether = Section.KeepTogetherType.Detail}
The other parameter influences the way the size of the section is calculated. Note that the width is not relevant for a section. In future releases, the height will be calculated automatically (with a possibility of manual adjustment).
The sample code included in the download contains the report displaying our custom objects, and the code required to preview it. I decided to save you some paper, so the actual printing code is commented out.
We have seen the most basic operations one expects from a reporting engine: displaying static text and data rows. In the next part, I'll show you how to implement different kinds of grouping, add aggregate functions, and solve paging issues.
| You must Sign In to use this message board. | ||||||||
|
||||||||
|
||||||||
|
||||||||
|
||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 27 Feb 2009 Editor: Deeksha Shenoy |
Copyright 2008 by Artem Smirnov Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |