0

我想通过单独线程上的 WiForm DrawToBitmap()函数使用DevExpress ChartControl呈现图表。

我尝试类似:

Form yourForm;
Thread thread = new Thread( () =>
{
     yourForm = new HiddenForm();
     Application.Run(yourForm);
});
thread.ApartmentState = ApartmentState.STA;
thread.Start();
yourForm.Invoke(chartRenderingFunction)

并且简单地确保 Hidden 永远不会真正显示出来。但是,我不需要那种隐藏形式,并且有Application.Run()的无参数形式。但是,如果我运行它,它不会返回。所以我的问题是,一旦我在线程中调用 Application.Run(),我如何在其中注入代码?

4

1 回答 1

3

好吧,您实际上确实需要那个隐藏的窗口。让代码在该线程上运行的唯一方法。必须有人调用 PostMessage() 并且这需要一个窗口句柄。您的 Invoke() 调用进行了该调用。你真的应该使用 BeginInvoke() 代替,如果你要等待调用完成,那么启动线程是没有意义的。

使用 Application.Run(yourForm) 将使窗口可见。您可以通过覆盖 HiddenForm 类中的 SetVisibleCore() 方法来阻止它变得可见:

protected override void SetVisibleCore(bool value) {
    if (!this.IsHandleCreated) {
        CreateHandle();
        value = false;
        ThreadReady.Set();
    }
    base.SetVisibleCore(value);
}

CreateHandle() 调用对于确保创建窗口以便处理 PostMessage() 通知是必要的。还要注意添加的 AutoResetEvent (ThreadReady),在调用线程的 Start() 方法后,您必须调用 ThreadReady.WaitOne() 以确保您的 BeginInvoke() 调用能够正常工作。处理表单以使线程退出或调用 Application.Exit()。

最后但同样重要的是,在该线程上使用非平凡的控件时要非常小心。当然没有显示图表控件。例如,如果该控件使用 SystemEvents 类,您将遇到长期存在的问题。您的工作线程将让它在该工作线程上引发事件。但是在图表打印出来后它就不再存在了。您现在将在任意线程池线程上触发事件,非常讨厌。死锁是一种常见的事故,特别容易在锁定工作站时触发。

于 2013-10-15T14:41:33.233 回答