Reputation: 2977
HI,
This quetion is in continuation to my question at this link.
I wrote an application to compare the approach, used there, with other ways. While running the application in debug mode I got the error "Invoke or BeginInvoke cannot be called on a control until the window handle has been created." on the first BeginInvoke in method UpdateCustDetails. Although, it doesn't give any runtime error while running the code without debug. Any ideas??
Thanks, Abhi.
Below is my code:-
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" });
}
}
Upvotes: 2
Views: 310
Reputation: 34218
Firstly, there are a few things I'd say about the structure of the code posted that might help.
What the code does is this:
Form1
, asynchronously invokes a method (on a different thread)There are a number of sillinesses in this code:
while
loop waiting on ar.IsCompleted
, you'll find that the UI thread is actually quite busy - hammering the CPU on that empty loop, instead of sitting idle and allowing background threads to run. I suspect that calling the method synchronously would be more performant.UpdateCustDetails
uses BeginInvoke
, it's going to send off the four asynchronous calls and return immediately. That means that - even though the constructor is waiting for ar.IsCompleted
- you have no guarantee that the labels will be updated by the time the constructor completes - because the four calls to updateLabel
aren't blocking.Form.BeginInvoke
kicks execution back to the form's UI thread, what you're really doing is kicking off a background thread just to kick work back to the thread that created it. So in short: ignore the error, take out all of the clever looking thread stuff, and just do this:
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");
}
}
You'll get the same result, with better performance, and more readable code.
Upvotes: 1