BeginInvoke错误

时间:2010-08-06 08:19:18

标签: c# multithreading delegates

HI,

这句话继续问我this link的问题。

我写了一个应用程序来比较那里使用的方法和其他方法。在调试模式下运行应用程序时,我收到错误“在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke”。在方法UpdateCustDetails中的第一个BeginInvoke上。虽然,它没有在没有调试的情况下运行代码时给出任何运行时错误。任何想法??

谢谢, ABHI。

以下是我的代码: -

public delegate void UpdateLabelDelegate(Label lb, string text);
public delegate void loadCustomersDelegate();

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        loadCustomersDelegate del = new loadCustomersDelegate(UpdateCustDetails);
        IAsyncResult ar = del.BeginInvoke(null, null);

        while (!ar.IsCompleted)
        {
        }

    }

    public void updateLabel(Label lb, string text)
    {

        lb.Text = text;

    }

    public void UpdateCustDetails()
    {
        BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label1, "Test" });
        BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label2, "Test1234" });
        BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label3, "Test5678" });
        BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label4, "Test0000" });
    }
}

1 个答案:

答案 0 :(得分:1)

首先,我会就发布的代码结构提出一些可能有用的建议。

代码的作用是:

  • Form1的构造函数中,异步调用方法(在不同的线程上)
  • 该方法异步调用对单独方法的四次调用来更新标签控件。调用被推回到UI线程(我们在Form1的构造函数中的线程)
  • 同时,构造函数在继续
  • 之前等待原始方法完成

此代码中有许多内容:

  • 异步调用方法(以非阻塞方式),然后代码等待其完成。除非有一个令人信服的理由让这个代码在后台线程上,为什么不只是同步调用该方法呢?它将使最终行为保持不变,但使调试和阅读代码变得更加容易。
  • 由于while循环等待ar.IsCompleted,你会发现UI线程实际上非常繁忙 - 在那个空循环上锤击CPU,而不是闲置并允许后台线程跑。我怀疑同步调用该方法会更有效。
  • 因为UpdateCustDetails使用BeginInvoke,它将发送四个异步调用并立即返回。这意味着 - 即使构造函数正在等待ar.IsCompleted - 您也无法保证在构造函数完成时更新标签 - 因为对updateLabel的四次调用都没有阻塞。 / LI>
  • 实际上,因为Form.BeginInvoke将执行踢回到表单的UI线程,所以你真正要做的就是启动后台线程,只是为了将工作重新放回创建它的线程。

所以简而言之:忽略错误,取出所有聪明的线程,然后执行此操作:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        UpdateCustDetails();
    }

    public void updateLabel(Label lb, string text)
    {
        lb.Text = text;
    }

    public void UpdateCustDetails()
    {
        updateLabel(label1, "Test");
        updateLabel(label2, "Test1234");
        updateLabel(label3, "Test5678");
        updateLabel(label4, "Test0000");
    }
}

您将获得相同的结果,更好的性能和更易读的代码。