创建一个从阻塞线程订阅事件的表单

Creating a form that subscribes to events from a blocking thread

所以我必须更新程序以使用更新版本的 Awesomium,特别是 1.7.5

有了更新,Awesomium 现在必须在它自己的线程上运行,而且它是阻塞的。

我可以使用 WebCore.QueueWork() 将工作排队到阻塞线程,这将完成在调用线程 WebCore.Run() 上传递的操作。我确保给它自己的线程,这样我的应用程序的其余部分就不会阻塞。

程序过去的运行方式是创建一个工作对象,该对象具有一个构造函数,该构造函数使用 WebCore 库实例化了 WebView 和 WebSession。然后它创建了一个表单,该表单接受一个工作对象作为参数,允许该表单订阅来自 WebCore 库的事件。

var worker = new Worker();
var debugForm = new PBForm(worker);
debugForm.Show();

worker 构造函数有这行代码,每当更新视图时调用函数 SurfaceIsDirty。

((ImageSurface)_view.Surface).Updated += (s, e) => { if (webView_SurfaceIsDirty != null) webView_SurfaceIsDirty(s, e); };

此函数在构造函数中赋值:

this.worker.webView_SurfaceIsDirty = (sender, e) =>
{
    ImageSurface buffer = (ImageSurface)this.worker._view.Surface;
    pictureBox1.Image = buffer.Image;
};

因此,只要 WebView 更新,表单图片就会更新。

这曾经能够在 WebCore 线程中 运行 但现在由于 WebCore 线程正在阻塞,我无法使此表单在其上正常工作。

这就是我被困的地方。我需要 运行 表单在一个单独的线程中,这样它就不会挂起,因为它被阻塞的 WebCore 线程卡住了。

我的思路如下:

  1. 创建工作人员时,在新线程中创建一个表单作为工作人员实例的 属性。
  2. 当 WebCore 事件发生时,worker 实例应该能够更新它的表单。

它正在编译,表单是响应式的,但图片没有更新,我怀疑这与现在处于不同线程中的表单有关。这是我现在拥有的相关代码:

我把这个属性加到工人class:

public PBForm2 DebugForm;

我在 WebCore 阻塞线程中实例化 worker class:

WebCore.QueueWork(AddWorker);

在 AddWorker 方法中,我创建了一个新线程和 运行 一个 Form,同时将它附加到 worker 属性:

static void AddWorker()
{
    var worker = new Worker();
    Workers.Add(worker);
    new Thread(() =>
    {
        worker.DebugForm = new PBForm2(worker.Id);
        var debugForm = new PBForm2(worker.Id);

        Application.Run(debugForm);
        Application.DoEvents();

    }).Start();
}

最后,工人事件本身现在是:

((ImageSurface)_view.Surface).Updated += (s, e) =>
{
    ImageSurface buffer = (ImageSurface)_view.Surface;
    DebugForm.pictureBox1.Image = buffer.Image;
    DebugForm.pictureBox1.Refresh();
};

看起来非常接近工作,表单响应用户交互,工作人员正在做他们的事情并触发事件,但图片在表单中并没有改变。事件正在发生并且新图像在那里,我怀疑表单在不同的线程中导致表单上的图像不更新。

这篇文章很长 post 如果您正在阅读本文,感谢您抽出宝贵的时间来阅读所有内容。在线程方面,我是一个新手,非常感谢任何建议或链接,甚至是搜索什么来解决这个问题。

您正在创建 2 个相同的表单:

worker.DebugForm = new PBForm2(worker.Id);
var debugForm = new PBForm2(worker.Id);

然后加载 debugForm,但是您的更新是对 DebugForm.picturebox1 完成的,因此您的更新将不会被看到。需要对 debugForm.picturebox1 进行更新,但您应该只创建一个。

在看不到所有代码的情况下,为什么不直接将代码加载到工作程序中 class 或将一个指向另一个?

Application.Run(worker.DebugForm);
Application.DoEvents();

worker.DebugForm = new PBForm2(worker.Id);
var debugForm = worker.DebugForm;

Application.Run(debugForm);
Application.DoEvents();

我想通了,在解决了我更新错误的 Form 对象的问题后(​​感谢 Troy Mac1ure),我 运行 陷入了一个线程问题,我无法从 Awesomium 线程访问 Form 的图片框.

我用助手解决了它class:

public static class ThreadHelper
{
    private delegate void SetPictureCallback(PBForm f, Image image);
    private delegate void AppendTextCallback(PBForm f, string text);

    public static void SetPicture(PBForm form, Image image)
    {
        if (form.InvokeRequired)
        {
            SetPictureCallback d = SetPicture;
            form.Invoke(d, form, image);
        }
        else
        {
            form.pictureBox1.Image = image;
            form.pictureBox1.Refresh();
        }
    }

    public static void AppendText(PBForm form, string text)
    {
        if (form.InvokeRequired)
        {
            AppendTextCallback d = AppendText;
            form.Invoke(d, form, text);
        }
        else
        {
            form.textBox1.Text += text;
            form.textBox1.SelectionStart = form.textBox1.TextLength - 1;
            form.textBox1.ScrollToCaret();
            form.textBox1.ScrollToCaret();
        }
    }
}

当在工作线程中触发事件时,我调用函数来更新表单:

_view.Surface = new ImageSurface();
((ImageSurface)_view.Surface).Updated += (s, e) =>
{
    ImageSurface buffer = (ImageSurface)_view.Surface;
    ThreadHelper.SetPicture(DebugForm, buffer.Image);
    Application.DoEvents();
};

_view.ConsoleMessage += (s, e) =>
    ThreadHelper.AppendText(DebugForm, string.Format("{0} : {1} [{2}]\r\n", e.LineNumber, e.Message, e.Source));