1

我想我已经阅读了这里和 MSDN 上的每一篇文章,但我认为我是一个特例,因为大多数文章和帖子似乎都没有涵盖我想要做的事情。

我正在浏览一个 Excel 表格并提取记录并将它们传递出去,以便它们可以转换为不同的文件类型。我正在尝试使用线程,所以我不会占用 UI,一切都很好,除了更新表单中的进度条。下面是需要更新表单的类:

public class ExcelItem : Form1
{
    private string inFile { get; set; }

    public ExcelItem(string file)
    {
        inFile = file;
    }

    public string getExcelData()
    {
        string result = "";
        int numRec = 0;
        int recCount = 0;
        Excel.Application xlApplication;
        Excel.Workbook xlWorkbook;
        Excel.Worksheet xlWorksheet;
        Excel.Range xlRange;

        xlApplication = new Excel.Application();
        xlWorkbook = xlApplication.Workbooks.Open(File, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
        xlWorksheet = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(2);
        xlRange = xlWorksheet.UsedRange;

        int rCnt = xlRange.Rows.Count;
        int cCnt = xlRange.Columns.Count;

        //for (int k = 1; k <= xlWorkbook.Worksheets.Count; k++)
        //    MessageBox.Show("Found worksheet " + k);

        // get the number of records in tne sheet and use numRec to set progress bar max
        for (int i = 1; i <= xlRange.Rows.Count; i++)
        {
            for (int j = 1; j <= xlRange.Columns.Count; j++)
            {
                if ((((Excel.Range)xlWorksheet.Cells[i, j]).Value2 != null) && (((Excel.Range)xlWorksheet.Cells[i, j]).Value2.ToString() == "Date of Birth"))
                {
                    numRec++;
                    //code for updating progress bar max would go here
                }
            }
        }

        // iterate through records in sheet, use recCount to set progress bar value and return records
        for (int i = 1; i <= xlRange.Rows.Count; i++)
        {
            for (int j = 1; j <= xlRange.Columns.Count; j++)
            {
                if ((((Excel.Range)xlWorksheet.Cells[i, j]).Value2 != null) && (((Excel.Range)xlWorksheet.Cells[i, j]).Value2.ToString() == "Date of Birth"))
                {
                    result += Environment.NewLine;
                    recCount++;
                    // code for updating progress bar value would go here
                }

                if ((((Excel.Range)xlWorksheet.Cells[i,j]).Value2 != null) && (((Excel.Range)xlWorksheet.Cells[i, j]).Value2.ToString() != ":"))
                {
                    result += (string)((Excel.Range)xlWorksheet.Cells[i, j]).Value2.ToString() + Environment.NewLine;
                }
            }
        }
        return result;
    }
}

}

返回记录不是问题,只是更新进度条之类的东西现在很头疼。到目前为止,我已经尝试过委托、backgroundworker、BeginInvoker 和线程,但似乎没有任何效果。提前感谢您的帮助。

4

2 回答 2

1

在 WinForms 中,您需要运行Invoke方法,以更新Control另一个Thread.

于 2013-07-12T05:44:27.813 回答
0

我找到了另一种使用位于 System.Runtime.Remoting.Messaging 中的 AsyncCallBack 来解决此问题的方法,该方法需要包含在内。下面实际上是我最终做的:

AsyncCallBack 方法(pbvalue 是一个私有全局变量):

public void setPg1InAnotherThread(Int32 val)
    {
        new Func<Int32>(setPbValue).BeginInvoke(new AsyncCallback(setPbValueCallback), null);
    }

    private Int32 setPbValue()
    {
        Int32 result = recCount;
        return result;
    }

    private void setPbValueCallback(IAsyncResult ar)
    {
        AsyncResult result = (AsyncResult)ar;
        Func<Int32> del = (Func<Int32>)result.AsyncDelegate;
        try
        {
            Int32 pbValue = del.EndInvoke(ar);
            if (pbValue != 0)
            {
                Form1 frm1 = (Form1)findOpenForm(typeof(Form1));
                if (frm1 != null)
                {
                    frm1.setPbValue(pbValue);
                }
            }
        }
        catch { }
    }

剩下的唯一一件事是获取对主表单的引用,这是我无法通过文件处理程序或委托完成的,因为我 a) 在单独的线程中,b) 在单独的类中。

private static Form findOpenForm(Type typ)
    {
        for (int i = 0; i < Application.OpenForms.Count; i++)
        {
            if (!Application.OpenForms[i].IsDisposed && (Application.OpenForms[i].GetType() == typ))
            {
                return Application.OpenForms[i];
            }
        }
        return null;
    }

有了这些方法,只需使用您需要的任何值调用 setPg1InAnotherThread() 即可。我也可能会回去将 Int32 重构为 Int16。这不是首选的方法,应尽可能使用 BackGroundWorker 或通常的委托方法,但适用于我的情况。

于 2013-08-04T00:23:02.290 回答