C#:Listbox CrossThreading问题

时间:2011-06-06 14:17:05

标签: c# synchronization

我试图从不同的线程访问我的程序中的3个列表框元素,并继续获得跨线程异常。我需要一种方法从另一个线程访问我的列表框,并将该代码放在一个名为threadUtilities.cs的单独类中。这样,我所有与线程访问相关的代码都将处于单独的类中。任何人都可以提供通用代码来访问另一个线程的任何列表框吗?

2 个答案:

答案 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");