2014-02-21 24 views
1

我正在使用MonoGame將Windows Phone 7遊戲移植到Windows Phone 8。我的遊戲使用Texture2D.FromStream加載來自Internet的圖片,一旦它沒有在MonoGame中實現,我試圖提出解決方法:在UI線程中使用BitmapImage加載圖片。WP8:Dispatcher.BeginInvoke不會在UI線程上執行動作

下面是代碼:

  Texture2D result = null; 
      EventWaitHandle Wait = new AutoResetEvent(false); 
      Deployment.Current.Dispatcher.BeginInvoke(() => 
      { 
       BitmapImage image = new BitmapImage(); 
       image.SetSource(stream); 
       WriteableBitmap writeImage = new WriteableBitmap(image); 

       var index = 0; 
       var pixels = new byte[writeImage.PixelWidth * writeImage.PixelHeight * 4]; 
       for (var h = 0; h < writeImage.PixelHeight; h++) 
        for (var w = 0; w < writeImage.PixelWidth; w++) 
        { 
         var pixel = writeImage.Pixels[index++]; 
         var wIndex = w * 4 + h * writeImage.PixelWidth * 4; 

         pixels[wIndex++] = (byte)(pixel >> 16 & 0xFF); 
         pixels[wIndex++] = (byte)(pixel >> 8 & 0xFF); 
         pixels[wIndex++] = (byte)(pixel >> 0 & 0xFF); 
         pixels[wIndex++] = (byte)(pixel >> 24 & 0xFF); 
        } 

       result = new Texture2D(graphicsDevice, writeImage.PixelWidth, writeImage.PixelHeight); 
       result.SetData(pixels); 
       Wait.Set(); 
      }); 

理論上一切正常。但不知何故,行動代碼永遠不會被調用。 我在非ui工作線程中調用BeginInvoke,Deployment.Current.Dispatcher不爲null並提供ui線程調度程序。 遊戲是由VS2012的MonoGame模板製作的WP8項目。 我試圖獲取並保存到主線程(遊戲構造函數)中的靜態變量dispatcher和SynchronizationContext,以確保它們完全屬於UI線程,但這沒有幫助。

我也試過這樣的代碼:

SynchronizationContext uiThread = Hub.SyncContext;//set in main thread (Game constructor) 
var waitHandle = new object(); 
lock (waitHandle) 
{ 
    uiThread.Post(_ => 
    { 
     lock (waitHandle) 
     { 

      BitmapImage image = new BitmapImage(); 
      image.SetSource(stream); 
      WriteableBitmap writeImage = new WriteableBitmap(image); 

      var index = 0; 
      var pixels = new byte[writeImage.PixelWidth * writeImage.PixelHeight * 4]; 
      for (var h = 0; h < writeImage.PixelHeight; h++) 
       for (var w = 0; w < writeImage.PixelWidth; w++) 
       { 
        var pixel = writeImage.Pixels[index++]; 
        var wIndex = w * 4 + h * writeImage.PixelWidth * 4; 

        pixels[wIndex++] = (byte)(pixel >> 16 & 0xFF); 
        pixels[wIndex++] = (byte)(pixel >> 8 & 0xFF); 
        pixels[wIndex++] = (byte)(pixel >> 0 & 0xFF); 
        pixels[wIndex++] = (byte)(pixel >> 24 & 0xFF); 
       } 

      result = new Texture2D(graphicsDevice, writeImage.PixelWidth, writeImage.PixelHeight); 
      result.SetData(pixels); 

      Monitor.Pulse(waitHandle); 
     } 

    }, null); 

    Monitor.Wait(waitHandle); 
} 

但同樣沒有運氣:在等待和斷點在動作代碼執行停止時從來沒有發射。

更新:我剛剛添加了簡單的代碼,只有一個日誌來示例MonoGame項目。 如果我等待AutoResetEvent,我永遠不會看到任何日誌。當我刪除are.WaitOne()行動開始工作。我用are.WaitOne(1000)取代了它,並開始按預期工作(爲什麼?)。 但圖像加載仍然沒有運氣。它看起來像是阻止主線程運行,而我在are.WaitOne()等待。 https://github.com/Taggersoft/ImageTools 這個叉子是WP8準確,如果你刪除喜歡的語句所有Contract.Requires它工作得很好:

+1

如果在UI線程中(即在加載或啓動等時)獲得Deployment.Current.Dispatcher值並將其存儲,那麼這是否有所作爲? –

+0

@Tertium,爲什麼不在這裏簡單地使用'uiThread.Send',而不是使用'Post'和'Monitor.Pulse'? – Noseratio

+0

@PeterRitchie不,這沒有幫助 – Tertium

回答

3

我使用這個庫解決的問題。 這裏是我的Texture2d.FromStream更換:

 public static Texture2D TextureFromStream(GraphicsDevice graphicsDevice, Stream stream, String dbg_nm) 
    {   
     #if WP8 
     byte [] b = new byte[4]; 
     stream.Read(b, 0, 4); 
     stream.Seek(0, SeekOrigin.Begin); 
     int stream_type = getStreamType(b, 0); 
     Texture2D result = null; 

     if (stream_type == 1 || stream_type == 0) 
     { 
      var image = new ExtendedImage(); 
      if (stream_type == 0) 
       new JpegDecoderNano().Decode(image, stream); 
      else 
      { 
       try 
       { 
        new PngDecoder().Decode(image, stream); 
       } 
       catch (System.Exception ex) 
       { 
        Debug.WriteLine("Error reading " + dbg_nm + ":" + ex.Message); 
       }     
      } 

      var Colors = new Color[image.Pixels.Length/4]; 
      for (var i = 0; i < image.Pixels.Length/4; i++) 
      { 
       Color unpackedColor = new Color(); 
       unpackedColor.R = (byte)(image.Pixels[i * 4 + 0]); 
       unpackedColor.G = (byte)(image.Pixels[i * 4 + 1]); 
       unpackedColor.B = (byte)(image.Pixels[i * 4 + 2]); 
       unpackedColor.A = (byte)(image.Pixels[i * 4 + 3]); 
       Colors[i] = unpackedColor; 
      } 
      Texture2D texture2D = new Texture2D(graphicsDevice, image.PixelWidth, image.PixelHeight); 
      texture2D.SetData(Colors); 
      result = texture2D; 
     } 

     return result; 

     #else 
     return Texture2D.FromStream(graphicsDevice, stream); 
     #endif 
    } 

而且在遊戲中構造函數:

#if WP8 
    Decoders.AddDecoder<PngDecoder>(); 
    Decoders.AddDecoder<JpegDecoder>(); 
    #endif 

這是actualy解決方法。但在我的情況下,這種方式比uithread的MS BitmapImage更好。

相關問題