Click here to Skip to main content
15,938,218 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have created windows forms application with target framework 4.7.2. I am doing USB communication with device. I have 4 buttons on UI from which 2 button enable(connect and disconnect) and 2 disabled(download data and download log), when I click on Connect Device button. I send command to device and receive response. I verify device id is stored in my application or not, if it is stored then I enable those 2 disabled buttons and display one green signal. When I click on disconnect, I disable those 2 enabled button and signal with red color.

This is perfectly working fine when I open form for first time. When I close that form and again open it, InvokeRequired is getting false for all controls.

Below is code snippet.

Opening form from home form.

C#
MenuSystem menuSystem = new MenuSystem();
menuSystem.Show();


Disabling buttons from MenuSystem form.

C#
if (btnDownloadData.InvokeRequired)
                    btnDownloadData.Invoke((MethodInvoker)delegate { btnDownloadData.Enabled = true; });
                else
                    btnDownloadData.Enabled = true;
                if (btnDownloadLogData.InvokeRequired)
                    btnDownloadLogData.Invoke((MethodInvoker)delegate { btnDownloadLogData.Enabled = true; });
                else
                    btnDownloadLogData.Enabled = true;
                if (lblDeviceConnection.InvokeRequired)
                    lblDeviceConnection.Invoke((MethodInvoker)delegate { lblDeviceConnection.BackColor = Color.Green; });
                else
                    lblDeviceConnection.BackColor = Color.Green;


What I have tried:

I tried using timer and background worker but in all cases I am getting InvokeRequired is false and I have written else case as well to modify GUI, but it is also not reflecting on UI.

You help is truly appreciated.
Posted
Updated 6-Aug-23 20:24pm

InvokeRequired (Microsoft Learn)[^] is only required if calling from another thread other than the main UI thread. So what you need to do is work out why the first time you're on a different thread and the second why you are on the main thread. There is not enough information above to identify why.

To identify, for each instance, you need to set a breakpoint on the line if (btnDownloadData.InvokeRequired), then when hit, look at the call stack window and walk back up the calls to identify what is happening.

As a bonus, to help clean up your code, I have a helper class for InvokeRequired:
C#
ublic static class DispatcherHelper
{
    public static void Execute(Action action)
    {
        // no cross-thread concerns
        if (Application.OpenForms.Count == 0)
        {
            action.Invoke();
			return;
        }

		try
		{
			if (Application.OpenForms[0]!.InvokeRequired)
                // Marshall to Main Thread
				Application.OpenForms[0]?.Invoke(action);
            else
                // We are already on the Main Thread
                action.Invoke();
        }
		catch (Exception)
		{
			// ignore as might be thrown on shutting down
		}
    }
}

To use:
C#
DispatcherHelper.Execute(() => btnDownloadData.Enabled = true);

Which replaces this:
C#
if (btnDownloadData.InvokeRequired)
    DownloadData.Invoke((MethodInvoker)delegate
        { btnDownloadData.Enabled = true; });
else
    btnDownloadData.Enabled = true;
 
Share this answer
 
v3
If you look at the Reference Source for Control.InvokeRequired:Reference Source[^] it shows you the code:
C#
public bool InvokeRequired {
    get {

        using (new MultithreadSafeCallScope())
        {
            HandleRef hwnd;
            if (IsHandleCreated) {
                hwnd = new HandleRef(this, Handle);
            }
            else {
                Control marshalingControl = FindMarshalingControl();

                if (!marshalingControl.IsHandleCreated) {
                    return false;
                }

                hwnd = new HandleRef(marshalingControl, marshalingControl.Handle);
            }

            int pid;
            int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(hwnd, out pid);
            int currentThread = SafeNativeMethods.GetCurrentThreadId();
            return(hwndThread != currentThread);
        }
    }
}
Which clearly shows that each time you get the property value it specifically checks the thread that it is running on. If it's the UI thread, it returns false, if not it returns true.

Which means that the two calls are being made from different threads: one from a non-UI thread, and the second from a UI thread.

So you need to check exactly when that code is being executed, and what event caused it to execute - we can't do that!

Me? I'd check once if an invoke was required, and if so invoke the current method instead of checking repeatedly and duplicating code!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900