/// <summary> /// Handler that calls the GetConfigData for the GenerationItem. This should alway be /// on the Caller's thread /// </summary> /// <param name="args"></param> private void ProcessSendGetConfigData(Object args) { ProcessSendGetConfigDataEventArgs sendArgs = (ProcessSendGetConfigDataEventArgs)args; sendArgs.curItem.GetDataHandler(this, sendArgs.getDataSourceArgs); if (sendArgs.fillParameterArgsList.Count != 0) { //List<ReportFillParameterEventArgs> //sendArgs.fillParameterArgsList //fist postion the "data pointer" to the correct item/folder foreach (ReportFillParameterEventArgs curFillArgs in sendArgs.fillParameterArgsList) { //not a path so easy.. //subscriber probably not doing anything with it if (curFillArgs.PathType == PathType.None) { sendArgs.curItem.FillParameterHandler(this, curFillArgs); continue; } //so this is a path.. need to call for all the items. ReportFillParameterEventArgs curPathFillArgs = curFillArgs.FirstChild; bool atDataPosition = false; ReportFillParameterEventArgs lastPathFillArgs = null; //First get to the correct data position while (curPathFillArgs != null && atDataPosition == false) { switch (curPathFillArgs.PathType) { case PathType.SelectedItem: case PathType.SelectedFolder: case PathType.FolderParent: case PathType.FolderRoot: { lastPathFillArgs = curPathFillArgs; sendArgs.curItem.FillParameterHandler(this, curPathFillArgs); curPathFillArgs = curPathFillArgs.FirstChild; break; } default: atDataPosition = true; break; } } //the data to get is not defined so the dataPosition defines the data if (atDataPosition == false) { if (lastPathFillArgs.Values != null) { curFillArgs.Values.AddRange(lastPathFillArgs.Values); } continue; } //now try to get the data foreach (ReportFillParameterEventArgs dataPathFillArgs in lastPathFillArgs.Children) { switch (dataPathFillArgs.PathType) { case PathType.CursorFolder: case PathType.CursorChildFolders: case PathType.CursorItems: { sendArgs.curItem.FillParameterHandler(this, dataPathFillArgs); if (dataPathFillArgs.Values != null) { curFillArgs.Values.AddRange(dataPathFillArgs.Values); } break; } case PathType.CursorDescendantFolders: case PathType.CursorDescendantItems: { //RM could do both DescendantFolders and DescendantItems at the same //time, but guessing that only one will be used in any path break; } } } }//end foreach(fillParameterArgsList) } sendArgs.Validated = sendArgs.report.ValidateParameters(sendArgs.parameterNamesToValueMap); }
/// <summary> /// Worker thread metod that does the work of generating the report(s) /// </summary> private void WorkerProc() { try { //loop thru all the reports to generate foreach (ReportGenerationItem curItem in this.generationParameter.GenerationItems) { ////NOTE: at somepoint could have a factory to create ////the correct IStaticReport Object but for now since it is ////all crystal Just create a crystal report Object IStaticReport report = new Crystal.CrystalReport(); lock (currentReportSync) this.currentReport = report; HashSet <string> requiredFieldNames = new HashSet <string>(); Dictionary <string, List <ReportParameterValue> > parameterNamesToValueMap = new Dictionary <string, List <ReportParameterValue> >(); //get the pre-configuration data from the IStaticReport Object //the pre-configuration data is infomation about the report that //is needed to configure the report. //in most cases this would load the report template get a list of needed parameters //and a list of needed fieldNames report.PopulateReportConfiguration(this.generationParameter, curItem, requiredFieldNames, parameterNamesToValueMap); ReportGetDataSourceEventArgs getDataArgs = new ReportGetDataSourceEventArgs(report, requiredFieldNames); ReportGetDataSourceEventArgs originalGetDataArgs = getDataArgs; //build fillParamsArgs tree List <ReportFillParameterEventArgs> fillParamArgsList = this.CreateParameterArgsList(report, parameterNamesToValueMap); ProcessSendGetConfigDataEventArgs sendArgs = new ProcessSendGetConfigDataEventArgs(); sendArgs.curItem = curItem; sendArgs.report = report; sendArgs.getDataSourceArgs = getDataArgs; sendArgs.fillParameterArgsList = fillParamArgsList; sendArgs.parameterNamesToValueMap = parameterNamesToValueMap; //sendArgs.parameterNamesToValueMap = parameterNamesToValueMap; //is there is a syncContext then can send request back to caller thread if (this.SyncContext != null) { //want to get this back to the caller thread to get the Config Data //especially the parameterValues. Might want to split the call up //make blocking send call back to caller thread to get the configuration data this.PostOrSend(false, new SendOrPostCallback(this.ProcessSendGetConfigData), new Object[] { sendArgs }); } else { //no syncContext so call on this thread this.ProcessSendGetConfigData(sendArgs); } if (sendArgs.Validated == false) { //TODO: !!!RM LOCALIZE //notify any subscribers of progress this.Notify(new ReportTaskStatusEventArgs(report, this, TaskStatus.Info, string.Format("completed generation: {0}", curItem.TemplatePath), null, false)); continue; } if (curItem.ReportTranslation != null) { getDataArgs = curItem.ReportTranslation.GetTranslatedObject(sendArgs); if (getDataArgs == null) { continue; } } Object curItemDatsSyncObject = getDataArgs.DataSourceSyncObject; // get the sync Object as soon as the GetConfig() returns. //Call IReportObject to configure the report. This will probably not build the report, but it could //it would all depend on the impl of IStaticReport // if it did then the BuildDocumentForView or export calls below would be faster report.ConfigureReport(curItem, getDataArgs, parameterNamesToValueMap); //TODO: !!!RM LOCALIZE //notify any subscribers of progress this.Notify(new ReportTaskStatusEventArgs(report, this, TaskStatus.Started, string.Format("starting generation: {0}", curItem.TemplatePath), null, false)); //if lock Object not null lock it if (curItemDatsSyncObject != null) { lock (curItemDatsSyncObject) { if (curItem.GenerationType == ReportGenerationType.ShowReportInDlg) { report.BuildDocumentForView(); } else { report.Export(); } } } else { if (curItem.GenerationType == ReportGenerationType.ShowReportInDlg) { report.BuildDocumentForView(); } else { report.Export(); } } //TODO: !!!RM LOCALIZE //notify any subscribers of progress this.Notify(new ReportTaskStatusEventArgs(report, this, TaskStatus.Info, string.Format("completed generation: {0}", curItem.TemplatePath), null, false)); //if gen type is show then need to post a message back to //the caller thread to show the window. doning this after //sending completed message if (curItem.GenerationType == ReportGenerationType.ShowReportInDlg) { this.PostOrSend(false, new SendOrPostCallback(this.ShowReport), new Object[] { report }); } } } catch (ThreadAbortException) { //catch the abort, and cancel the task Thread.ResetAbort(); this.isCanceled = true; } catch (Exception ex) { System.Windows.MessageBox.Show(ex.ToString()); //catch any other ex and set the property. //the task should never throw will be up to caller to determine what to do with //the exception this.error = ex; } finally { //all done this.SetTaskCompleted(); } }