views:

147

answers:

7

I have method which create background thread to make some action. In this background thread I create object. But this object while creating in runtime give me an exception :

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

I know that I must use Dispatcher to make reflect something to UI. But in this case I just create an object and dont iteract with UI. This is my code:

    public void SomeMethod()
      {
         BackgroundWorker worker = new BackgroundWorker();
         worker.DoWork += new DoWorkEventHandler(Background_Method);
         worker.RunWorkerAsync();
      }

   void Background_Method(object sender, DoWorkEventArgs e)
      {
         TreeView tv = new TreeView();
      }

How can I create objects in background thread?

I use WPF application

+3  A: 

TreeView is a UI control. You can only create and manipulate UI controls on a UI thread, so what you're trying to do is not possible.

What you want to do is do all of the time-consuming work on the background thread, and then "call back" to the UI thread to manipulate the UI. This is actually quite easy:

void Background_Method(object sender, DoWorkEventArgs e)
{
    // ... time consuming stuff...

    // call back to the window to do the UI-manipulation
    this.BeginInvoke(new MethodInvoker(delegate {
        TreeView tv = new TreeView();
        // etc, manipulate
    }));
}

I may have got the syntax wrong for BeginInvoke (it's off the top of my head), but there you go anyway...

Dean Harding
I get some data from web service and runtime spend a lot of time for it. That why I want to get data in background and generate my treeView when data will be ready.
Polaris
I've updated my answer with some more comments about how you can do stuff in the UI thread from a worker thread.
Dean Harding
A: 

To make your code simply work, you must join a STA COM apartment by calling Thread.SetApartmentState(ApartmentState.STA). Since BackgroundWorker is probably using some shared thread pool, joining a particular apartment may affect other users of this thread pool or may even fail if it has already been set to e.g. MTA before. Even if it all worked out, your newly created TreeView would be locked to this worker thread. You wouldn't be able to use it in your main UI thread.

If you explained in a bit more detail about your true intentions, you would surely get better help.

wpfwannabe
A: 

Try following Code:

public void SomeMethod() 
{ 

System.ComponentModel.BackgroundWorker myWorker = new  System.ComponentModel.BackgroundWorker();

myWorker.DoWork += myWorker_DoWork;

myWorker.RunWorkerAsync();

}

private void myWorker_DoWork(object sender,
   System.ComponentModel.DoWorkEventArgs e)
{
   // Do time-consuming work here
}
Archie
+2  A: 

HTH:

    void Background_Method(object sender, DoWorkEventArgs e)
    {
        // Time Consuming operations without using UI elements
        // Result of timeconsuming operations
        var result = new object();
        App.Current.Dispatcher.Invoke(new Action<object>((res) =>
            {
                // Working with UI
                TreeView tv = new TreeView();
            }), result);
    }
Andrew
A: 
void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    TreeView tv = new TreeView(); 
    // Generate your TreeView here
    UIDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => 
    { 
        someContainer.Children.Add(tv);
    }; 
}
Veer
A: 

I solved my problem. I just used e.Result property of RunWorkerCompleted method. I get data in background thread and then use this data when thread completed. Thank every body for useful methods. Special thank to Veer to give a recommendation about e.Result property.

Polaris
If you want to update your UI at some intervals, you can use the ReportProgress Method's UserState parameter to send your data and use them in your ProgressChanged method by casting e.UserState to the required type.
Veer
A: 

See the answer on this question: http://stackoverflow.com/questions/2378016/how-to-run-something-in-the-sta-thread/2378077#2378077

When you define your thread, set the ApartmentState to STA:

thread.SetApartmentState(ApartmentState.STA);

This should do the trick!

Arcturus