C# 如何在 STA 线程中运行某些东西?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2378016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to run something in the STA thread?
提问by stiank81
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:
在我的 WPF 应用程序中,我进行了一些异步通信(与服务器)。在回调函数中,我最终从服务器的结果中创建了 InkPresenter 对象。这要求正在运行的线程是 STA,而目前显然不是。因此我得到以下异常:
Cannot create instance of 'InkPresenter' defined in assembly [..] The calling thread must be STA, because many UI components require this.
无法创建程序集 [..] 中定义的“InkPresenter”的实例调用线程必须是 STA,因为许多 UI 组件需要这样做。
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.
我怎样才能使回调 - 这将创建 InkPresenter - 成为 STA?或者在新的 STA 线程中调用 XamlReader 解析。
public void SearchForFooCallbackMethod(IAsyncResult ar)
{
var foo = GetFooFromAsyncResult(ar);
var inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter; // <!-- Requires STA
[..]
}
采纳答案by Arcturus
You can start STA Threads like so:
您可以像这样启动 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
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!
唯一的问题是您的结果对象必须以某种方式传递。您可以为此使用私有字段,或者深入研究将参数传递给线程。在这里,我将 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;
}
Hope this helps!
希望这可以帮助!
回答by Kyle Rozendo
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.
在 UI 线程上调用它应该足够了。因此,在 上使用BackgroundWorker
和RunWorkerAsyncCompleted
,您就可以创建inkPresenter。
回答by Jehof
You can use the Dispatcherclass to execute the method call on the UI-Thread. The Dispatcher provides the static property CurrentDispatcher to get the dispatcher of a thread.
您可以使用Dispatcher类在 UI-Thread 上执行方法调用。Dispatcher 提供静态属性 CurrentDispatcher 来获取线程的调度程序。
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.
如果创建 InkPresenter 的类对象是在 UI-Thread 上创建的,则 CurrentDispatcher 方法返回 UI-Thread 的 Dispatcher。
On the Dispatcher you can call the BeginInvoke-method to call the specified delegate asynchronously on the thread.
在 Dispatcher 上,您可以调用 BeginInvoke 方法在线程上异步调用指定的委托。
回答by alex
It's a bit of a hack, but I would use XTATestRunnerSo your code will look like:
这有点黑客,但我会使用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;
});
}
as a bonus it's possible to catch exceptions thrown in STA (or MTA) thread like this:
作为奖励,可以像这样捕获 STA(或 MTA)线程中抛出的异常:
try
{
new XTATestRunner().RunSTA(() => {
throw new InvalidOperationException();
});
}
catch (InvalidOperationException ex)
{
}
回答by mouldycurryness
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...
我刚刚使用以下内容从 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();