Automating the InvokeRequired code pattern

后端 未结 9 1352
醉话见心
醉话见心 2020-11-21 23:57

I have become painfully aware of just how often one needs to write the following code pattern in event-driven GUI code, where

private void DoGUISwitch() {
           


        
9条回答
  •  清歌不尽
    2020-11-22 00:24

    Lee's approach can be simplified further

    public static void InvokeIfRequired(this Control control, MethodInvoker action)
    {
        // See Update 2 for edits Mike de Klerk suggests to insert here.
    
        if (control.InvokeRequired) {
            control.Invoke(action);
        } else {
            action();
        }
    }
    

    And can be called like this

    richEditControl1.InvokeIfRequired(() =>
    {
        // Do anything you want with the control here
        richEditControl1.RtfText = value;
        RtfHelpers.AddMissingStyles(richEditControl1);
    });
    

    There is no need to pass the control as parameter to the delegate. C# automatically creates a closure.


    UPDATE:

    According to several other posters Control can be generalized as ISynchronizeInvoke:

    public static void InvokeIfRequired(this ISynchronizeInvoke obj,
                                             MethodInvoker action)
    {
        if (obj.InvokeRequired) {
            var args = new object[0];
            obj.Invoke(action, args);
        } else {
            action();
        }
    }
    

    DonBoitnott pointed out that unlike Control the ISynchronizeInvoke interface requires an object array for the Invoke method as parameter list for the action.


    UPDATE 2

    Edits suggested by Mike de Klerk (see comment in 1st code snippet for insert point):

    // When the form, thus the control, isn't visible yet, InvokeRequired  returns false,
    // resulting still in a cross-thread exception.
    while (!control.Visible)
    {
        System.Threading.Thread.Sleep(50);
    }
    

    See ToolmakerSteve's comment below for concerns about this suggestion.

提交回复
热议问题