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

前端 未结 3 488
离开以前
离开以前 2021-01-12 12:11

how is it possible? I have windows Form control, derived from System.Windows.Forms.Form with WebBrowser control contained in this form. Webbrowser object instance is created

3条回答
  •  隐瞒了意图╮
    2021-01-12 13:01

    Form.InvokeRequired returns false before the form is shown.

    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 the helper

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

    the output is

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

    Also note that this is somewhat documented on MSDN:

    If the control's handle does not yet exist, InvokeRequired searches up the control's parent chain until it finds a control or form that does have a window handle. If no appropriate handle can be found, the InvokeRequired method returns false.

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

    In the case where the control's handle has not yet been created, you should not simply call properties, methods, or events on the control. This might cause the control's handle to be created on the background thread, isolating the control on a thread without a message pump and making the application unstable.

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

    Your solution is to also check for IsHandleCreated.

    Edit:
    The Handle can be created at any time internal in the WebBrowser control or externally. This does not automatically create the handle of 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 the output:

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

提交回复
热议问题