如何获得control.Handle属性跨线程

时间:2014-06-16 16:35:56

标签: c# multithreading

我是并行编程的新手,在尝试绘制测量结果时,我遇到了臭名昭着的错误“控制控件名称从一个线程访问,而不是它创建的线程。”

经过数小时的网页浏览和失败的实验后,我不得不放弃并寻求建议。

我想要做的是在程序继续执行时在单独的线程中进行一些绘图。

在绘图程序中(在Panel控件上)我非常广泛地使用API​​调用(Polyline,BitBlt等),我必须使用IntPtr hDCh_Dst = Win32.GetDC(pnlSchermo.Handle)。

我在网上找到了数千个针对此问题的建议解决方案(几乎所有解决方案都设置属性和一些用于获取)但我无法使它们正常工作。

以下是我目前正在WFA项目中测试的(简化)代码。

do
{
    // Data acquisition and processing...
    // etc...

    // Plot the measurement results...
    Thread thrDisegna = new Thread(() => DisegnaGrafico(NcF: NcZxF));
    thrDisegna.Start();

    // Do some other processing...

    // Wait for the end of the plot job:
    while (thrDisegna.IsAlive);

}
while (bMisuraOn);

private void DisegnaGrafico(string HcTipo = "", int NcF = 0)
{
    // Some initialisations...

    // Call the method XY in the Class QL (that is an instance of the Class Quadro) for scaling the pnlSchermo control and do some API plot:
    QL.XY(pnlSchermo, ..., ..., ref hdcDst, ..., ...);

    // Some other API plotting using the hdcDst...
}

public void XY(Panel pnlSchermo, ..., ..., ref IntPtr hdcDst, ..., ...))
{
    // ...

    // Here is where I need to use the pnlSchermo.Handle:
    hDCh_Dst = Win32.GetDC(pnlSchermo.Handle); // <-- Fails with the "Control control name accessed ..." exception.

    // or... but doesn't work either and the program hangs:
    pnlSchermo.Invoke(new MethodInvoker(delegate() { hDCh_Dst = Win32.GetDC(pnlSchermo.Handle); }));

    // or... the program doesn't hangs, no exception thrown but returns _hDCh_Dst = 0. Does it need a EndInvoke?
        IntPtr _hDCh_Dst = IntPtr.Zero;
    pnlSchermo.BeginInvoke(new MethodInvoker(delegate
    {
        _hDCh_Dst = pnlSchermo.Handle;
    }));
        hDCh_Dst = Win32.GetDC(_hDCh_Dst);

    // or... other solutions found on the Web and tested without success...
}

Ciao,感谢您的关注。

佛朗哥

1 个答案:

答案 0 :(得分:0)

解决!!

越来越多的网页浏览时间给了他们成果!

Control.Invoke挂起应用程序的问题是由于Invoke的交叉干扰,它在返回之前等待它完成,并且主线程循环在:

而(thrDisegna.IsAlive);

用以下内容替换此行就足够了:

做{Application.DoEvents(); } while(thrDisegna.IsAlive);

让以下句柄访问方法有效:

        IntPtr hDCh_Dst1 = IntPtr.Zero;
        pnlSchermo.Invoke(new MethodInvoker(delegate() { hDCh_Dst1 = Win32.GetDC(pnlSchermo.Handle); }));
        hDCh_Dst = hDCh_Dst1;

现在,为了好奇,我必须调查为什么pnlSchermo.BeginInvoke(...)继续返回零...

Ciao和下一个。

佛朗哥