Daniel Peñalba
Daniel Peñalba

Reputation: 31897

ShowDialog using invoke is making the application unresponsive

I'm using Control.Invoke() to show a dialog. The code is a handler to get credentials from the user and it can be execute in a thread, this is the reason I perform the call into an InvokeRequired/Invoke snippet.

Sometimes, and only in some machines, when I close the dialog, the application becomes unresposive (it does not manage some mouse clicks, but manage others). If I execute some "allowed" actions, the application start to be responsive again. It seems that processing any event, the application fixes itself.

Do you know any known bug in the .NET framework, or something that could cause this issue?

Thanks in advance.


EDIT: This is the code I'm using:

public class GuiCredentialsHandler
{
    // control used to invoke if needed
    private static Control mInvokeControl;

    // control used as parent for showDialog (could be null)
    private static Control mParentControl;

    /// <summary>
    /// Initialize a GetCredentials handler for current process.
    /// This method should be always called from the UI thread, for
    /// a correctly handling for invokes (when the handler is called
    /// from a thread).
    /// </summary>
    /// <param name="parentControl">Application top form. 
    /// Can be null if unknown</param>
    public static void Initialize(Control parentControl)
    {
        if (parentControl != null)
        {
            mInvokeControl = parentControl;
        }
        else
        {
            mInvokeControl = new Control();
            // force to create window handle
            // otherwise, invoke required always
            // return false
            mInvokeControl.CreateControl();
        }

        mParentControl = parentControl;
    }

    public static Credentials GetCredentials(
        string servername, SEIDWorkingMode serverWorkingMode)
    {
        if (mInvokeControl.InvokeRequired)
        {
            return mInvokeControl.Invoke(
                new GetCredentialsDelegate(DoGetCredentials),
                new object[] { servername, serverWorkingMode })
            as Credentials;
        }
        else
        {
            return DoGetCredentials(servername, serverWorkingMode);
        }
    }

    private static Credentials DoGetCredentials(
        string servername, SEIDWorkingMode serverWorkingMode)
    {

        GetCredentialsDialog dialog = new GetCredentialsDialog();

        dialog.Server = servername;
        dialog.WorkingMode = serverWorkingMode;

        DialogResult result = dialog.ShowDialog(mParentControl);

        if (result == DialogResult.Cancel) return null;

        UserInfoRetriever retriever = new UserInfoRetriever(
            servername, serverWorkingMode,
            dialog.UserName, dialog.Password);

        SEID seid = retriever.GetCurrentUser();

        return new Credentials(seid, serverWorkingMode);
}

public delegate Credentials GetCredentialsDelegate(
    string serverName,
    SEIDWorkingMode mode);

Upvotes: 0

Views: 1772

Answers (2)

Security Hound
Security Hound

Reputation: 2548

mParentControl will always be set equal to parentControl even if its NULL which does not seem right.

The reason your program becomes unresposive is because your mParentControl is NULL:

DialogResult result = dialog.ShowDialog(mParentControl);

One solution around this problem is to only show the dialog if the parent is known.

if ( mParentControl != NULL )
    DialogResult result = dialog.ShowDialog(mParentControl);
else
    DialogResult result = dialog.ShowDialog(mInvokeControl);

I based my answer on the following code:

 if (parentControl != null)
                { 
                   mInvokeControl = parentControl;                
                }       

I think you mean my answer makes no sense. What makes more sense that Hans Passant comment doesn't hold some truth or your code is actually correct and you discovered a bug. Since you are being rude I will just take my experience and help somebody else. Humor yourself and add code to avoid the mParentControl is Null situation because IT CAN HAPPEN. mParentControl is ALWAYS set to parentcontrol even when its NULL.

Application top form. /// Can be null if unknown

Upvotes: 0

sgmoore
sgmoore

Reputation: 16077

Is Control.Invoke actually needed in this case?

I was always under the impression that invoke was used to ensure that UI elements are accessed by the thread that creates the control which is usually the UI thread but does not have to be.

In this case it looks like you are trying to create a dialog from a thread and hence you should be able to update it from the thread. (Obviously you can't access it from outside your thread, which will include the main UI thread).

If I'm wrong no doubt this will get downvoted very quickly.

Upvotes: 1

Related Questions