事件在错误的线程?

时间:2012-10-31 14:23:21

标签: c# wpf multithreading

我对线程有疑问。

我有一个WPF应用程序,它应该显示一些查询的状态。为此,我创建了一个类,它在多个线程(backgroundworker)中运行多个查询。我还创建了一个事件,所以我可以在查询运行时做出反应。

    private void cmdStart(object sender, RoutedEventArgs e)
    {
        QuerySetup qs = new QuerySetup();
        //Filling qs with some data
        //...
        SqlProxy sql = new SqlProxy();
        sql.QueryCompleted += new SqlProxy.QueryCompletedEventHandler(sql_QueryCompleted);

        //Starts the backgroundworker
        sql.RunSQL(qs);
    }

    private void sql_QueryCompleted(QueryResult qr)
    {
        lstStatus.Items.Clear();
        lstStatus.Items.Add(qr.RuntimeTotal);
        //... and some more...
    }

现在我收到一条错误消息,告诉我,我无法访问lstStatus,因为它由不同的线程拥有。

但为什么呢?事件不应该与GUI在同一个线程中吗?我怎样才能解决我的问题?

3 个答案:

答案 0 :(得分:5)

没有。
大多数非UI组件都会在非UI线程(通常是ThreadPool线程)中引发回调

您可以调用Dispactcher.BeginInvoke在UI线程上运行代码:

Dispactcher.BeginInvoke(new Action(delegate {
    ...
}));

答案 1 :(得分:1)

不,该事件不会在UI线程上执行。

虽然很容易解决,但您必须调用与UI线程上的GUI元素交互的代码:

private void sql_QueryCompleted(QueryResult qr)
{
    Dispatcher.BeginInvoke(new Action(() => { 
        lstStatus.Items.Clear();
        lstStatus.Items.Add(qr.RuntimeTotal);
        //... and some more...
    });
}

答案 2 :(得分:1)

Dispatcher.BeginInvoke总是有助于更新来自其他线程的控件。 此外,如果您正在使用Backgroundworker类并从DoWork引发事件,则会在DoWork线程上引发事件处理程序。 如果你从Backgroundworker的WorkCompleted事件中引发事件,它将在你启动Backgroundworker的线程上引发,它可以是你的UI线程(这里不需要Dispatcher)。 Backgroundworker.ProgressChanged事件也是如此。