我试图从不同的线程访问我的程序中的3个列表框元素,并继续获得跨线程异常。我需要一种方法从另一个线程访问我的列表框,并将该代码放在一个名为threadUtilities.cs的单独类中。这样,我所有与线程访问相关的代码都将处于单独的类中。任何人都可以提供通用代码来访问另一个线程的任何列表框吗?
答案 0 :(得分:2)
您希望从UI线程获取SynchronizationContext
,然后将其提供给后台线程。
根据您使用的技术,派生的SynchronizationContext
将可用,但这并不是真正关注的问题; Current
property将返回当前安装的那个,Windows Forms和WPF将为您安装适当的版本。
将SynchronizationContext
传递给您要拨打电话的主题后,您可以调用Send
method(类似于Invoke
method)或Post
method(类似)到BeginInvoke
method)取决于您的需求。
以下是一个例子:
public void Button1_OnClick(sender object, EventArgs e)
{
// Get the current SynchronizationContext.
// NOTE: Must make the call on the UI thread, NOT
// the background thread to get the proper
// context.
SynchronizationContext context = SynchronizationContext.Current;
// Start some work on a new Task (4.0)
Task.Factory.StartNew(() => {
// Do some lengthy operation.
...
// Notify the user. Do not need to wait.
context.Post(o => MessageBox.Show("Progress"));
// Do some more stuff.
...
// Wait on result.
// Notify the user.
context.Send(o => MessageBox.Show("Progress, waiting on OK"));
});
}
另外,应该提到BackgroundWorker
class在幕后为你做所有这些事情;如果此模型适合您直接使用SynchronizationContext
,那么请务必使用它(BackgroundWorker
类在内部使用SynchronizationContext
。
答案 1 :(得分:1)
取决于它是WinForms还是WPF。如果是WinForms,请使用Control.Invoke方法。如果是WPF,请使用Dispatcher。
简单的WinForms示例:
ListBox listBox = GetListBoxFromSomewhere();
if( listBox.InvokeRequired )
listBox.Invoke(() => listBox.Items.Add("Some item");
else
listBox.Items.Add("Some item");
您可以为UI访问创建一个通用函数,如下所示:
void PerformUIOperation(Control c, Action action)
{
if( c.InvokeRequired )
c.Invoke(action);
else
action();
}
像这样使用:
PerformUIOperation(listBox, () => listBox.Items.Add("Some item");