Control.Invoke with ShowDialog

C

Chris Dunaway

I have a main form with a "lock" button. When the lock button is
clicked, another form is shown using ShowDialog(this). The user must
enter their PIN on this form to close it and resume the main app.
Because it is showing using ShowDialog(this), the main form in the back
cannot be used until the user clears the login form. A feature was
added to the app to automatically lock the app after a period of
inactivity. This uses a timer. If the lock routine is called from the
timer, then I get an illegal cross thread operation exception,
presumably because the lock form is shown on another thread and passing
in "this" causes the exception. Here is the code for the lock routine,
the button click, and the idle timer:

void _idleTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
lockRegister();
_idleTimer.Start();
}

private void btnLock_Click(object sender, EventArgs e)
{
_idleTimer.Stop();
lockRegister();
_idleTimer.Start();
}

private void lockProgram()
{
LoginForm frmLogin = new LoginForm(_user, "Program
Locked!", true);

frmLogin.StartPosition = FormStartPosition.Manual;
frmLogin.Size = this.pnlDataEntry.Size;
frmLogin.Location = this.pnlDataEntry.Location;

frmLogin.ShowDialog(this);
if (frmLogin.DialogResult == DialogResult.OK)
_user = frmLogin.CurrentUser;
else
this.Close();
}

To summarize:

1. If the program is locked using the Lock button, it works correctly.
2. If the timer elapses, I get the cross thread exception.

I know I can check the InvokeRequired to see if I need control invoke,
but how do I pass "this" to the ShowDialog method in that instance so
that the main form cannot be accessed until the dialog is closed?

Thanks,

Chris
 
T

Tom Spink

Chris said:
I have a main form with a "lock" button. When the lock button is
clicked, another form is shown using ShowDialog(this). The user must
enter their PIN on this form to close it and resume the main app.
Because it is showing using ShowDialog(this), the main form in the back
cannot be used until the user clears the login form. A feature was
added to the app to automatically lock the app after a period of
inactivity. This uses a timer. If the lock routine is called from the
timer, then I get an illegal cross thread operation exception,
presumably because the lock form is shown on another thread and passing
in "this" causes the exception. Here is the code for the lock routine,
the button click, and the idle timer:
<snippedy-do-daah>

Hi Chris, change your _idleTimer_Elapsed function to this:

///
void _idleTimer_Elapsed ( object sender, System.Timers.ElapsedEventArgs e )
{
this.Invoke( new SafeLockRegisterDelegate( SafeLockRegister ) );
_idleTimer.Start();
}

private delegate void SafeLockRegisterDelegate ( );
private void SafeLockRegister ( )
{
lockRegister();
}
///

That should do the trick!
 
S

Stoitcho Goutsev \(100\)

Chris,

1. You can use System.Windows.Forms.Timer. It is not very accurate, but the
event handler is executed in the main UI thread and you won't run into this
threading probelms.

2. You can also use System.Timer.Timer also. Set the timer's
SynchronizingObject to reference one of your controls or the form itself and
then the timer will marshal its Elapsed event to the UI thread and you again
won't run to this problem. From what I see you use exactly this, just need
to set this property; no need of Control.Invoke in this case.


3. If you prefer to use ControlInvoke make sure that you

you create the PIN dialog form in the method that is marshaled using
Control.Invoke. The form needs to be created in the UI thread, it is not
only the ShowDialog that has to be to be called by the UI thread.
 
C

Chris Dunaway

Thanks Tom, Stoitcho for the suggestions.

What I ended up doing was using a delegate:

private delegate void lockdelegate();

I then changed my timer event as follows:

void _idleTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
//marshal the call to the correct thread using a delegate
this.Invoke(new lockdelegate(lockRegister));
_idleTimer.Start();
}

This way, the lock method is executed on the UI thread.

Thanks,

Chris
 
S

Stoitcho Goutsev \(100\)

Chris,

I want to say it one more time in case you missed it in my post. If you use
System.Timers.Timer class (component) you don't need to marshall the call by
your self. You can let the timer do it for you - just set the
SynchronizingObject property to reference a control on your UI.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top