1

I am getting this error when I am passing browser control to my background tasks which keep track of browser control values. What change do I need in code so I can pass this browser control safely to my background scraper class.

Error

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

Here is how I am passing browser control to my background singleton class.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            brwser.Navigate("https://xyz.com");
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            Task.Factory.StartNew(() =>
           {
               if (BfScrapper.Instance.CanStart)
                   BfScrapper.Instance.StartTask(brwser);
           });
        }
    }
John Saunders
  • 160,644
  • 26
  • 247
  • 397
SOF User
  • 7,590
  • 22
  • 75
  • 121
  • Please don't repeat tags in titles. – Ondrej Tucny Mar 17 '13 at 22:47
  • its not duplicate refreing example is not using Task/Task Factory Class to launch new instance of singleton class – SOF User Mar 17 '13 at 22:53
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 17 '13 at 23:09

2 Answers2

2

You will have to start a task which is running an STA thread.

To do so, you will need to use TaskScheduler.FromCurrentSynchronizationContext (assuming the thread from which you are creating the task is itself an STA thread).

You can pass this to one of the overloads of TaskFactory.StartNew that accepts a TaskScheduler argument.

For example:

Task.Factory.StartNew
(
    () =>
    {
        if (BfScrapper.Instance.CanStart)
            BfScrapper.Instance.StartTask(brwser);
    },
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext()
);

I also recommend you google FromCurrentSynchronizationContext STA, since this stuff is far from obvious, and has ramifications.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • can you please share snippet of code how to use in this case by passing contorl? – SOF User Mar 17 '13 at 23:09
  • It works great thanks I wish I could give many points instead of like other people who refereeing to old answers this is what answer I wanted to hear from expert like you. Because this class using Task Factory – SOF User Mar 17 '13 at 23:19
  • 1
    When I first started using Tasks instead of Threads I ran into this problem (it was easy to fix for threads because you can just set the STA state for a thread). It took me quite a while to find out about the FromCurrentSynchronizationContext() thing! But be fair to everyone - they are all trying to help (and I myself often post replies that turn out to be not as helpful as I'd hoped...) – Matthew Watson Mar 17 '13 at 23:21
1

I guess you are trying to change something in the passed UI element. The easiest way to do this is like this:

UIElement.Dispatcher.BeginInvoke(/*do stuff here*/);

I have a handy extension method for this:

public static DispatcherOperation DispatcherCall<T>(this T obj, Action action, DispatcherPriority priority) where T : DispatcherObject
        {
            return obj.Dispatcher.BeginInvoke(priority, action);
        }

the usage would look like this:

mLabel.DispatcherCall(() => mLabel.Text = "Test...", DispatcherPriority.Normal);

This avoids the rather large cost of always having to switch back and forth between the Synchronisation Contexts

Nefarion
  • 872
  • 2
  • 8
  • 28