如何在STA线程中运行某些东西?

时间:2010-03-04 09:15:25

标签: c# .net wpf sta

在我的WPF应用程序中,我做了一些异步通信(与服务器)。在回调函数中,我最终从服务器的结果创建InkPresenter对象。这要求运行的线程是STA,显然它当前不是。因此我得到以下例外:

  

无法在assembly [..]中定义'InkPresenter'的实例。调用线程必须是STA,因为许多UI组件都需要这个。

目前我的异步函数调用是这样的:

public void SearchForFooAsync(string searchString)
{
    var caller = new Func<string, Foo>(_patientProxy.SearchForFoo);
    caller.BeginInvoke(searchString, new AsyncCallback(SearchForFooCallbackMethod), null);
}

如何进行回调 - 这将创建InkPresenter - 是STA吗?或者在新的STA线程中调用XamlReader解析。

public void SearchForFooCallbackMethod(IAsyncResult ar)
{
    var foo = GetFooFromAsyncResult(ar); 
    var inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter; // <!-- Requires STA
    [..]
}

5 个答案:

答案 0 :(得分:57)

您可以像这样启动STA线程:

    Thread thread = new Thread(MethodWhichRequiresSTA);
    thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
    thread.Start(); 
    thread.Join(); //Wait for the thread to end

唯一的问题是你的结果对象必须以某种方式传递..你可以使用私有字段,或者深入将参数传递给线程。在这里,我将foo数据设置在私有字段中,并启动STA线程以改变inkpresenter!

private var foo;
public void SearchForFooCallbackMethod(IAsyncResult ar)
{
    foo = GetFooFromAsyncResult(ar); 
    Thread thread = new Thread(ProcessInkPresenter);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join(); 
}

private void ProcessInkPresenter()
{
    var inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter;
}

希望这有帮助!

答案 1 :(得分:11)

您可以使用Dipatcher类在UI-Thread上执行方法调用。 Dispatcher提供静态属性CurrentDispatcher来获取线程的调度程序。

如果创建InkPresenter的类的对象是在UI-Thread上创建的,那么CurrentDispatcher方法将返回UI-Thread的Dispatcher。

在Dispatcher上,您可以调用BeginInvoke方法在线程上异步调用指定的委托。

答案 2 :(得分:3)

在UI线程上调用它应该足够了。因此,使用BackgroundWorker然后在RunWorkerAsyncCompleted上,您可以创建inkPresenter。

答案 3 :(得分:1)

这有点像黑客,但我会使用XTATestRunner所以你的代码看起来像:

    public void SearchForFooAsync(string searchString)
    {
        var caller = new Func<string, Foo>(_patientProxy.SearchForFoo);
        caller.BeginInvoke(searchString, new AsyncCallback(SearchForFooCallbackMethod), null);
    }

    public void SearchForFooCallbackMethod(IAsyncResult ar)
    {

            var foo = GetFooFromAsyncResult(ar); 
InkPresenter inkPresenter;
            new XTATestRunner().RunSTA(() => {
                        inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter;
                    });
    }

作为奖励,可以捕获STA(或MTA)线程中抛出的异常,如下所示:

try{
new XTATestRunner().RunSTA(() => {
                        throw new InvalidOperationException();
                    });
}
catch(InvalidOperationException ex){
}

答案 4 :(得分:1)

我刚刚使用以下方法从STA线程获取剪贴板内容。以为我将来会发帖帮助某人...

string clipContent = null;
Thread t = new Thread(
    () =>
    {
        clipContent = Clipboard.GetText();
    });
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();

// do stuff with clipContent

t.Abort();