To use third-party software in the project is like shooting Niagara Falls. From the first sight, the Fall looks breathtaking and promising, but you always should remember that you can’t see all hidden rocks and must be equipped for emergencies!
The same is with software. You just can’t see the future and get prepared to it! Even when it seems that you found the right tool, you never know what your customer will want you to do tomorrow, what tasks you will get in the future. Personally I’ve never met customers who can formulate their requirements sufficiently. Have you?
So, now the story… Several months ago, I faced the necessity to develop a large-scale ERP solution for my company with a plenty of specific features. I don’t want to bother you with all the peculiarities of my application, I just must tell you that it required to generate hundreds of different reports and it was impossible to foresee all the features of the reports which my customer may need with the lapse of time.
And the main challenge was how to find the best reporting tool for my application! I asked myself: “What criteria shall I use to choose the right tool which will not to make me fall from 53 meters of Niagara Falls into the boiling water of everyday support and debugging when my customers wish to realize one or another task?” A reporting system is a growing like living body which should be constantly supported and updates. If your reporting tool cannot fulfill this living body needs, here you start feeling like falling from the much talked-about Niagara ….
So, after days of researching and testing and thinking and fighting, I found out some criteria which describe the right reporting solution and secure myself from the majority of potential risks if a reporting tool does not provide the functionality I may need later:
- Convenient report templates designer.
It‘s a great piece of luck when a reporting tool has a designer that allows the creation of the majority of every-day and task-specific reports quick and intuitively. Even if the functionality of a reporting tool can be extended, the designer must provide the ability which ensures the solving of all your main tasks. But, none of the reporting tools provides all the features you may need. So, the next main criteria is - Open plug-in architecture.
Open plug-in architecture is vital! If you have some task that is impossible to solve with the granted features, at least, you will be able to implement the required features yourself. The reporting tools which have open plug-in architecture and support for scripting are flexible enough to solve the most complex tasks. Open plug-in architecture allows the realization of the required functionality and the use of new features in further development. - Ability to manipulate the source data in a report template.
Ability to manipulate the source data directly in a report template is very convenient; it allows you to get any new data which are calculated on the basis of the source data. And to do this, you just need to make changes in a report template. - Ability to dynamically set parameters in a report template depending on the source data.
Ability to dynamically set template parameters on the basis of the source data allows the flexible data presentation depending on the source data values. A template becomes versatile and this allows you to minimize the number of the report templates to be developed. It is especially vital when the further development is required. - Ability to output any data with any settings in any part of a final document.
Ability to output any data in any place of the rendered report allows you to generate a whole report or a part of it manually, if the reporting tool features don’t provide solution for one or another task. Of course, you must avoid creating reports manually. But this additional flexibility will make you confident that you will be able to present the data in any way you may ever need.
So, after days of research and testing of plenty of reporting tools available on the software market from different vendors worldwide, I found the product that met almost all my requirements, Report Sharp-Shooter. It is not the ideal reporting tool, but it really surprised me with the flexibility it offers. I finished my ERP solution 5 months ago. It works very well and my customers are really satisfied. And as I predicted I had to develop the diversity of reports gathered like a snowball. But I must admit that I handled it all, and glad to share my experience with you now.
First of all, what I like most in Report Sharp-Shooter is that it has open plug-in architecture.
A document and its elements themselves define the logic not only of their output and behavior in the designer, but what is the most important, they define the logic of a document generation. This means that you can easily extend the functionality of the tool by redefining the logic of the provided elements or by creating your own.
For example, the product has the element for outputting the list footer. And in most of my reports, it was required to output the footer not right after the list, but at the bottom of the page where the list ends.
I solved this issue very simple: I created a new element by redefining the logic of the existing one. Here, I added a new property, GrowToBottom, which decides whether the list footer must be placed at the bottom of the page.
I redefined the generation logic of this element in the Render method where I limited free space on the generated page to shift the elements which are generated by the base class at the bottom of the page:
Inherits PerpetuumSoft.Reporting.DOM.Footer
Private _growToBottom As Boolean = False
<System.ComponentModel.Category("Behavior")> _
<System.ComponentModel.DefaultValue(False)> _
<PerpetuumSoft.Framework.Serialization.XSerializable()> _
<PerpetuumSoft.Reporting.DOM.ReportBindable()> _
Public Property GrowToBottom() As Boolean
Get
Return _growToBottom
End Get
Set(ByVal value As Boolean)
_growToBottom = value
End Set
End Property
Public Overrides Sub Render()
If Me.GrowToBottom Then
MyBase.Prepare()
If (MyBase.Engine.FreeHeight > MyBase.Size.Height) Then
Engine.UsedHeight = (Engine.UsedHeight + (MyBase.Engine.FreeHeight - MyBase.Size.Height))
End If
End If
MyBase.Render()
End Sub
End Class
<System.ComponentModel.DefaultValue(False)> _
<PerpetuumSoft.Framework.Serialization.XSerializable()> _
<PerpetuumSoft.Reporting.DOM.ReportBindable()> _
Public Property GrowToBottom() As Boolean
Get
Return _growToBottom
End Get
Set(ByVal value As Boolean)
_growToBottom = value
End Set
End Property
Public Overrides Sub Render()
If Me.GrowToBottom Then
MyBase.Prepare()
If (MyBase.Engine.FreeHeight > MyBase.Size.Height) Then
Engine.UsedHeight = (Engine.UsedHeight + (MyBase.Engine.FreeHeight - MyBase.Size.Height))
End If
End If
MyBase.Render()
End Sub
End Class
As you can see, it is very easy. I also would like to draw your attention that the behavior of the control in the designer can be defined by standard attributes having the same destination as for Visual Studio, as well as by special ones.
For example the ReportBindable attribute notifies that it is possible to assign binding for this property. That means that a new “GrowToBottom” property can be assigned not only as a constant but as a calculable value.
A new control can be easily registered in the designer, and before this, I remove the old control, since I do not need it.
PerpetuumSoft.Reporting.DOM.ReportControl.ControlTypes.Add(GetType(CustomControl.AdvancedFooter))
What made me a fan of this product is the support for scripting in this reporting tool.
You can use any .NET programming language (VB.NET or C#) as a script language. It allows the realization of a lot of tasks saving great deal of time, since the majority of other reporting tools have a special scripting language that has to be learnt from scratch.
Report Sharp-Shooter scripts provide full access to all report elements and you can manipulate them programmatically from scripts. A report template and a report itself represent open object model.
Scripts allow the getting of the information about the current report generation state and influence it.
And you can use any features of your application or third-party libraries from scripts!
There is the ability to assign the expression for each property and the value of this property will be calculated dynamically.
When any report element is generated, a special script is executed and there you can make all the required settings.
So, the scripts in Report Sharp-Shooter makes possible to not only adjust the provided features, but to develop new ones!
Now, I would like to show some examples for you. I used VB.NET language here.
I will demonstrate you how to implement relatively simple functionality, but on the other nand, it could be practically impossible to do this without scripting. To make it easier for understanding, I got the date using the GetData function (“SourceName.FiledName”) where SourceName is the name of the source and FieldName is the name of the source field.
So, for example, we want to set the appearance of the data depending on their values.
To do this we need to dynamically define the style for an element that displays a value.
So, we assign the following expression for the Style property of a report element:
iif(, “Hightlight”, “Normal”)
- is some criterion on the basis of the source data.
“Highlight” and “Normal” are the names of styles from the styles table which I have defined before.
So, for example, we want to highlight all products whose price is more than $ 20.00.
iif(GetData(“Products.UnitPrice”) > 20, “Hightlight”, “Normal”)
And that’s it!
One more sample. For example we want to number the pages within some group of data.
Of course, the product has a variable for continuous numbering, but for this particular case, we can take advantage of scripts.
To do this, we define a common variable containing a new page:
private GroupPageCount as integer
Initiate the variable before the generation GroupPageCount = 0;
Reset the variable in the group footer GroupPageCount = 0;
Increase counter when creating a page GroupPageCount += 1
And use the following expression to display the page number: “Page ” & PageCount.
So, you see how simple it is. At least, I hope that I managed to make my idea clear. I managed to avoid falling from Niagara Falls and wish you the same!
Enjoy coding!