在后台工作程序中实例化对象会导致UI冻结

时间:2011-09-26 10:43:11

标签: c# .net wpf multithreading backgroundworker

这就是我现在所拥有的,但当我致电Dispatcher.BeginInvoke()时,我的用户界面冻结了:

        BackgroundWorker backgroundWorker = new BackgroundWorker();
        backgroundWorker.WorkerSupportsCancellation = true;
        backgroundWorker.WorkerReportsProgress = true;


        ViewModel.GenerateReport(backgroundWorker, Dispatcher);

视图模型:

backgroundWorker.DoWork += delegate(object s, DoWorkEventArgs args)
        {
            try
            {
                ReportViewModel reportViewModel = new ReportViewModel(SessionContext, Mediator, reportDashboardViewModel.ReportRequest, false);

                dispatcher.BeginInvoke((Action)(() =>
                {
                    ReportPreviewView reportPreviewView = new ReportPreviewView(reportViewModel);
                    reportPreviewView.ReportName = reportDashboardViewModel.ReportRequest.Report.ReportName;

                    ReportView = reportPreviewView;
                }));
            }
            catch (Exception exception)
            {
                backgroundWorker.ReportProgress(0, "There Was an Error generating the report");
                backgroundWorker.CancelAsync();
                throw;
            }
        };

        backgroundWorker.RunWorkerAsync();

dispatcher.BeginInvoke中的第一行导致我的UI冻结。 ReportPreviewView reportPreviewView = new ReportPreviewView(reportViewModel);

注意ReportPreviewView为报告请求创建相关视图。可以是DevexpressC1pivot reports

我删除dispatcher.BeginInvoke后,我收到此错误:

The calling thread must be STA, because many UI components require this.

所以我的问题是,我需要做些什么来解决这个问题?

使用BackgroundWorker的全部原因是我的UI始终保持响应。

我是multithreading的新手,所以也许我的结构都错了......

2 个答案:

答案 0 :(得分:2)

Disptacher.BeginInvoke启动使用Action ansynchronoulsy封装的代码,但BackgroundWorker也会更新Do_Work处理程序,因此您不应该使用它。

主要问题是您尝试从另一个线程访问UI实例,并且Windows不允许:只有主线程才能访问UI元素实例。

如果您使用的是Windows窗体,正确的方法是使用Control.Invoke。

A deep article about the winforms threading model

答案 1 :(得分:0)

故事的道德,需要在UI线程上创建所有UI元素!

话虽如此,如果创建UI元素需要很长时间,UI将会冻结。承担所有繁重的工作并将其放入TaskBackgroundWorker

然后你会有一个响应更快的用户界面。