Search code examples
c#multithreadingformscrystal-reportsreport

C# Creating/Closing Multiple Forms (Threads) - Crystal Report Viewer


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


Solution

  • 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