简体   繁体   中英

C# thread safe control update

Question : When a form and its controls are accessed from a thread, which one is more suitable?:

  1. invoke form and update its controls in form-invoke

  2. invoke controls distinctly and update controls distinctly

Code

if (mainForm.InvokeRequired)
{
   mainForm.Invoke(
      (Action)(() =>
                  {
                     mainForm.label1.Text = "update";
                     mainForm.textBox1.Text = "update";
                     mainForm.button1.Text = "update";
                  }));
}
else
{
   mainForm.label1.Text = "update";
   mainForm.textBox1.Text = "update";
   mainForm.button1.Text = "update";
}


//OR

if (mainForm.label1.InvokeRequired)
{
   mainForm.Invoke((Action)(() => { mainForm.label1.Text = "update"; }));
}
else
{
   mainForm.label1.Text = "update";
}

Each time you Invoke , there's a delay and cost as we have to send a message to the UI thread, essentially the message being "please run this code". Then we have to wait for the UI thread to pick up this message (it may currently be busy doing some other work), run the code we've asked it to, and for it to indicate that it's done so. Then, finally, we can resume working after the Invoke call.

Now, in the grand scheme of things, this cost is quite a low one. So if you're just using Invoke once or twice, it's not worth considering. However, if you were planning on executing a big loop and Invoke ing inside the loop, you may want to pause and reconsider. It's usually better to move the Invoke outside of the loop instead.

However , the UI thread is a precious resource. We don't want to spend time on that thread doing non UI related tasks.

So if you have a loop doing a mixture of CPU-intensive work and UI updates, neither is necessarily appropriate. In such a case, see if you can re-structure your code so that you prepare batches of UI updates within the loop and then occasionally (or after the loop if possible) do an Invoke to just perform those UI updates.

In your case, you appear to already have a batch of UI updates to perform. So prefer the code that Invoke s once to do all three:

if (mainForm.InvokeRequired)
{
   mainForm.Invoke(
      (Action)(() =>
                  {
                     mainForm.label1.Text = "update";
                     mainForm.textBox1.Text = "update";
                     mainForm.button1.Text = "update";
                  }));
}
else
{
   mainForm.label1.Text = "update";
   mainForm.textBox1.Text = "update";
   mainForm.button1.Text = "update";
}

But note that it's usually better to structure the code so that you're not duplicating the actual UI updates that you have above. Something like:

private void DoUpdate()
{
   if(mainForm.InvokeRequired)
   {
      mainForm.Invoke(DoUpdate);
      return;
   }
   mainForm.label1.Text = "update";
   mainForm.textBox1.Text = "update";
   mainForm.button1.Text = "update";
}

I usally use the ISynchronizeInvoke since all forms/usercontrols inherit this interface, and then call a method to execute your action on the ui thread (if the invocation is required),

 public void SafeExecute(IView form, Action methodToExecute)
 {
      // args chek....
      ISynchronizeInvoke view = form as ISynchronizeInvoke;
      if(view != null)
      {
        if (!View.InvokeRequired)
            {
                methodToExecute();
            }
            else
            {
                view.Invoke(methodToExecute, null);
            }
      }
      else methodToExecute();
 }

and then in your codebehind you can call this method like this (I assume your view implement an interface, in this case I call it IView)

 SafeExecute(this, () => {
   mainForm.label1.Text = "update";
   mainForm.textBox1.Text = "update";
   mainForm.button1.Text = "update";
 })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM