WPF - 尝试在任务中打开一个新窗口但是接收一个"调用线程必须是STA异常"

时间:2016-06-06 02:12:27

标签: c# wpf multithreading

这是我的第一篇文章,如果我犯错,请原谅我。

我有一个返回字符串的Task。在该任务中,我想打开一个用户输入代码的新窗口。输入代码并关闭窗口后,Task将返回代码。

我的代码如下:

 public Task<string> GetLoginCode()
        {

            return Task.Run(() =>
            {
                CodeRequestView view = new CodeRequestView();
                CodeRequestViewModel viewModel = new CodeRequestViewModel();
                view.ShowDialog();
                return viewModel.Code;
            });

        }

我遇到的问题是当我运行我的项目时我收到了一个&#34;调用线程必须是STA,因为许多UI组件都需要这个。&#34; CodeRequestView.xmal.cs文件的构造函数中的异常。

如何解决这个问题的一些帮助将不胜感激。 谢谢!

2 个答案:

答案 0 :(得分:3)

当你从非UI线程调用UI内容时,你可以使用像Dispatcher这样的UI线程。

  public Task<string> GetLoginCode()
            {

                return Task.Run(() =>
                {
                    CodeRequestViewModel viewModel = new CodeRequestViewModel();
                    Application.Current.Dispatcher.Invoke(delegate 
                    {
                        CodeRequestView view = new CodeRequestView();
                        view.ShowDialog();
                    });
                    return viewModel.Code;
                });
            }

答案 1 :(得分:1)

WPF窗口和控件需要在其apartment state的STA线程上运行。 Task.Run()使用线程池,它被定义为MTA,并且不允许它们实例化必须在STA线程上的Window子类对象。

在使用它创建新的窗口对象之前,您需要手动创建一个新线程,并将其公寓状态设置为STA。由于您没有显示完整代码,因此我不知道为什么需要返回Task<string>对象而不是string对象。如果你想让它以异步方式运行(等待),你使用Task.Run()的原始实现已经在另一个线程(来自线程池)上运行它,并立即返回给调用者。

无论如何,这是一个例子:

public string GetLoginCode()
{
    string retVal;
    Thread viewThread = new Thread(() =>
    {
        CodeRequestView view = new CodeRequestView();
        CodeRequestViewModel viewModel = new CodeRequestViewModel();
        view.ShowDialog();
        retVal = viewModel.Code;
        });
    }
    viewThread.SetApartmentState(ApartmentState.STA);
    viewThread.Start();

    return retVal;
}

我从来没有试过这个,所以我不确定返回值是否会导致同步问题。