cancel
Showing results for 
Search instead for 
Did you mean: 

Invalid Section Height when I load the nth subreport

0 Kudos

I am attempting to load multiple sub-reports into a master report document. The process is:

  1. Use the RAS SDK to obtain a reference to the detail area
  2. Add a section to the detail area
  3. Import the subreport into the detail area

The code is pretty simple as well.

        private ReportDocument AddSubReportToParent(string subReportName, string fileName)

        {

            try

            {

                CrystalDecisions.ReportAppServer.ReportDefModel.ISCRArea detailArea = _crystalDocument.ReportClientDocument.ReportDefController.ReportDefinition.DetailArea;

                CrystalDecisions.ReportAppServer.ReportDefModel.Section section = new CrystalDecisions.ReportAppServer.ReportDefModel.Section();

                string sectionName = "Section" + subReportName.Replace(".", "");

                section.Name = sectionName;

                section.Kind = CrystalDecisions.ReportAppServer.ReportDefModel.CrAreaSectionKindEnum.crAreaSectionKindDetail;

                section.Width = headerArea.Sections[0].Width;

               

                _crystalDocument.ReportClientDocument.ReportDefController.ReportSectionController.Add(section, detailArea, -1);

                _crystalDocument.ReportClientDocument.SubreportController.ImportSubreport(subReportName, _configSettings.InputPath + "\\" + fileName, section);

                ReportDocument subreport = _crystalDocument.OpenSubreport(subReportName);

                return subreport;

            }

            catch (Exception ex)

            {

                Logger.ErrorException(this.GetReportBuilderErrorText(this.GetReportBuilderErrorText(String.Format("Unable to add subreport '{0}' from file {1} to custom Crystal Report", subReportName, fileName))), ex);

                throw;

            }

        }

However, when I attempt to load the 41st report (or sometimes greater) the ImportSubreport method throws an exception with the message, "Invalid Section Height". Note that I have one section for each report. This is to make it easier to place the subreport on in the document and on it's own page.

I cannot seem to determine what is going wrong. Why would the 41+ import fail?

I am using Crystal Reports Version for Visual Studio .NET, 13.0.8.

Accepted Solutions (1)

Accepted Solutions (1)

former_member183750
Active Contributor
0 Kudos

This is a by design limit of the RAS SDK. Only work-around; place the subreport into a different section(s).

As a by the by, stuffing so many subreports into one report does have consequences that you may not want...

For one, if the detail section returns 100 records, each subreport is run by the report engine consuming a print job. You will quickly run out of print jobs as these are set at 75 by default. E.g.; with 40 subreports, you will be running 4001 report jobs (40subrpt *100recs + 1 main rpt). You can increase this limit, but at the expense of higher stresses on the hardware.

The performance of these reports will be very poor.

- Ludek

Senior Support Engineer AGS Product Support, Global Support Center Canada

Follow us on Twitter

0 Kudos

Sorry, I made a mistake in my original post. I am adding the subreoort to new section in the detail area. Each sub report is added to its own section. Our master report returns zero records so we don't reprint each subreport.

Can you clarify what the by design limitation is? Is there a limit on the number of sections in the detail area or a limit on the number of subreports than can be loaded into a section or is it something else.

Thanks for your help.

former_member183750
Active Contributor
0 Kudos

That KBA did not resolve the issue unfortunately. I tried calling each of the following after I added a section to a report with no luck. I also tried calling these after I importing the subreport, No luck there either.

                sectionController.AutoFitSections(null);

                sectionController.AutoFitSections(detailArea);

                sectionController.AutoFitSections(section);

The app still fails when trying to load the 41st report so I do not appear to be anywhere near the section limit...although..if there are sections without the subreports themselves, would these add up to the 120 section within a given area limit within the final report? I threw in some section counts for the detail area before and after adding the section and subreport and they total does not appear to include the sections in the subreports.

0 Kudos

Hi Ryan,

Why are you opening every subreport after you add it? Must be a lot of missing code because you are also not setting the subreport links up...

What happens if you do this in CR Designer? Add a section then insert the subreport and another section then insert the subreport....

Then try to preview it? You are possibly running out of room to fit all those subs onto a single page.

Any Conditional Supression happening also?

Change your default printer to Landscape to see if that extends the number of subreports you can add also, curious if it's the page formatter throwing the error.

And, not sure if they improved this but in crpe32 there is a built in limit of 40 subreports, it's a macro the SDK uses that goes back to the beginning in crpe32 and quite possibly limited in RAS also.

You may want to rethink this report creation format. Adding that many subreports could easily be replaced by adding Groups and setting the group data on the same info the subreports are returning.

