UI スレッドから WriteableBitmap を呼び出す必要があります。これは、回避できないユーティリティの制限にすぎません。
MSDN から:
WriteableBitmap クラスは 2 つのバッファーを使用します。バック バッファはシステム メモリに割り当てられ、現在表示されていないコンテンツを蓄積します。フロント バッファはシステム メモリに割り当てられ、現在表示されているコンテンツが含まれます。レンダリング システムは、フロント バッファをビデオ メモリにコピーして表示します。
2 つのスレッドがこれらのバッファーを使用します。ユーザー インターフェイス (UI) スレッドは UI を生成しますが、画面には表示しません。UI スレッドは、ユーザー入力、タイマー、およびその他のイベントに応答します。アプリケーションは複数の UI スレッドを持つことができます。レンダリング スレッドは、UI スレッドからの変更を作成してレンダリングします。アプリケーションごとに 1 つのレンダリング スレッドしかありません。
UI スレッドはコンテンツをバック バッファーに書き込みます。レンダリング スレッドは、フロント バッファーからコンテンツを読み取り、それをビデオ メモリにコピーします。バック バッファーへの変更は、変更された四角形領域で追跡されます。
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx
BackgroundWorker の代替:
UI スレッドでこれを行う必要があるという事実を回避することはできません。ただし、キューの最後にプッシュして、ユーザーが目立たないようにすることができます。
次のようなことを試してください:
public static void RunDelayedOnUiThread(Action action)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(1)
};
timer.Tick += (sender, args) =>
{
timer.Stop();
action();
};
timer.Start();
});
}
画像処理 (この場合は渡されたアクション) が、UI スレッドで処理されるのを待っているキューの最後に配置されるようにするには、これで十分です。画像処理は、動作中の UI スレッドを引き続きブロックしますが、少なくとも他のすべてを最初に実行する必要があります。
使い方:
BeginInvoke を呼び出すと、アクションはディスパッチャーのキューの最後に配置され、UI スレッドが現在実行中 (コードの実行) から解放されたときに実行されます。しかし、BeginInvoke を再度 (そして何度も) 呼び出すと、画像処理によってディスパッチャのキュー内の他のものがブロックされる可能性があるため、これを再び後ろに置きたいと考えています。これが DispatcherTimer の出番です。 MSDN から:
タイマーは、時間間隔が発生したときに正確に実行されることは保証されていませんが、時間間隔が発生する前に実行されないことは保証されています。これは、DispatcherTimer 操作が他の操作と同様に Dispatcher キューに置かれるためです。DispatcherTimer 操作が実行されるタイミングは、キュー内の他のジョブとその優先度に依存します。
したがって、指定した 1 ミリ秒の間隔だけで、これをキューの最後に押し戻すのに十分なはずです。
Windows Phone 7 では、一部のタッチ イベントがブロックされる可能性がありますが、少なくともページのレンダリングがブロックされることはありません。
Windows Phone 8 では、Panorama、Pivot、および LongListSelector はすべて非 UI スレッドでの入力に応答するため、少し安全になります。