Invoke(Delegate)

后端 未结 9 1053
误落风尘
误落风尘 2020-11-22 16:33

Can anybody please explain this statement written on this link

Invoke(Delegate):

Executes the specified delegate on the thread that owns th

相关标签:
9条回答
  • 2020-11-22 17:02

    The answer to this question lies in how C# Controls work

    Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread. This property can be used to determine if you must call an invoke method, which can be useful if you do not know what thread owns a control.

    From Control.InvokeRequired

    Effectively, what Invoke does is ensure that the code you are calling occurs on the thread that the control "lives on" effectively preventing cross threaded exceptions.

    From a historical perspective, in .Net 1.1, this was actually allowed. What it meant is that you could try and execute code on the "GUI" thread from any background thread and this would mostly work. Sometimes it would just cause your app to exit because you were effectively interrupting the GUI thread while it was doing something else. This is the Cross Threaded Exception - imagine trying to update a TextBox while the GUI is painting something else.

    • Which action takes priority?
    • Is it even possible for both to happen at once?
    • What happens to all of the other commands the GUI needs to run?

    Effectively, you are interrupting a queue, which can have lots of unforeseen consequences. Invoke is effectively the "polite" way of getting what you want to do into that queue, and this rule was enforced from .Net 2.0 onward via a thrown InvalidOperationException.

    To understand what is actually going on behind the scenes, and what is meant by "GUI Thread", it's useful to understand what a Message Pump or Message Loop is.

    This is actually already answered in the question "What is a Message Pump" and is recommended reading for understanding the actual mechanism that you are tying into when interacting with controls.

    Other reading you may find useful includes:

    What's up with Begin Invoke

    One of the cardinal rules of Windows GUI programming is that only the thread that created a control can access and/or modify its contents (except for a few documented exceptions). Try doing it from any other thread and you'll get unpredictable behavior ranging from deadlock, to exceptions to a half updated UI. The right way then to update a control from another thread is to post an appropriate message to the application message queue. When the message pump gets around to executing that message, the control will get updated, on the same thread that created it (remember, the message pump runs on the main thread).

    and, for a more code heavy overview with a representative sample:

    Invalid Cross-thread Operations

    // the canonical form (C# consumer)
    
    public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type
    
    public void SetText(Control control, string text) {
        if (control.InvokeRequired) {
            control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
        } else {
            control.Text=text;      // the "functional part", executing only on the main thread
        }
    }
    

    Once you have an appreciation for InvokeRequired, you may wish to consider using an extension method for wrapping these calls up. This is ably covered in the Stack Overflow question Cleaning Up Code Littered with Invoke Required.

    There is also a further write up of what happened historically that may be of interest.

    0 讨论(0)
  • 2020-11-22 17:03

    this.Invoke(delegate) make sure that you are calling the delegate the argument to this.Invoke() on main thread/created thread.

    I can say a Thumb rule don't access your form controls except from main thread.

    May be the following lines make sense for using Invoke()

        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.textBox1.InvokeRequired)
            {   
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text = text;
            }
        }
    

    There are situations though you create a Threadpool thread(i.e worker thread) it will run on main thread. It won't create a new thread coz main thread is available for processing further instructions. So First investigate whether the current running thread is main thread using this.InvokeRequired if returns true the current code is running on worker thread so call this.Invoke(d, new object[] { text });

    else directly update the UI control(Here you are guaranteed that you are running the code on main thread.)

    0 讨论(0)
  • 2020-11-22 17:04
    Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
    
    0 讨论(0)
提交回复
热议问题