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和线程,但似乎什么都做不到。提前感谢您的帮助。
在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或通常的委托方法,但适用于我的情况。