我有一个需要将项目添加到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);
如果你有专门针对这种情况的解决方案,那很好。
如果没有,我怎样才能让工作线程告诉我的主线程执行一个特定的方法(工作线程提供了几个参数)?这可能是一个更好的选择,因为我的工作线程实际上正在做一堆东西(比如写入数据库),而且我不确定一切是否是线程安全的。我是一名学生,也是多线程学的新手,但这真的不是我的强项。
答案 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);
}
}