2011-11-04 84 views
0

我有父窗体和子窗体。父表单包含一个dataGridView(帐户列表),子表单允许用户注册一个帐户。事件,GUI和线程

子窗体在单独的线程上启动。

当账户被注册时,它被添加到SQL数据库中,并且事件在父窗体订阅的子窗体上触发。父窗体然后更新dataGridView以从数据库添加新值。

问题是,当试图更新父窗体中的dataGridView时,事件被解雇我得到一个交叉线程错误。这是正常的行为吗?

+0

与ui控件的任何交互操作都必须从创建控件的线程中完成。假设您使用win窗体,则需要使用Control.BeginInvoke/Invoke方法与另一个线程中创建的控件进行交互 – Loman

回答

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... 
} 
+0

在事件处理程序中会有这样的事情吗?this.Invoke((MethodInvoker)delegate fillData(); }); –

+0

在进行“正常工作”部分之后,您将回到UI线程,因此您可以调用'FillData()'而不必担心invoke(它通常会同步调用UI线程中的某些内容) 。 – Reddog

0

是的,这是正常的,触发事件的线程是子线程表单。在此事件中运行在mainform中的代码在子窗体线程中运行。所以这很正常。 我鼓励你不要在不同的线程中启动窗体,控件。留在主线程中。但是您可以使用BackgroundWorker或其他任何工具在另一个线程中执行内部进程。

0

是的,您不允许从其他线程访问UI元素,而不是创建它们。您需要将呼叫整理到父窗体所在的线程(如果您使用winforms,则InvokeRequired是您的朋友)

0

此类行为是预期的 - WinForms应用程序模型不是线程安全设计。 要与来自非UI线程的控件进行交互,请使用Control.Invoke或Control.BeginInvoke()方法。

例子:

void RefreshData() 
{ 
    // Refresh database here 
} 

void MyOtherThreadCallback() 
{ 
    this.BeginInvoke(new Action(RefreshData())) 
} 
0

你父窗体尝试更新使用解雇事件的线程的网格视图。这会导致交叉线程错误。为了避免这种情况,您必须使用您创建控件的线程来更新控件。这通常使用代码:

if(control.InvokeRequired) 
{ 
    control.Invoke(delegateToThisMethod) 
} 

并在delegateToThisMethod您更新网格视图。

对这一问题的好深入回答this question

0

你不列出您使用的是什么版本,但检查出MSDN上的BackgroundWorker Class,它使基本线程很容易。

你会想看看这些事件:

OnDoWork    Raises the DoWork event. 
OnProgressChanged  Raises the ProgressChanged event. 
OnRunWorkerCompleted Raises the RunWorkerCompleted event. 

在DoWork的方法会发生什么是一个单独的线程(以及任何调用),但二者所创建的运行ProgressChanged和RunWorkerCompleted方法在UI线程上,因此可以更新UI元素。