InvokeRequired of Form == false and InvokeRequired from the contained control == true

how is this possible? I have a window form control derived from System.Windows.Forms.Form with the WebBrowser control contained in this form. An instance of the Webbrowser object is created in the form constructor (in the InitializeComponent () method). Then, in the background thread, I manipulate the contents of WebBrowser, and I found that in some cases Form.InvokeRequired == false, and WebBrowser.InvokeRequired == true. How can it be?

+7
winforms webbrowser-control invokerequired
source share
3 answers

Form.InvokeRequired returns false until the form is displayed.

I did a simple test:

 Form2 f2 = new Form2(); Thread t = new Thread(new ThreadStart(() => PrintInvokeRequired(f2))); t.Start(); t.Join(); f2.Show(); t = new Thread(new ThreadStart(() => PrintInvokeRequired(f2))); t.Start(); t.Join(); 

with assistant

 private void PrintInvokeRequired(Form form) { Console.WriteLine("IsHandleCreated: " + form.IsHandleCreated + ", InvokeRequired: " + form.InvokeRequired); } 

output

IsHandleCreated: False, InvokeRequired: False
IsHandleCreated: True, InvokeRequired: True

Also note that this is somewhat described on MSDN :

If a control handle is not already installed, InvokeRequired searches to control the parent chain until it finds a control or form that has a window handle. If not, you can find the handle. InvokeRequired returns false.

This means that InvokeRequired can return false if Invoke is not required (the call is in the same thread), or if the control was created on another thread, but the control handle has not yet been created.

In the case where the control handle has not yet been created, you should not just call properties, methods, or events on the control. This can cause the control knob created against the background of the flow, isolating the flow control without a message pump and the application is unstable.

You can protect against this case also by checking the value of IsHandleCreated when InvokeRequired returns false in the background thread. If the control handle has not yet been created, you must wait until it was created before invoking Invoke or BeginInvoke. Typically, this only happens if a background thread is created in the primary form constructor for the application (as in Application.Run (new MainForm ()), before the form has been shown or Application.Run is called.

Your solution should also check IsHandleCreated .

Edit:
Handle can be created at any time inside the WebBrowser control or externally. This does not automatically create a handle to the parent form.

I created an example:

 public Form2() { InitializeComponent(); Button button1 = new Button(); this.Controls.Add(button1); Console.WriteLine("button1: " + button1.IsHandleCreated + " this: " + this.IsHandleCreated); var tmp = button1.Handle; // Forces the Handle to be created. Console.WriteLine("button1: " + button1.IsHandleCreated + " this: " + this.IsHandleCreated); } 

with output:

button1: False this: False
button1: True this: False

+9
source share

Here's a detailed study of the corresponding and more general problem: http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html

+1
source share

I study this weirdest behavior. I need to control some controls from different threads (for example, display information about a device that is associated with the host or trigger actions depending on the state of different devices).

This link gave me good advice: http://csharpfeeds.com/post/2898/Control.Trifecta_InvokeRequired_IsHandleCreated_and_IsDisposed.aspx

I still don’t know how MS people intended to use their own things (and disagree in many aspects), but in one application I had to make the following dirty and dirty workaround:

  • Create a control / form in the main thread (make sure that this is the main thread).
  • In the same procedure, check the control knob. This simple check will make it create in the right stream!

How ugly, isn't it? I would like to know if anyone else has a better way to do this.

 _my_control = new ControlClass( ); _my_control.Owner = this; IntPtr hnd; // Force Handle creation by reading it. if ( !_my_control.IsHandleCreated || _my_control.Handle == IntPtr.Zero ) hnd = _my_control.Handle; 

(Sorry to post some old posts on this, but I just thought it might be useful to someone).

0
source share

All Articles