I am trying to display some html content in a bitmap in a windows service.
I am using System.Windows.Controls.WebBrowser to do the rendering. The main rendering setting works as a separate process with the WPF window that hosts the control, but as a service, at least I do not fire LoadCompleted events.
I know that I at least need a dispatcher or other message flow for this WPF control. Maybe I'm doing it right, and additional tricks / incompatibilities are needed for the WebBrowser control. Here is what I have:
I believe that only one dispatcher should work and that it can work throughout its entire life cycle. I believe that Dispatcher.Run () is the actual loop and therefore needs its own thread, which it can block. And this thread should be [STAThread] in this scenario. Therefore, in the corresponding static constructor, I have the following:
var thread = new Thread(() => { dispatcher = Dispatcher.CurrentDispatcher; Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start();
where dispatcher is a static field. Again, I think there can only be one, but I'm not sure that I should use Dispatcher.CurrentDispatcher() from anywhere and get the correct link.
The rendering operation is as follows. I create, move, and delete the WebBrowser on dispatcher stream, but the destination of the event handler and mres.Wait I think everything can happen in the rendering request processing operation. I got The calling thread cannot access this object because a different thread owns it , but now I do not do this setting.
WebBrowser wb = null; var mres = new ManualResetEventSlim(); try { dispatcher.Invoke(() => { wb = new WebBrowser(); }); wb.LoadCompleted += (s, e) => { // Not firing }; try { using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms, Encoding.Unicode)) { sw.Write(html); sw.Flush(); ms.Seek(0, SeekOrigin.Begin); // GO! dispatcher.Invoke(() => { try { wb.NavigateToStream(ms); Debug.Assert(Dispatcher.FromThread(Thread.CurrentThread) != null); } catch (Exception ex) { // log } }); if (!mres.Wait(15 * 1000)) throw new TimeoutException(); } } catch (Exception ex) { // log } } finally { dispatcher.Invoke(() => { if (wb != null) wb.Dispose(); }); }
When I run this, every time LoadCompleted never fires, I get my timeout. I tried to verify that the dispatcher is working and working correctly. I donβt know how to do this, but I connected some dispatcher events from a static constructor, and I get some fingerprints from it, so I think it works.
The code hits the wb.NavigateToStream(ms); breakpoint wb.NavigateToStream(ms); .
Is this a bad dispatcher application? Is wb.LoadCompleted abandoned due to something else?
Thanks!