C#:使用线程从另一个类更新表单属性

时间:2013-07-12 05:02:51

标签: c# multithreading class parameter-passing argument-passing

我想我已经阅读了这里和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;
    }
}

}

返回记录不是问题,只是更新进度条之类的东西现在很头疼。到目前为止,我已经尝试过代理,后台工作,BeginInvoker和线程,但似乎无法获得任何工作。提前感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分: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或通常的委托方法应尽可能使用,但适用于我的情况。