6

我有一个工作线程需要将项目添加到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

4 回答 4

1

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

于 2010-08-12T21:09:38.720 回答
1

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

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);
}
于 2010-08-12T21:20:52.143 回答
0

您可以向主、UI、线程触发事件,并且有:

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

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

于 2010-08-12T21:05:23.943 回答
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);
    }
}
于 2010-08-12T22:26:53.373 回答