Category: Active Reports 6

In the ActiveReport-ReportStart section of your parent report, you can assign any object type to the Report object variable, ‘UserData’

UserData is a public object of the DataDynamics.ActiveReports.ActiveReport.

Scenario:

Let’s say you are using a Watermark in your parent report. The Watermark is embedded into your parent report at design time. You want to share this Watermark with your sub reports. To do this, store the image of this Watermark in the UserData object. Now it can be accessed by a sub report.

If you are like me and have a report that dynamically calls a sub report that then calls sub reports (using the sub report control), you may have run into the occasional sub report overlap nightmare. The latest encounter for me had to do with textboxes on the sub reports having properties of CAN GROW, MULTILINE, and WORD WRAP. Because these textboxes can grow, depending on whether these textboxes are populated with data less than 5 characters or many characters, overlapping the next sub report can occur.

With trial and error, I have found two solutions to the problem. You could even use both solutions to cover all bases. Before I get into explaining the solutions, let me give you more background on what I am trying to accomplish with these reports.

The image below represents a sub report that is called dynamically from the parent report. Based on my experience and knowledge (I could be wrong), sub reports cannot call sub reports dynamically. If they could, I would not have written this article and you most likely would not be reading it. Instead, I had to drag ten sub report controls to the surface of this sub report.

Notice how all the sub reports are flush to the left and bottom of the previous sub report (Well, except the last one for the purpose of presentation). This could potentially cause overlapping nightmares, especially if these reports have textboxes that CAN GROW.

Without going into the whys and how comes, I am simply going to offer my solutions.

The image below represents a small amount of padding I placed between each sub report control. The reason I have such a small amount of padding is because the white space will take up real estate on the rendered report and can look ugly if the gap is too big. This small gap is exactly what you need to fix the problem.

Do you want double insurance? The second solution expounds on the first solution. The image below represents placing a line control (make it INVISIBLE) between each sub report in the gap we provided in the first solution. The line control ensures that the previous sub report renders completely.

Instead of passing a parameter to a report with a value set to preexisting data, you can instead prompt the user running the report with an inputBox (Microsoft.VisualBasic) in order to capture the data on the fly to be used in the report.

For example, let’s create a report that displays three textboxes (First, Middle, and Last Name) as such:

In the VB script behind the design, dim three variables that will hold the values entered via the inputBox.

In order to debug active reports in the Visual Studio IDE solution, you need to set EnableScriptDebugging = True.

In this example, I want to debug a sub report. When creating a sub report dynamically in the main report that calls the sub report, after creating the ActiveReport object for the sub report,

Dim _SubReport As New DataDynamics.ActiveReports.ActiveReport

set debugging to true like this:

_SubReport.EnableScriptDebugging = True

In Visual Studio, you can’t set breakpoints at design time inside a report, so if you are trying to debug a sub report knee deep in your main report, you would need to set a break point in your harness that calls the report:

mReport.Run()

You then would have to step through each line of code by hitting F8 until you enter the sub report you want to debug. But that could take forever!

There is faster way to this.

In your sub report, place the following line of code at the top of your script:

Debug.Assert(False)

When you run the main report (And you can remove the breakpoint on your mReport.Run() statement), this line of code ‘Debug.Assert(False)’ will cause an exception error. A dialog box will present itself. You must click RETRY.

After you click RETRY, the IDE will enter your sub report highlighted ‘green’ the statement ‘Debug.Assert(False)’ as an exception. Hit F8 once, and the next line of code is highlighted ‘yellow’ and you are now debugging.

Put this class in your solution. Change ‘[object name of your collection]’ to be the name of your object that defines your collection.

