我有父母表格和子表格。父表单包含dataGridView(帐户列表),子表单允许用户注册帐户。
子表单是在单独的线程上启动的。
注册帐户后,会将其添加到SQL数据库中,并在父表单订阅的子表单上触发事件。然后父表单更新dataGridView以从数据库添加新值。
问题是在事件被触发时尝试更新父表单中的dataGridView时出现交叉线程错误。在这种情况下这是正常行为吗?
答案 0 :(得分:0)
是的,这是正常的,触发事件的线程是子线程形式。此事件在mainform中运行的代码在子表单线程中运行。这很正常。 我鼓励你永远不要在不同的线程中启动表单,控件。保持主线。但您可以使用BackgroundWorker或其他任何东西在另一个线程中执行内部过程。
答案 1 :(得分:0)
是的,不允许您从其他线程访问UI元素,而不是创建它们。您需要将调用封送到父表单所在的主题(如果您使用的是winforms,那么InvokeRequired是您的朋友)
答案 2 :(得分:0)
这种行为是预期的 - WinForms应用程序模型在设计上不是线程安全的。 要与非UI线程中的控件进行交互,请使用Control.Invoke或Control.BeginInvoke()方法。
示例:
void RefreshData()
{
// Refresh database here
}
void MyOtherThreadCallback()
{
this.BeginInvoke(new Action(RefreshData()))
}
答案 3 :(得分:0)
您的父表单尝试使用已触发事件的线程更新网格视图。这会导致交叉线程错误。为避免这种情况,您必须使用创建控件的线程更新控件。这通常使用代码完成:
if(control.InvokeRequired)
{
control.Invoke(delegateToThisMethod)
}
并在delegateToThisMethod
中更新网格视图。
答案 4 :(得分:0)
在你的处理程序中,你必须做一些工作才能将处理程序带回UI线程......“规范”是使用InvokeRequired
和BeginInvoke
以下模式:
private void OnChildFormSaysNewItemsHandler(object sender, EventArgs e)
{
// Bring on the UI thread
if (this.InvokeRequired)
{
Action<object, EventArgs> handler = OnChildFormSaysNewItemsHandler;
this.BeginInvoke(handler, sender, e);
return;
}
// Do the normal work...
}
答案 5 :(得分:0)
您没有列出您正在使用的版本,但请查看MSDN上的BackgroundWorker Class,它使基本线程非常简单。
你想看看这些事件:
OnDoWork Raises the DoWork event.
OnProgressChanged Raises the ProgressChanged event.
OnRunWorkerCompleted Raises the RunWorkerCompleted event.
DoWork方法中发生的事情是在一个单独的线程(以及它调用的任何东西)上,但是您创建的ProgressChanged和RunWorkerCompleted方法都在UI线程上运行,因此可以更新UI元素。