我有一个UserControl,可以完成一些后台工作。当事物有一个已完成的事件,用户控件订阅了该事件。由于事件是在一个单独的线程中引发的,并且事件处理程序对用户控件进行了一些更新,因此我使用以下命令启动事件处理程序:
private void ProcessProcessCompleted(object sender, ProcessCompletedEventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action<object, ProcessCompletedEventArgs>(ProcessProcessCompleted),
new[] { sender, e });
return;
}
// Update the user control, etc.
}
这样可以正常工作,除非在进程完成之前关闭包含用户控件的表单。我试图取消订阅用户控件的dispose方法中的事件,但这似乎只是工作的一部分时间。我该怎么做?想避免将它包装在try catch块中。在我调用之前是否有InvokeIsPossible
属性或我可以查看的内容?
答案 0 :(得分:3)
您可以使用SynchronizationContext
,它是在.NET 2中引入的,以简化线程间通信:
将其初始化为表单的thread sync'context:
syncContext = SynchronizationContext.Current;
像这样更改ProcessProcessCompleted
方法:
private void ProcessProcessCompleted(object sender, object e)
{
this.syncContext.Post(new SendOrPostCallback(delegate(object state)
{
// Update the user control, etc.
})
, null);
}
您可以在此处阅读SynchronizationContext
:
http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx
或http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx
答案 1 :(得分:1)
虽然它没有同步线程,但您可以使用Control.IsDisposed
检查是否可以在当前状态下调用Invoke()
方法(Form
继承自Control
):
if (!this.IsDisposed)
{
// tatata...
}
为了保证它是有效的,你必须将它包装在lock(syncobject) { ... }
块中以检查自定义布尔标志,同样在lock
- Form_Close
- {{1}}事件中更改该标志。
答案 2 :(得分:1)
我使用的是一个我称之为线程门的类,我通常会继承它,但你可以实例化它或者其他什么。这使用SynchronizationContext类。
public class ThreadGate { private readonly SynchronizationContext _synchronizationContext;
public ThreadGate()
{
_synchronizationContext = AsyncOperationManager.SynchronizationContext;
}
public void Post<T>(Action<T> raiseEventMethod, T e)
{
if (_synchronizationContext == null)
ThreadPool.QueueUserWorkItem(delegate { raiseEventMethod(e); });
else
_synchronizationContext.Post(delegate { raiseEventMethod(e); }, null);
}
}
我这样用:
Post(OnProgressChanged,new ProgressChangedEventArgs(1,null)));
或者如果你喜欢Action
Action<string> callback;
Post(callback,str));