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

发布于 2024-08-23 13:59:56 字数 771 浏览 9 评论 0原文

在我的 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
    [..]
}

In my WPF application I do some async communication (with server). In the callback function I end up creating InkPresenter objects from the result from server. This requires the running thread to be STA, which apparently it currently isn't. Therefore I get the following exception:

Cannot create instance of 'InkPresenter' defined in assembly [..] The calling thread must be STA, because many UI components require this.

Currently my async function call is like this:

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

How can I make the callback - which will do the InkPresenter creation - be STA? Or invoke the XamlReader parsing in a new STA thread.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

往事随风而去 2024-08-30 13:59:56

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

希望这有帮助!

You can start STA Threads like so:

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

The only problem is that your result object must be passed along somehow.. You can use a private field for that, or dive into passing along parameters into threads. Here I set the foo data in a private field and start up the STA Thread to mutate the 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;
}

Hope this helps!

菊凝晚露 2024-08-30 13:59:56

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

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

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

You can use the Dispatcher class to execute the method call on the UI-Thread. The Dispatcher provides the static property CurrentDispatcher to get the dispatcher of a thread.

If your object of the class, that creates the InkPresenter, is created on the UI-Thread, then the CurrentDispatcher method returns the Dispatcher of the UI-Thread.

On the Dispatcher you can call the BeginInvoke-method to call the specified delegate asynchronously on the thread.

却一份温柔 2024-08-30 13:59:56

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

It should be good enough to call it on the UI thread. Therefore, use a BackgroundWorker and on the RunWorkerAsyncCompleted, you can then do the creation of the inkPresenter.

深海夜未眠 2024-08-30 13:59:56

我刚刚使用以下命令从 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();

I have just used the following to get clipboard content from the STA thread. Thought I would post to maybe help someone in the future...

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

// do stuff with clipContent

t.Abort();
·深蓝 2024-08-30 13:59:56

这有点黑客,但我会使用 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)
{
}

It's a bit of a hack, but I would use XTATestRunner So your code will look like:

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

as a bonus it's possible to catch exceptions thrown in STA (or MTA) thread like this:

try
{
    new XTATestRunner().RunSTA(() => {
        throw new InvalidOperationException();
    });
}
catch (InvalidOperationException ex)
{
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文