我有多个类在线程中执行冗长的任务,并希望它们输出某种进度,所以我可以将它显示在进度条或计数器上。
我可以使用在接口中定义的事件或委托,但似乎每个实现我都需要编写完全相同的FireEvent代码来检查事件是否为null并提升它,如果不是的话。
使用抽象类似乎也很糟糕,因为这样的功能不属于最顶级的类,这意味着我必须再次在不同的地方实现它。
如何以最可重复使用的方式执行此操作,无需重复代码?
答案 0 :(得分:6)
如果您对其他主题使用BackgroundWorker
,则可以使用ReportProgress
方法,这会引发ProgressChanged
事件。
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
答案 1 :(得分:2)
我通常反转视图和模型之间的关系,以便视图了解模型。在此示例中,进度对话框将引用IProgress
接口。然后它连接到ProgressChanged
事件,因此视图可以在需要时自行更新。这样做的主要优点是各个类中的代码不会重复 - 只有那些告诉我们剩下多少内容的代码才在这些类中。通过这种方式,可以非常轻松地锁定经常发出进度状态的类的进度更新。
只是为了让你了解我通常做的事情:
interface IProgress
{
event EventHandler ProgressChanged;
int ProgressTarget { get; }
int CurrentProgress { get; }
}
一个实施班。我甚至不知道它是否能够正常工作 - 这只是给人一种如何实现这个界面的印象。
class StreamCopier: IProgress
{
private Stream _source;
private Stream _destination;
public StreamCopier(Stream source, Stream destination)
{
_source = source;
_destination = destination;
}
public void WriteAll()
{
int b;
while ((b = _source.ReadByte()) != -1)
{
_destination.WriteByte((byte)b);
EventRaiser.Raise(ProgressChanged, this); // Just one call here! Can't be less
}
}
public event EventHandler ProgressChanged;
public int ProgressTarget {
get { return (int)_source.Length; }
}
public int CurrentProgress {
get { return (int)_destination.Position; }
}
}
然后是EventRaiser
课程。注意如何在参数堆栈上传递处理程序引用,因此不需要对'tmp'进行线程安全的复制! :)
static class EventRaiser
{
public static void Raise(EventHandler handler, object sender, EventArgs args)
{
handler(sender, args);
}
public static void Raise(EventHandler handler, object sender)
{
Raise(handler, sender, EventArgs.Empty);
}
}