The look would be the same basically...

If you must though, another way is to create a template report with 120 Details with dummy subreports in it and after updating each subreport with yours then simply delete the Detail sections that do not have a subreport replaced by your code.

So there is a lot of missing code here but that may not be an issue, for now...

Don

0 Kudos

Hi Don

To answer some of your questions...

The reason we have so many subreports is that we have an application that renders many different data driven charts client side in Flex (up to 60). We need the ability to print these charts to PDF in a user defined order. Our solution was to use Crystal Reports (we use it for other reporting needs as well). We have one subreport per chart so that we can load these in the order that the charts are displayed in our application. For each subreport we set the record selection formula for the subreport so that it returns the proper dataset for each chart. This is why we return the subreport in our method, so we can later apply the proper record selection formula for each each and set any required parameters on the reports (like chart caption).

As to the other questions, I'll need to get back to you on those. It'll take a little bit of time to try each one.

Thanks,

Ryan

0 Kudos

Hi Ryan,

Ah, that would be the easiest way to do what you are doing then and because there is no main report data linking is not required.

Did this work in a previous version of CR runtime?

To simplify, export the report that has 40 subreports and then start adding in CRD.

Also before adding try verify the database also and if you get some message box pop indicating the report has been updated it indicates some object or collection is not up to date...

Something else you may want to try is when you hit to 40 limit, save the report using the .SaveAs method, open it up again and then continue on. May give us a clue as to where and possibly why it's failing also.

private void btnSaveReportAs_Click(object sender, System.EventArgs e)
{
    saveFileDialog.Filter = "Crystal Reports (*.rpt)|*.rpt";
    if (DialogResult.OK == saveFileDialog.ShowDialog())
    {

        object saveFolder = System.IO.Path.GetDirectoryName(saveFileDialog.FileName);
        string saveFileName = System.IO.Path.GetFileName(saveFileDialog.FileName);

        if (!IsRpt)
        {
            rptClientDoc.SaveAs(saveFileName, ref saveFolder,
                (int)CdReportClientDocumentSaveAsOptionsEnum.cdReportClientDocumentSaveAsOverwriteExisting);
        }
        else
        {
            try
            {
                rpt.SaveAs(saveFolder + "\\" + saveFileName, true);
            }
            catch (Exception ex)
            {
                btnSQLStatement.Text = "ERROR: " + ex.Message;
                // SetLogonInfo_Click();
                //return;
            }
        }
    }
}

Don

0 Kudos

Hi Ryan,

No need to test, Ludek found this KBA:

1670453 - RAS Can't Create Objects in Crystal Report Sections Past
40

So your only work around is to create a template report with dummy subreports already embedded in it.

Here's something to get you started:

btnReportObjects = Text box

subreportClinetDocument.IsImported is a new API so you may need to upgrade CR for VS.

btnReportObjects.Text = "";
flcnt = 0;
foreach (String resultField in rptClientDoc.SubreportController.GetSubreportNames())
{
    SubreportController subreportController = rptClientDoc.SubreportController;
    SubreportClientDocument subreportClinetDocument = subreportController.GetSubreport(resultField);
    if (subreportClinetDocument.IsImported)
    {
        textBox1 = "Imported: " + subreportClinetDocument.SubreportLocation.ToString();
        btnReportObjects.Text += textBox1;
        btnReportObjects.AppendText(" 'End' \n");
        ++flcnt;
        btnCount.Text = flcnt.ToString();
    }
    else
    {
        textBox1 = "embedded: " + " " + resultField.ToString();
        btnReportObjects.Text += textBox1;
        btnReportObjects.AppendText(" 'End' \n");
        ++flcnt;
        btnCount.Text = flcnt.ToString();
    }

    CrystalDecisions.CrystalReports.Engine.ReportObjects crReportObjects;

    //set the crSections object to the current report's sections
    CrystalDecisions.CrystalReports.Engine.Sections crSections = rpt.ReportDefinition.Sections;

    if (resultField.ToString() == "World Sales Report.rpt")
    {
        //loop through all the sections to find all the report objects
        foreach (CrystalDecisions.CrystalReports.Engine.Section crSection in crSections)
        {
            crReportObjects = crSection.ReportObjects;
            //loop through all the report objects to find all the subreports
            foreach (CrystalDecisions.CrystalReports.Engine.ReportObject crReportObject in crReportObjects)
            {
                if (crReportObject.Kind == ReportObjectKind.SubreportObject)
                {
                    CrystalDecisions.ReportAppServer.ReportDefModel.Section rasSection;
                    rasSection = rptClientDoc.ReportDefController.ReportDefinition.FindSectionByName(crSection.Name);
                    CrystalDecisions.ReportAppServer.Controllers.SubreportClientDocument MyNewSub;
                    MyNewSub = rptClientDoc.SubreportController.GetSubreport(resultField.ToString());

                    CrystalDecisions.ReportAppServer.ReportDefModel.SubreportObject objSubreport = rptClientDoc.ReportDefController.ReportObjectController.GetAllReportObjects()[crReportObject.Name] as CrystalDecisions.ReportAppServer.ReportDefModel.SubreportObject;
                    CrystalDecisions.ReportAppServer.ReportDefModel.SubreportObject objSubreport2 = (CrystalDecisions.ReportAppServer.ReportDefModel.SubreportObject)objSubreport.Clone(true);
                    rptClientDoc.ReportDefController.ReportObjectController.Remove(objSubreport);
                    CrystalDecisions.ReportAppServer.ReportDefModel.SubreportLinks mySubLinks = rptClientDoc.SubreportController.GetSubreportLinks(objSubreport2.SubreportName.ToString());
                    mySubLinks.RemoveAll();

                    objSubreport2.Left = 10;
                    objSubreport2.Height = 10;
                    objSubreport2.Width = 10;
                    objSubreport2.Name = "sub1";
                    objSubreport2.SubreportName = "sub1";
                    //rptClientDoc.ReportDefController.ReportObjectController.Modify(rptClientDoc.ReportDefController.ReportObjectController.GetAllReportObjects()[crReportObject.Name] as CrystalDecisions.ReportAppServer.ReportDefModel.SubreportObject, objSubreport2);
                    rptClientDoc.ReportDefController.ReportObjectController.Add(objSubreport2, rasSection, -1);
                }
            }
        }
    }
}

