How to create a common header over a dynamic report created with CrossBand

You can often face a necessity to create a tabular report without setting table columns statically in the designer, but adding them if and when needed before report generation. To implement this you can use the CrossBand element. The use of the element itself should not bring any difficulties. You can find more information about it in the following article: http://helpcenter.perpetuumsoft.com/KB/a106/crossband.aspx

Although the use of cross band element itself it not difficult, the task to add a general header over the column headers may become a challenge.

Unfortunately such behavior cannot be implemented with the help of standard controls and we will need to take advantage of scripts.

Let’s consider now a common case. The algorithm can be much easier for custom cases, but if you understand the general approach on this sample, you won’t have any problems with simpler things. 

So, in general we will work with the following:

  1. We have a table. Part of the columns are created dynamically, but there are some columns which are set in the template and they are not created dynamicall, but the header should be placed over all of the columns.
  2. Quantity of the dynamic columns can be any. Thus, a table can take one or more pages width. And the header should be located on all pages.
  3. If the current page is not the last, the header should not have a border on the right side. If it is not the first – it should not have the left border.
 

The green space here is a general header, the blue space – header of the area set in the template, the red one is column headers and light blue and light red are the content of the columns set in the designer and generated dynamically.
To display the header, we add an additional header over the columns header and add there 3 cross bands. First one will be for the first page, the second one will be for the middle pages, and the last header – for the last page.
We could use just one cross band (and even do not use it at all), but this would require implementing logic using many scripts. But doing the proposed way, we will use abilities of the controls:

We won’t have text in the headers for the middle and last pages, but if you set text for all cross bands, the text will be displayed on all pages.

The whole code that manages header generation will be placed to the header2.GenerateScript.

First, we need to know width of the dynamic column, static column and a number of the dynamic columns. Pay attention that we passed columns quantity along with the data source. This allows us to avoid casting data sources to the specific types:

double commonColumnWidth = crossBand2.Size.Width;

double continousColumnWidth = crossBand1.Size.Width;

int columnsCount = (int)GetData("Data.ColumnsCount");

Then we can calculate general width of the dynamic part and space available on the page:

double totalAdditionalLength = continousColumnWidth * columnsCount;

double pageWidth = Engine.UsedWidth + Engine.FreeWidth;

Now we have enough information to calculate the header of the first page. Please pay attention that we need to calculate the first page separately because of the static area on it.:

double firstPageFreeWidth = pageWidth - commonColumnWidth;

int firstPageMaxElementsCount = 
(
int)(firstPageFreeWidth / continousColumnWidth);

double firstPageMaxElementsWidth = 
firstPageMaxElementsCount * continousColumnWidth;

double firstPageCaptionWidth = commonColumnWidth + 
((totalAdditionalLength > firstPageFreeWidth) ? 
(firstPageMaxElementsWidth) : (totalAdditionalLength));

Now we can delete the elements displayed on the first page from the calculation:

totalAdditionalLength -= firstPageCaptionWidth;

columnsCount -= firstPageMaxElementsCount;

Then we calculate the middle and last pages. We also need to know how many elements fit the page:

double middlePageCaptionWidth = 0;

double lastPageCaptionWidth = 0;

int maxElementsPerPage = (int)(pageWidth / continousColumnWidth);

Then we calculate the pages:

if (columnsCount > 0)

{

    int pagesCount = columnsCount / maxElementsPerPage;

    middlePageCrossBand.InstanceCount = pagesCount;

    middlePageCaptionWidth = maxElementsPerPage * continousColumnWidth;

    columnsCount -= maxElementsPerPage * pagesCount;

    lastPageCaptionWidth = columnsCount * continousColumnWidth;

    lastPageCrossBand.InstanceCount = 1;

}

else

{

    textBox7.StyleName = "BorderClosed";

}

Please note that if all elements fit one page then we need to display the finished border of the header. To do this, we change the default style (without the right border) to the style with the full borders.

Now we just need to specify the calculated values:

firstPageCrossBand.Size = 
new Vector(firstPageCaptionWidth, firstPageCrossBand.Size.Height);

middlePageCrossBand.Size = 
new Vector(middlePageCaptionWidth, middlePageCrossBand.Size.Height);

lastPageCrossBand.Size = 
new Vector(lastPageCaptionWidth, lastPageCrossBand.Size.Height);

Worth to mention that the suggested solution is not the only one (probably even not the most optimal one). Scripts features provide wide opportunities and open many doors – just don’t miss it!

You can download a sample application here: http://www.perpetuumsoft.com/Support/samples/CrossBandCommonHeaders.zip

Add Feedback