I've been trying to get a WebBrowser to draw to a texture in XNA 4.0, and I've found several guides on how to do it. The problem is when I try to implement it, whether I change the Url
property or call Navigate()
it just won't load the page. I have a feeling I'm being a bit ignorant about the threading required, since my project is not started as an STA thread, so I create a separate thread to start the web browser and render to a bitmap.
Here's how I start it:
public void LoadTexture(GraphicsDevice gfx, ContentManager content, string filename, float duration = -1f)
{
this.gfx = gfx;
this.filename = filename;
this.duration = duration;
_reset开发者_JS百科Event = new AutoResetEvent(false);
Thread thread = new Thread(GetWebScreenshot);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
_resetEvent.WaitOne();
}
And here's GetWebScreenshot
:
public void GetWebScreenshot()
{
this.web = new WebBrowser();
this.web.Size = new Size(gfx.Viewport.Width, gfx.Viewport.Height);
this.web.Url = new Uri(this.filename);
while (this.web.ReadyState != WebBrowserReadyState.Complete)
{
if (this.web.ReadyState != WebBrowserReadyState.Uninitialized)
{
Console.WriteLine(this.web.ReadyState.ToString());
}
}
bitmap = new Bitmap(this.gfx.Viewport.Width, this.gfx.Viewport.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
this.web.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
this.texture = BitmapToTexture2D(this.gfx, bitmap);
_resetEvent.Set();
}
The ReadyState
property never changes from Uninitialized
, I've also tried using the DocumentReady
event, and that never gets fired. I've also tried Join()
instead of AutoResetEvent
, but nothing seems to work.
I was right, it was ignorance on my part. The critical thing about ActiveX controls and Single Threaded Apartments is that the message queue needs to be pumped. So now I've restructured my code to the following:
public void LoadTexture(GraphicsDevice gfx, ContentManager content, string filename, float duration = -1f)
{
this.gfx = gfx;
this.filename = filename;
this.duration = duration;
Thread thread = new Thread(GetWebScreenshot);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
public void GetWebScreenshot()
{
this.web = new WebBrowser();
this.web.Size = new Size(gfx.Viewport.Width, gfx.Viewport.Height);
this.web.Url = new Uri(this.filename);
this.web.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(web_DocumentCompleted);
Application.Run(); // Starts pumping the message queue (and keeps the thread running)
}
void web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Bitmap bitmap = new Bitmap(this.gfx.Viewport.Width, this.gfx.Viewport.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
this.web.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
this.texture = HTMLTextureFactoryMachine.BitmapToTexture2D(this.gfx, bitmap);
Application.ExitThread(); // Exits the thread
}
This works no problem.
精彩评论