I don't recall now what I was testing but all of the basics are there to replace the dummy subreports with your new ones.

I DID NOT test this with more than 40 subreport objects either so you may still run into the SDK limit. We may have to ask the Report Designer Resource if this can be handled in the report by using Conditional suppression...

Don

0 Kudos

Hi Don, Ludek,

The link you supplied is inaccessible to me. The page cannot be displayed. Perhaps it is not a public link? I would be interested in reading the details. It'll be important for me to succinctly explain the issue to my team so we can decide what our best approach is. We may ultimately decide to limit the application to only display 40 charts; however, I'll take a look at the code you provide to see if we can work around it.

Thanks,

Ryan

0 Kudos

Hi Ryan,

KBA was under a product that required a Support Contract, Ludek changed it so it will eventually show up in SCN.

Nothing much in the KBA other than saying it's a limit and we've asked R&D multiple times to change it and it's been rejected each time because it would cause all sorts of Design/Designer problems.

I had a re-look at the header file for crpe32 and there is no way we can change this. It's a Macro we use in all of the Section and area functions and to change it would require a full regression test on all products so it's not going to happen.

I do know though that code I pasted above will allow you to modify and existing subreport. .Modify doesn't not have the limit as the .Add does. So if your team decides to allow more than 40 charts then this would be the way to work around it.

Also, I was talking to the Report Design Resource and a few question and point:

Is the data source the same for all or most and if not can it all be combined into one data source?

If it is then we can possibly use Conditional Suppression to "hide" the ones not required.

Let me know what you decide and I'll do more testing also.

Thanks again

Don

0 Kudos

Hi Don,

The data source is not the same for each chart. While it's all in the same database we reference different tables and fields for each chart in the subreports. The data is sufficiently different that we cannot combine it into a single table.

We've decided to apply the workaround you proposed with the dummy subreports. However, given the changes we'll need to make to our existing processes (from configuration, reports, code, etc.) it may be a few weeks until we have a final resolution. Thanks for you help in confirming that this was not an issue with our code and is a Crystal Reports limitation. I'll update this post with more info as soon as we have it.

Thanks,

Ryan

0 Kudos

Hello Don.

I finally have a little time to look at the workaround you provided. Unfortunately, I am not sure if this is going to work for us as we make *heavy* use of non-embedded subreports. That is, our code is relying on ImportSubreport to load our subreports into the master report. I don't immediately see a way to clone a subreport (as shown in the workaround) and change it's properties such that it would "load" from the subreport on disk. Using the above we'd workaround it seems we'd need each report that the user *might* include in the master report just for cloning and then replacing on of the templates. Is this correct? Is there a simpler way?

Ultimately, what we want to achieve is that the user has X charts, A, B, C, D, and E. And we want them to be able to choose which charts should be included in the master report and in which order. For instance, they may only want C, A, and E.

Thanks,

Ryan

Answers (0)