Public Class SimpleComparer
Implements IComparer(Of [object name of your collection])
Private _propertyToSort As String
Private _sortOrder As System.Windows.Forms.SortOrder = System.Windows.Forms.SortOrder.Ascending
Public Sub New(ByVal propertyToSort As String, ByVal sortOrder As System.Windows.Forms.SortOrder)
MyBase.new()
_sortOrder = sortOrder
_propertyToSort = propertyToSort
End Sub
Public Property SortOrder() As System.Windows.Forms.SortOrder
Get
Return _sortOrder
End Get
Set(ByVal Value As System.Windows.Forms.SortOrder)
_sortOrder = Value
End Set
End Property
Public Property PropertyToSort() As String
Get
Return _propertyToSort
End Get
Set(ByVal Value As String)
_propertyToSort = Value
End Set
End Property
Public Function Compare(ByVal x As[object name of your collection], ByVal y As [object name of your collection]) As Integer Implements System.Collections.Generic.IComparer(Of[object name of your collection]).Compare
Dim prop As Reflection.PropertyInfo = x.GetType.GetProperty(Me.PropertyToSort)
If Me.SortOrder = System.Windows.Forms.SortOrder.None OrElse prop.GetValue(x, Nothing) = _
prop.GetValue(y, Nothing) Then
Return 0
Else
If prop.GetValue(x, Nothing) > prop.GetValue(y, Nothing) Then
If Me.SortOrder = System.Windows.Forms.SortOrder.Ascending Then
Return 1
Else
Return -1
End If
Else
If Me.SortOrder = System.Windows.Forms.SortOrder.Ascending Then
Return -1
Else
Return 1
End If
End If
End If
End Function
End Class

Call your IComparer class with your collection as follows. Replace [property of your object within the collection to sort on] with the property name to sort. You can also choose Ascending or Descending to sort by.

[your collection].Sort(New SimpleComparer(“[property of your object within the collection to sort on]”, System.Windows.Forms.SortOrder.Ascending))

You can create a page header for a report, but if that report is used as a sub-report, the page header and page footer of that report does not render. Instead, only the parent report’s page header and page footer will display.

Good news. This can be done by using a group header on your subreport instead. Here is how:

1) Create a group header for your sub report. Inside the group header, add a textbox (let’s say we call it txtGroupHeader). In the code-behind of your sub-report, you can add any value you want to the textbox as such:

txtGroupHeader.text = "Group Header information"

2) Set the RepeatStyle property of your group header to ‘OnPage’

3) What if you want to suppress the group header of your sub-report on page 1 of the rendered report? This may be desirable if at the top of your detail section of your parent report, you have a report header, and only want to see the group header on preceding pages of your sub-report.

To do this, add the following logic to your script behind.

a) At the top of your script of the sub-report, add the following boolean variable:

Dim mGroupHeaderFirstTime as boolean = True

b) In your group header format sub-routine of the sub-report, add the following logic:

The following illustrates one way to communicate information from a sub report back to its parent or main report. It may not be the cleanest way, but it works.

Let’s say you have a main report, RPT-001.rpx. This report has a page header. We already suppress the page header for page 1 and produce it for the remainder of the pages. (Interrogate rpt.pagenumber = 1 in the ActiveReport_PageStart to handle this).

Now, this report calls five sub reports. The user asks to suppress the page header of the entire report for the last sub report, SUB-RPT-005.rpx (as we will call it here for example).

Here is how it can be done:
1) Add a textbox to your report header of the main report (Let’s call it txtSuppress). Set its Visible property to False. Set its DataField property to String.Empty (or blank).
2) In the ActiveReport_PageStart sub routine of the main report, add the following logic:

All the sub reports get processed in the main report’s ActiveReport_ReportStart section first. That means the logic (Step 3 above) in our last sub report, SUB-RPT-005.rpx, sets the DataField property of our invisible textbox, txtSuppress, on our main report next.

Lastly, the ActiveReport_PageStart sub routine of the main report gets executed. Since we initialized our txtSuppress.DataField = String.Empty, the If statement (Step 2 above) checks for a value of “SUPPRESS” in order to set the visibility of our controls in the page header of the main report to False and sets the height = 0 with the result of NOT seeing the page header for sub report SUB-RPT-005.

In this example, we take an unsorted Product Collection called ProductCollection that is assigned

to our report Data Source. We instantiate another Product Collection for sorting called

sortedProductCollection. Using a Do Loop, we read the Product Collection and build the

sortedProductCollection in sorted order. When done, we overlay the ProductCollection

in the Data Source with our sortedProductCollection

‘Sort the Product Collection

Dim sortedProductCollection As New ProductCollection

‘A class that defines a collection

Dim mCounter = 0
Dim mLoopComplete = False
Do Until mLoopComplete = True
For Each item As product In rpt.DataSource(0).ProductCollection
If item.product_number.Value = mCounter + 1 Then
sortedProductCollection.Add(item)
Exit For
End If
Next
mCounter += 1
If rpt.DataSource(0).ProductCollection.Count = sortedProductCollection.Count Then
mLoopComplete = True
End If
Loop
rpt.DataSource(0).ProductCollection = sortedProductCollection