在我的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
[..]
}
答案 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();