1

当我将浏览器控件传递给跟踪浏览器控件值的后台任务时,出现此错误。我需要对代码进行哪些更改,以便我可以安全地将这个浏览器控件传递给我的后台爬虫类。

错误

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

这是我将浏览器控制传递给我的后台单例类的方式。

    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);
           });
        }
    }
4

2 回答 2

2

您必须启动一个正在运行 STA 线程的任务。

为此,您需要使用TaskScheduler.FromCurrentSynchronizationContext(假设您从中创建任务的线程本身就是一个 STA 线程)。

您可以将其传递给接受 TaskScheduler 参数的TaskFactory.StartNew的重载之一。

例如:

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

我还建议您使用谷歌FromCurrentSynchronizationContext STA,因为这些东西远非显而易见,并且会产生影响。

于 2013-03-17T23:08:17.353 回答
1

我猜您正在尝试更改传递的 UI 元素中的某些内容。最简单的方法是这样的:

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

我有一个方便的扩展方法:

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

用法如下所示:

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

这避免了总是不得不在同步上下文之间来回切换的相当大的成本

于 2013-03-17T23:19:26.547 回答