Willem
Willem

Reputation: 9486

Instantiating an object in a background worker causes the UI to freeze up

This is what i have at the moment, but when i call Dispatcher.BeginInvoke(), my UI freezes up:

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


        ViewModel.GenerateReport(backgroundWorker, Dispatcher);

ViewModel:

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();

The first line in dispatcher.BeginInvoke causes my UI to freeze up. ReportPreviewView reportPreviewView = new ReportPreviewView(reportViewModel);

Note: ReportPreviewView creates the relevant view for the report request. May it be Devexpress, C1 or pivot reports.

As soon as i remove the dispatcher.BeginInvoke, i get this error:

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

So my question is, what do i need to do to get around this?

The whole reason for using a BackgroundWorker was so that my UI stays responsive at all times.

I am new to multithreading,so maybe i got the structure all wrong...

Upvotes: 1

Views: 1016

Answers (2)

Willem
Willem

Reputation: 9486

Moral of the story, all UI elements needs to be created on the UI thread!

That being said, if the creation of the UI element takes a long time, the UI will freeze up. Take all the heavy lifting and put it in a Task or BackgroundWorker.

Then you will have a more responsive UI.

Upvotes: 0

Ricardo Amores
Ricardo Amores

Reputation: 4687

Disptacher.BeginInvoke launches the code you encapsulated withing an Action ansynchronoulsy, but the Do_Work handler is also updated async by the BackgroundWorker, so you should't use it.

The main problem is that you are trying to access an UI instance from another thread, and windows disallow that: only the main thread can access an UI element instance.

The correct way to do it is using Control.Invoke if you are using windows Forms.

A deep article about the winforms threading model

Upvotes: 2

Related Questions