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

本文关键字:更新 表单 属性 另一个 线程 | 更新日期: 2023-09-27 18:22:13

我想我已经通读了这里和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和线程,但似乎什么都做不到。提前感谢您的帮助。

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

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

我找到了另一种方法,使用位于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;
    }

有了这些方法,所需要的就是使用所需的任何值调用setPg1AnotherThread()。我可能还会返回并将Int32重构为Int16。这不是首选的方法,应该尽可能使用BackGroundWorker或通常的委托方法,但适用于我的情况。