C# 如何在STA线程中运行某些内容?

C# 如何在STA线程中运行某些内容?,c#,.net,wpf,sta,C#,.net,Wpf,Sta,在我的WPF应用程序中,我(与服务器)进行一些异步通信。在回调函数中,我最终从服务器的结果创建InkPresenter对象。这要求运行的线程是STA,而目前显然不是。因此,我得到以下例外情况: 无法创建程序集[…]中定义的“InkPresenter”实例调用线程必须是STA,因为许多UI组件都需要此线程 当前我的异步函数调用如下所示: public void SearchForFooAsync(string searchString) { var caller = new Func<

在我的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);
}
public void searchforfoosync(string searchString)
{
var caller=新函数(_patientProxy.SearchForFoo);
BeginInvoke(searchString,新的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
    [..]
}
public void SearchForFooCallbackMethod(IAsyncResult ar)
{
var foo=GetFooFromAsyncResult(ar);

var inkPresenter=XamlReader.Parse(foo.Xaml)作为inkPresenter;//在UI线程上调用它应该足够了。因此,使用
BackgroundWorker
,然后在
RunWorkerAsyncCompleted
上,您可以创建inkPresenter。

您可以像这样启动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;
}
希望这有帮助!

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

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


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

这有点像黑客,但我会使用它,这样您的代码将如下所示:

    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线程获取剪贴板内容。我想我可能会在将来帮助某人

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

// do stuff with clipContent

t.Abort();

你说得对。问题是回调不是在UI线程上运行的。UI线程是用STA运行的,所以在UI线程上运行它应该可以帮我解决这个问题。谢谢:)让我知道它是否可以解决问题。我们使用此技术在服务器上生成Xaml控件的PNG图像!似乎可以解决问题,但刚刚遇到另一个问题。叹气。。当我在这里完成所有工作后,将立即标记为已接受。。Thx!@Arcturus:什么是
MethodWhichRequiresSTA
仅仅是一个方法?如果我将一个方法放在那里,我的代码将不会编译,因为它需要参数。请提供一个method MethodWhichRequiresSTA的示例?很抱歉发布得太晚-但是GetFoodFromAsyncResult是什么?Dispatcher.Invoke或BeginInvoke是一种方法。比公认的解决方案简单得多。使用
Dispatcher.CurrentDispatcher
时要小心,除非您确定您运行的UI线程将处理
DispatcherOperation
s。
CurrentDispatcher
将为当前线程创建一个Dispatcher,如果它不可用oesn还没有,即使当前线程是MTA。我通常认为在我要更新的控件上使用
Dispatcher
属性更好。无论
[STAThread]发生了什么
在一个方法之前?不总是合适的,但很简单。也许它直到2011年才出现?我记得从2011年起我就没有使用过它…在这个方法对我有效之前添加[StatThread]。谢谢你,ebyrob!:-)
string clipContent = null;
Thread t = new Thread(
    () =>
    {
        clipContent = Clipboard.GetText();
    });
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();

// do stuff with clipContent

t.Abort();