私のWPFアプリケーションでは、(サーバーとの)非同期通信を行います。コールバック関数では、サーバーからの結果からInkPresenterオブジェクトを作成することになります。これには、実行中のスレッドがSTAである必要がありますが、現在はそうではないようです。したがって、次の例外が発生します。
多くのUIコンポーネントがこれを必要とするため、アセンブリで定義された 'InkPresenter'のインスタンスを作成できません。
現在、私の非同期関数呼び出しは次のようになっています。
public void SearchForFooAsync(string searchString)
{
var caller = new Func<string, Foo>(_patientProxy.SearchForFoo);
caller.BeginInvoke(searchString, new AsyncCallback(SearchForFooCallbackMethod), null);
}
InkPresenterの作成を行うコールバックを作成するにはどうすればよいですか?または、新しいSTAスレッドでXamlReader解析を呼び出します。
public void SearchForFooCallbackMethod(IAsyncResult ar)
{
var foo = GetFooFromAsyncResult(ar);
var inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter; // <!-- Requires STA
[..]
}
次のように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スレッドを起動して、インクプレゼンターを変更します!
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;
}
お役に立てれば!
Dipatcher クラスを使用して、UI-Threadでメソッド呼び出しを実行できます。 Dispatcherは、スレッドのディスパッチャを取得するための静的プロパティCurrentDispatcherを提供します。
InkPresenterを作成するクラスのオブジェクトがUIスレッドで作成された場合、CurrentDispatcherメソッドはUIスレッドのDispatcherを返します。
Dispatcherでは、BeginInvoke-methodを呼び出して、指定されたデリゲートをスレッドで非同期に呼び出すことができます。
UIスレッドで呼び出すのに十分なはずです。したがって、BackgroundWorker
を使用し、RunWorkerAsyncCompleted
で、inkPresenterの作成を行うことができます。
ちょっとしたハックですが、私は 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){
}
以下を使用して、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();