2014-02-21 21 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更好。

相关问题