假设我在线程T上创建了一个对象O.如何从对象O内部获取线程T并在该线程上调用一个方法?这样,创建对象的表单就不需要这样:
private void ChangeProgress(int value)
{
progressBar1.Value = value;
}
void FD_ProgressChanged(object sender, DownloadEventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action<int>(ChangeProgress), new object[] { e.PercentDone });
}
else ChangeProgress(e.PercentDone);
}
这只是丑陋的并且要求使用该对象的任何人要么弄清楚在创建该对象的同一个线程上引发了哪些事件,哪些不是,并在那些不是的那些上添加if(InvokeRequired)...else
代码,或者只需在每个事件处理程序上添加代码。如果对象本身负责在正确的线程上调用事件,我认为会更优雅。这可能吗?
答案 0 :(得分:4)
使用BackgroundWorker类。它负责所有这些。请注意ReportProgress事件。
答案 1 :(得分:2)
您必须自己跟踪
class Foo {
private readonly Thread creatingThread;
public Foo() {
this.creatingThread = Thread.CurrentThread;
}
}
如果你不这样做,就没有办法知道。但你这样做的事实是一种气味。考虑使用BackgroundWorker
。
答案 2 :(得分:1)
您需要考虑以下几点:
Object O
中保留引用。可能在使用Thread.Current
静态属性的构造函数中。SynchronizationContext
相关联。 (通常,UI线程拥有它。并且为您创建的自定义线程创建一个并不容易。)Send()
上使用Post()
或SynchronizationContext
方法。答案 3 :(得分:1)
在http://www.codeproject.com/KB/threads/invoke_other_way.aspx
找到了一个不错的解决方案这是我的通用版本:
private void RaiseEventAsync(Delegate handler, object e)
{
if (null != handler)
{
List<Delegate> invocationList = handler.GetInvocationList().ToList();
foreach (Delegate singleCast in invocationList)
{
System.ComponentModel.ISynchronizeInvoke syncInvoke =
singleCast.Target as System.ComponentModel.ISynchronizeInvoke;
try
{
if ((null != syncInvoke) && (syncInvoke.InvokeRequired))
syncInvoke.Invoke(singleCast,
new object[] { this, e });
else
singleCast.Method.Invoke(singleCast.Target, new object[] { this, e });
}
catch
{ }
}
}
}
这就是你如何使用它:
protected void OnProgressChanged(DownloadEventArgs e)
{
RaiseEventAsync(ProgressChanged, e);
}
这样可以解决我的问题,而不需要使用并不总是需要的BackgroundWorker
(就像我的情况一样,我正在为已经使用不同线程对象的类创建子类)。