Active Reports – How to access a public variable on a parent report from a sub report.

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.

You can write the code in vbscript like this:

Sub ActiveReport_ReportStart 
    rpt.UserData = rpt.Watermark
    . . . . . . .
End Sub

In your sub report, you may want to display the Watermark depending on some condition.

You can access the UserData object that was set in your parent report from your sub report like this:

If "Some Condition" = True Then
    rpt.ParentReport.Watermark = Nothing
Else
    rpt.ParentReport.Watermark = rpt.ParentReport.UserData
End If

If would like to learn how to access controls and their properties on a parent report from a sub report, you can check out my article on the subject here:

http://www.jamesandchey.net/?p=559

Active Reports – Sub reports overlapping each other when rendered.

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.

subreportflush

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.

RENDER-ISSUE-01

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.

RENDER-ISSUE-02

 

Hope this helps!

Active Reports 6 – Inputbox

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:

Inputbox-001

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

Dim mFirstName As String = String.Empty
Dim mLastName As String = String.Empty
Dim mMiddleName As String = String.Empty

In the ReportStart sub routine section of the report,  write the code that will prompt the InputBox.

mFirstName = inputBox("What is your first name?", "FIRST NAME")
mMiddleName = inputBox("What is your middle name?", "MIDDLE NAME")
mLastName = inputBox("What is your last name?", "LAST NAME")

Executing the report will display the inputBox like this:

Inputbox-002

After clicking “OK”, two more inputBox’s will appear for the Middle and Last Name.

After entering John Michael Doe, the report will then render in the viewer and look like this:

Inputbox-003

You can get the code here. The file is called TestInputbox.rpx.
http://sdrv.ms/17yvYud

Active Reports 6 – Enable Script Debugging and force a breakpoint using Debug.Assert(False) in a sub report

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.

At this time, you can set your breakpoints and walk through the code.

 

Microsoft Visual Studio / Active Reports 6 – How to sort your collections using IComparer

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))

Active Reports 6 – How to display page header information on a subreport within a parent report

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:

Sub MyGroupHeader_Format
    If mGroupHeaderFirstTime = True Then
       mGroupHeaderFirstTime = False
       txtGroupHeader.Visible = False
       MyGroupHeader.Height = 0
    Else
       textboxes.Visible = True
       txtGroupHeader.text = "Customer #: 11223344"
       MyGroupHeader.Height = 0.328
    End If
End Sub

 

 

Active Reports 6 – How to communicate from sub report to parent report

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:

If txtSuppress.DataField = "SUPPRESS" Then
    ‘Set all your controls Visible property = False
    ‘Set the Height of your page header Name = 0
Else
    ‘Set all your controls Visible property = True
    ‘Set the values of all your controls for display
    ‘Set the Height of your page header Name = design-time height
End If

3) In the last sub report, SUB-RPT-005.rpx, add the following logic to the ActiveReport_ReportStart sub routine:

rpt.ParentReport.Sections("your main report’s page header Name").controls("txtSuppress").DataField = "SUPPRESS"

So, what is going on here?

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.

Active Reports 6 – Sort a collection in Active Reports

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