0
votes

I have been working on a problem for 6 hours now and I still can't figure it out. I hope that you can help me.

I am working on a project that has to do with the Crystal-Report-Engine (SAP, Newest Version on a .NET Framework 4.0, 32-bit C# application). Basically, it works like that:

I am opening my Main-Form which dynamically shows me all the parameter for a specific report-file (.rpt). After entering my parameter values, the application is doing some syntax checks and passes the parameters to the ReportDocument.

The problem: Now I am creating a new ReportForm (my own class) which is a derived class from Windows.Form with a CrystalReportViewer. The ReportForm sets the crystalReportViewer-Object's ReportSource to the previously created ReportDocument with the passed through parameters. -> The Crystal Report Viewer is loading, when the form shows up.

Problem #1: I still want to be able to access my Main-Form while the Crystal Report Viewer is loading the Report (sometimes this could take about 5-6 minutes) - for example to create some other reports while the previous report is still loading. This is only possible, if I create a thread for this new form - but this (sometimes) causes a ContextSwitchDeadlock, because I would have to create a new Thread, which is creating a new GUI-Control (the ReportForm).

Problem #2: If I do not create a new Thread and start the new ReportForm for example with myNewReportForm.Show(), then I have to wait until the Report is loaded and have no possibility to get access to my Main-Form (until the report is completely loaded). The next Problem is that I have no possibility to Close/Exit/Kill my application, because the Thread is still loading the report - I also have to wait, until the report is loaded. But I want to be able to shutdown the application whenever I want to (Main-Form AND all ReportForms)

It basically looks like that (short version):

/* pass parameters to reportDocument */
ReportForm reportForm = new ReportForm(reportDocument);
reportForm.Show();

In ReportForm:

crystalReportViewer.ReportSource = this.reportDocument;

Do you have any ideas?

Best, Cylence

2
You should be fixing your report. It should not take 5-6 min to load a report. How much data are you pulling and displaying in the report? How are you opening myNewReportForm.Show() in the formload or in the button click?smr5
Thanks for your answer. The report usually does not take that long...But there is still a possibility that viewer runs into a timeout (e.g. database connection info does not exist any longer / is wrong) - and I want to make sure that in this case, the user can still be working (go back to main form and start another report while report runs in timeout) or the user can close the application. I am opening myNewReportForm.Show() with a button in the Main-Form after passing through the parameters and creating the new ReportForm(ReportDocument)-Object.Cylence
Well in that case I suggest you open myNewReportForm.Show() in the formload of the main form. This way when you open formload it will open that form and let it run and you can still work in your main form.smr5
Good Idea but this does not really help, because the Forms are created dynamically - depends on how many reports the users wants to have during the run time. The next problem is that I will not be able to work in my main form while the reportViewer is loading inside the form.Cylence

2 Answers

1
votes

Finally solved the problem. So this is my solution:

For everybody who is creating a new Thread for a Crystal Report Viewer: watch out!

Problem solving - SAP

Here is a general solution:

/* In Main Form */

            /*...*/

     ThreadStart threadStart = delegate() { reportThreadFunction(reportDocument); };
     Thread reportThread = new Thread(threadStart);

     /* Setting the ApartmentState to STA is very important! */
     reportThread.SetApartmentState(ApartmentState.STA);
     reportThread.Start();
}

         /* ... */

private void reportThreadFunction(ReportDocument reportDocument)
{
     ReportThread rt = new ReportThread(reportDocument);
     newReportForm = rt.Run();
     Application.Run(newReportForm);
     newReportForm.Show();
}


/* Class ReportThread */
public class ReportThread
{
    ReportDocument reportDocument;
    CrystalReportViewer crv;
    Template template;

    public ReportThread(ReportDocument reportDocument)
    {
        this.reportDocument = reportDocument;
    }

    public ReportForm Run()
    {
        ReportForm rf = new ReportForm(reportDocument);
        return rf;
    }
}

Best, Cylence

0
votes

Thanks! This resolve for me!

Just for simplify the code above:

 /* In Main Form */

 /*...*/
 ThreadStart threadStart = delegate({reportThreadFunction(reportDocument);};
 Thread reportThread = new Thread(threadStart);

 /* Setting the ApartmentState to STA is very important! */
 reportThread.SetApartmentState(ApartmentState.STA);
 reportThread.Start();
 }

 private void reportThreadFunction(ReportDocument reportDocument)
 {
     //Create and Start the form
     Application.Run(new ReportThread(reportDocument));
 } 


 /* Class ReportThread */
 /* A form whith a CrystalReportViewer inside*/
 public partial class ReportThread : Form
 {
     public CrystalReportViewer crv; //initiated in partial class off form

     public ReportThread(ReportDocument reportDocument)
     {
        InitializeComponent();
        CrystalReportViewer.ReportSource = reportDocument;
     }
 }