41

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

无法创建程序集中定义的“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
    [..]
}
4

5 回答 5

59

您可以像这样启动 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;
}

希望这可以帮助!

于 2010-03-04T09:26:43.037 回答
12

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

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

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

于 2010-03-04T09:34:36.703 回答
3

在 UI 线程上调用它应该足够好了。因此,使用BackgroundWorkerRunWorkerAsyncCompleted,您就可以创建inkPresenter。

于 2010-03-04T09:19:56.427 回答
1

这有点 hack,但我会使用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)
{
}
于 2013-08-16T18:00:24.030 回答
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();
于 2019-06-18T12:26:48.343 回答