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
Finally solved the problem. So this is my solution:
For everybody who is creating a new Thread for a Crystal Report Viewer: watch out!
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