我正在编写一个在库中执行特定操作的类。但是操作很繁琐,我希望能够找到该类中方法的进度,以便我可以在WinForms应用程序中使用它来报告进度。
我打算在我的WinForms应用程序中的另一个线程上运行我的类,我希望该类与WinForms应用程序的关注点分开,我不想将它绑定到除了它之外的任何特定内容。确实
在库类中实现进度报告机制的最佳方法是什么?
以某种方式在类中有一个进度变量,并在我的WinForms应用程序中添加一个事件监听器是不是一个好主意?如果是的话,我该怎么办呢?
编辑:之前我使用过BackgroundWorker
类,但我的问题是我不希望我的库类与任何多线程操作有关。所以我不想在库类中调用ReportProgress
,我想(可能)在包含当前进度的类中有一个变量,我希望UI线程以某种方式“订阅”它。我不知道这是否是设计它的好方法。
答案 0 :(得分:4)
查看BackgroundWorker课程。它支持跨线程自动编组以进行进度报告,并且它有一个非常简单的事件模型用于此类支持。
编辑:鉴于您对直接使用BackgroundWorker的立场,您可能会创建一个简单的包装器:
// Error checking elided for expository purposes.
public interface IProgressReporter
{
void ReportProgress(int progress, object status);
}
public class BackgroundWorkerProgressReporter : IProgressReporter
{
private BackgroundWorker _worker;
public BackgroundWorkerProgressReporter(BackgroundWorker worker)
{
_worker = worker;
}
public void ReportProgress(int progress, object status)
{
_worker.ReportProgress(progress, status);
}
}
然后,更改要报告进度的类的构造函数(或添加属性)以接受IProgressReporter。这是一种依赖注入形式,应该有意义地允许您的对象报告进度,同时避免对线程库的特定依赖。
答案 1 :(得分:1)
在这里,您可以通过两种不同的方式发布以下两个选项,以帮助您找到正确的方向
你应该在另一个线程上执行此操作,然后从该线程更新UI线程。您通过在UI线程上执行此工作来阻止进一步处理。
如果您无法将此代码移至UI线程,那么您可以随时致电Application.DoEvents
,但我强烈建议您先探索这些选项:
System.ComponentModel.BackgroundWorker
System.Threading.ThreadPool
System.Threading.Thread
System.Threading.Tasks
namespace 第二种选择你可以这样做:
您需要将数据从一个线程转移到另一个线程。这可以通过几种方式完成......
首先,你的“后台”线程可以更新某种“CurrentStatus”字符串变量,它随着它的变化而变化。然后,您可以在表单上放置一个计时器,然后获取CurrentStatus变量并使用它更新标签。
其次,您可以使用标签控件的InvokeRequired属性,使用委托从后台线程调用操作到UI线程。例如......
private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
if (this.label1.InvokeRequired)
{
this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
return;
}
this.label1.Text = status;
}
您可以从任何线程(UI或后台)调用UpdateStatus()方法,它将检测是否需要在主UI线程上调用操作(如果是,则执行此操作)。
编辑:要实际设置线程,您可以这样做:
private void StartProcessing()
{
System.Threading.Thread procThread = new System.Threading.Thread(this.Process);
procThread.Start();
}
private void Process() // this is the actual method of the thread
{
foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
// Do processing
// Show progress bar
// Update Label on Form, "f.Name is done processing, now processing..."
UpdateStatus("Processing " + f.Name + "...");
}
}
然后当用户点击“GO”按钮时,您只需调用StartProcessing()。