Question

Give the below code what would be the best way to cancel the Background Worker, so that Excel properly closes. For instance if you user closes the form in the middle of the excel process. The below code works fine. Just stared using Background Workers, so just getting the hang of it and want to do it the proper way. Basically, the below code will let users choose what columns (fields) they want to export using checkboxes. the int[] cols is the corresponding number to column they selected.

*Here is the updated code. I used the suggestion with the cancellation and break during the loop along with the basic bgw msdn article. I couldn't think of another way to check when to exit Excel, so I used the row count. Thanks for the tip.

    private void XLWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        this.XLWorker.ReportProgress(-1);

        xl._Application app = new Microsoft.Office.Interop.Excel.Application();
        xl._Workbook workbook = app.Workbooks.Add(Type.Missing);

        // creating new Excelsheet in workbook 
        xl._Worksheet worksheet = null;

        // get the reference of first sheet. By default its name is Sheet1. 
        // store its reference to worksheet            
        worksheet = workbook.Sheets[1];
        worksheet = workbook.ActiveSheet;

        // changing the name of active sheet 
        worksheet.Name = "User Details";
        worksheet.Cells.Font.Size = "12";

        int headerCounter = 1;
        foreach (int col in _export)
        {
            worksheet.Cells[1, headerCounter] = _form.DataGridResultsSet.Columns[col].HeaderText;
            headerCounter++;
        }

        //Format zip code
        xl.Range rngResult = null;
        xl.Range FindRange = null;

        int rowCount = worksheet.UsedRange.Rows.Count;
        for (int columnIndex = 1; columnIndex <= worksheet.UsedRange.Rows.Count; columnIndex++)
        {
            FindRange = worksheet.UsedRange.Columns[columnIndex];
            rngResult = FindRange.Find("ZipCode", Type.Missing, Type.Missing, Type.Missing, Type.Missing, xl.XlSearchDirection.xlNext, Type.Missing, Type.Missing, Type.Missing);

            if (rngResult != null)
            {
                rngResult.EntireColumn.NumberFormat = "00000";
            }
        }

        //Add rows
        int colCounter = 0;
        int pending = 0;
        for (int i = 0; i < _form.DataGridResultsSet.Rows.Count - 1; i++)
        {
            if ((XLWorker.CancellationPending == true))
            {
                e.Cancel = true;
                break;
            }
            else
            {
                foreach (int col in _export)
                {
                    worksheet.Cells[i + 2, colCounter + 1] = _form.DataGridResultsSet.Rows[i].Cells[col].Value.ToString();
                    colCounter++;
                }
                colCounter = colCounter - _export.Length;
                XLWorker.ReportProgress((i * 100) / _form.DataGridResultsSet.Rows.Count - 1);
            }
            pending = i;
        }
        int cancel = pending + 2;
        if (cancel < _form.DataGridResultsSet.Rows.Count)
        {
            Marshal.FinalReleaseComObject(rngResult);
            Marshal.FinalReleaseComObject(FindRange);
            Marshal.FinalReleaseComObject(worksheet);

            rngResult = null;
            FindRange = null;

            worksheet = null;

            workbook.Close(false, Type.Missing, Type.Missing);

            app.Application.Quit();
            app.Quit();

            Marshal.FinalReleaseComObject(workbook);
            workbook = null;

            Marshal.FinalReleaseComObject(app);
            app = null;

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        else
        {
            //Format sheet
            worksheet.Columns.AutoFit();
            worksheet.Cells.HorizontalAlignment = xl.XlHAlign.xlHAlignLeft;
            worksheet.Cells.Font.Size = "11";
            xl.Range rngB = (xl.Range)worksheet.Rows[1];
            rngB.Font.Bold = true;

            //Worker completed
            XLWorker.ReportProgress(100);

            Marshal.FinalReleaseComObject(rngResult);
            Marshal.FinalReleaseComObject(FindRange);
            Marshal.FinalReleaseComObject(rngB);
            Marshal.FinalReleaseComObject(worksheet);
            Marshal.FinalReleaseComObject(workbook);

            rngResult = null;
            FindRange = null;
            rngB = null;
            worksheet = null;
            workbook = null;

            //Sleep unti export is complete
            Thread.Sleep(1000);

            //Show Excel
            app.Visible = true;

            //Cleanup
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }

    private void XLWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (e.ProgressPercentage < 0)
        {
            this.buttonActExport.Text = "Calculating...";
            toolStripProgressBar1.Visible = true;
            toolStripStatusLabel1.Visible = true;
        }
        else if (e.ProgressPercentage != 100)
        {
            this.buttonActExport.Text = ("Exporting: " + e.ProgressPercentage.ToString() + "%");
            toolStripProgressBar1.Value = e.ProgressPercentage;
        }
        else
        {
            this.buttonActExport.Text = "Done";
            toolStripProgressBar1.Value = e.ProgressPercentage;
        }
    }

    private void XLWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if ((e.Cancelled == true))
        {
            this.buttonActExport.Text = "Canceled!";
        }

        else if (!(e.Error == null))
        {
            this.buttonActExport.Text = ("Error: " + e.Error.Message);
        }
        else
        {
            this.buttonActExport.Text = "Done!";
        }
        this.buttonActExport.Text = "Export";
        this.buttonActExport.Enabled = true;
        toolStripProgressBar1.Visible = false;
        toolStripStatusLabel1.Visible = false;
        toolStripProgressBar1.Value = 0;
    }
Was it helpful?

Solution

You need to do "Cooperative Cancellation" you need to modify your code to "cooperate" with the cancellation process and gracefully stop what it was trying to do. What that will require is you check workerXL.CancellationPending throughout your code and if it returns true you do the appropriate steps to "cancel" the operation like disposing of the necessary resources and closing the excel instance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top