事件,GUI和线程

时间:2011-11-04 00:37:23

标签: c#

我有父母表格和子表格。父表单包含dataGridView(帐户列表),子表单允许用户注册帐户。

子表单是在单独的线程上启动的。

注册帐户后,会将其添加到SQL数据库中,并在父表单订阅的子表单上触发事件。然后父表单更新dataGridView以从数据库添加新值。

问题是在事件被触发时尝试更新父表单中的dataGridView时出现交叉线程错误。在这种情况下这是正常行为吗?

6 个答案:

答案 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中更新网格视图。

this question

对这个问题进行了深入的回答

答案 4 :(得分:0)

在你的处理程序中,你必须做一些工作才能将处理程序带回UI线程......“规范”是使用InvokeRequiredBeginInvoke以下模式:

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元素。