工作线程添加到BindingList时的跨线程操作异常

时间:2010-08-12 20:59:33

标签: c# winforms multithreading data-binding bindinglist

我有一个需要将项目添加到BindingList的工作线程。但是,BindingList数据绑定为DataGridView。所以,当我尝试添加到列表中时,我得到一个InvalidOperationException (Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.)

通常情况下,您可以这样做:

if(winformControl.InvokeRequired) {
    winformControl.Invoke(MethodDelegate);
}

但是,数据绑定会让事情变得混乱,因为看不到Winform控件。我所拥有的是以下行,它抛出异常:

ClassInstance.MyBindingList.Add(myObject);

如果你有专门针对这种情况的解决方案,那很好。

如果没有,我怎样才能让工作线程告诉我的主线程执行一个特定的方法(工作线程提供了几个参数)?这可能是一个更好的选择,因为我的工作线程实际上正在做一堆东西(比如写入数据库),而且我不确定一切是否是线程安全的。我是一名学生,也是多线程学的新手,但这真的不是我的强项。

4 个答案:

答案 0 :(得分:1)

此处的一个选项是告诉BindingList<T>使用同步上下文like this - 但是,这可能不是最佳方法。我想知道您是否可以通过事件或类似事件公开您的数据(而不是直接添加到列表中) - 然后让您的UI通过发送到正确的线程并添加到UI模型来处理事件。

答案 1 :(得分:1)

在你的worker类构造函数中,试试这个:

private System.Threading.SynchronizationContext mContext = null;

/// <summary>
/// Constructor for MyBackgroundWorkerClass
/// </summary>
public MyBackgroundWorkerClass(System.Threading.SynchronizationContext context)
{
    mContext = context;
}

然后,当您需要在UI线程上调用某些内容时:

private void CallOnTheUiThread(object dataToPassToUiThread)
{
    // Make sure the code is run on the provided thread context.
    // Make the calling thread wait for completion by calling Send, not Post.
    mContext.Send(state =>
        {
            // Change your UI here using dataToPassToUiThread.  
            // Since this class is not on a form, you probably would 
            // raise an event with the data.
        }
    ), null);
}

从UI线程上的表单创建工作类时,这将作为同步上下文传递。

private void Form1_Load(object sender, EventArgs e)
{
    var worker = new MyBackgroundWorkerClass(SynchronizationContext.Current);
}

答案 2 :(得分:0)

您可以将事件发送到主,UI,线程,并且有:

if (this.InvokeRequired)
{
    this.Invoke(...);
}

所以你正在测试主窗口本身。

答案 3 :(得分:0)

如果能够满足要求,BackgroundWorkers很容易实现。

定义在后台线程上运行的DoWork方法,例如保存到数据库。 DoWork完成时调用RunWorkerCompleted方法。 RunWorkerCompleted在UI线程上运行,您可以毫无问题地更新视图列表。

// on the UI thread
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += RunWorkerCompleted;
worker.RunWorkerAsync("argument");

活动:

static void DoWork(object sender, DoWorkEventArgs e)
{
    e.Result = "4";
}

static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
        string a = (string)e.Result;
        Console.WriteLine(a);
    }
    else
    {
        Console.WriteLine(e.Error.Message);
    }
}