3

WritableBitmap があり、その寸法を取得したいと考えています。オブジェクトは別のスレッドによって所有されているため、Dispatcher を経由する必要があります。私はこれを試しました:

int targetPixelWidth = 0;
int targetPixelHeight = 0;

writeableBitmap.Dispatcher.Invoke(new Action(() =>
{
    targetPixelWidth = writeableBitmap.PixelWidth;
    targetPixelHeight = writeableBitmap.PixelHeight;
}));

// Do something with targetPixelWidth and targetPixelHeight

ただし、これは時々失敗します。実際の値が異なっていても、値はしばしば 0 のままです。

スレッドの問題かもしれないと考えて、次のようにコードを変更しました。

var bitmapInfo = (Tuple<int, int>)writeableBitmap.Dispatcher.Invoke(new Func<Tuple<int, int>>(
   () => Tuple.Create(writeableBitmap.PixelWidth, writeableBitmap.PixelHeight)
));

Debug.Assert(bitmapInfo != null, "Obviously, this should pass.");

targetPixelWidth = bitmapInfo.Item1;
targetPixelHeight = bitmapInfo.Item2;

// Do something with targetPixelWidth and targetPixelHeight

しかし、今bitmapInfoは時々nullです。(ドキュメントによると)デリゲートに戻り値がない場合にのみ null を返す必要があるため、これは奇妙Invokeです。この場合は明らかにそうです。Debug.Assertの戻り値も編集しましたがTuple.Create、null になることはありませんでした。

ここで何が欠けていますか?この競合状態の原因は何ですか?どうすればよいですか?

4

2 に答える 2

0

理由はわかりませんが、これは機能します。

ManualResetEventSlim mre = new ManualResetEventSlim(false);

int targetPixelWidth = 0;
int targetPixelHeight = 0;

writeableBitmap.Dispatcher.Invoke(new Action(() =>
{
    try {
        targetPixelWidth = writeableBitmap.PixelWidth;
        targetPixelHeight = writeableBitmap.PixelHeight;
    }
    finally {
        mre.Set();
    }
}));

mre.Wait();
// Do something with targetPixelWidth and targetPixelHeight

誰か (この質問への回答を投稿したが後で削除した) は、Invokeを呼び出すスレッドではなく、GUI スレッドで同期することを提案しましたInvoke。それが本当なら、なぜこれが機能するのか説明できます。しかし、ドキュメンテーション、本 [ 1、2 ] 、およびこの問題を再現しようとする小さなおもちゃのプログラムはすべて、そうではないことを示唆しています。Invoke呼び出しスレッドで同期する必要があります。

本当の説明を思いつくことができませんでした。誰かがそれを持っているなら、私はすべての耳です:)。

編集私の元のややとりとめのない答えをより首尾一貫したものに置き換えました。

于 2013-05-02T14:06:58.530 に答える