Tide Gu
Tide Gu

Reputation: 835

How to Invoke multiple controls in C#

I have a C# program seems stuck at random time, and after a random while it recovered itself! When it stuck, I can see the memory growth, and when it recover, the memory usage just drops to normal. The CPU usage seems normal all the way and there is no files is written or read (as designed).

The program calls an external (3rd party) DLL function to communicate with hardware, and updates the UI from the DLL's callback which running on a different thread. I have checked the code and found nothing suspicious apart from the following code (redacted):

private void Func(StructType para) {
    if (labelA.InvokeRequired) {
        labelA.BeginInvoke(new MethodInvoker(() => Func(para)));
        return;
    }
    if (labelB.InvokeRequired) {
        labelB.BeginInvoke(new MethodInvoker(() => Func(para)));
        return;
    }
    labelA.Text = para.A;
    labelB.Text = para.B;
}

I wonder if this is a proper way of update the UI element from another thread? If not, how to revise it?

In fact, I invoke 6 labels and another form (optionally). It seems working fine for most time but occasionally stuck. I can't post all code here for obvious reason, but just trying to troubleshot from where I doubt most.

Thanks in advance for any suggestions!

Upvotes: -2

Views: 1880

Answers (1)

antiduh
antiduh

Reputation: 12435

You don't need to individually check each each control to determine if you need to invoke it - there is only one UI thread, thus, that check is only useful once. Keep in mind - modifying any UI component is almost certain to cascade into a whole bunch of other reads/writes to other UI components; as a result of that, you have to make the assumption that if you are touching any UI object, you have to assume you're touching all UI components.

With that in mind, I'd recommend you perform your invoke check once, and I recommend performing the check and invoke on the parent control of both labels.

Assuming this refers to the class that is the parent to both those labels, I would modify your code as follows:

private void Func(StructType para) {
    if (this.InvokeRequired) {

        // Elide the explicit delegate declaration; it's not necessary.
        this.BeginInvoke( Func(para) );

        // Elide the return statement - multiple returns are messy, and in this case, easily removed.
    }
    else {
       labelA.Text = para.A;
       labelB.Text = para.B;
   }
}

Be aware that InvokeRequired returns false if the object is disposed, even if the calling thread is not the UI thread.

Upvotes: -1

Related Questions