Control.Invoke() problem at exit

J

Jen C.

Hi
I wanted to make a control with a method that is called
asynchronously to adjust something displayed in the control. I used
this.Invoke() to do this, and it works great until I close the form.
Then I get an exception because the method is being called after the
control is disposed. I tried to avoid this by stopping the thread
when the Form1.Closing event happens, but it does not help. How can I
make this work properly?

Thanks in advance,
Jenny C.


// These methods are in my Form1 class
protected void myThreadProc()
{
while(!m_bThreadDone)
{
this.userControl11.asyncSetCircleRadius(m_tick++);
if (m_tick > m_maxtick) m_tick = 10;
if(!m_bThreadDone) Thread.Sleep(40);
}
}


private void Form1_Closing(object sender, CancelEventArgs e)
{
m_bThreadDone = true;
Thread.Sleep(40);
}

// These are in my control:
public int CircleRadius
{
get
{
return m_circleSize;
}
set
{
m_circleSize = value;
this.Invalidate();
}
}

public int m_newCircleSize=10;

// public delegate void circleSizeDelegate();

protected void localSetCircleRadius(object Sender, EventArgs
args)
{
CircleRadius = m_newCircleSize;
}
public void asyncSetCircleRadius(int newRadius)
{
m_newCircleSize = newRadius;
this.Invoke(new EventHandler(localSetCircleRadius));
}
 
J

Jerod Houghtelling

Hi
I wanted to make a control with a method that is called
asynchronously to adjust something displayed in the control. I used
this.Invoke() to do this, and it works great until I close the form.
Then I get an exception because the method is being called after the
control is disposed. I tried to avoid this by stopping the thread
when the Form1.Closing event happens, but it does not help. How can I
make this work properly?

Thanks in advance,
Jenny C.

// These methods are in my Form1 class
protected void myThreadProc()
{
while(!m_bThreadDone)
{
this.userControl11.asyncSetCircleRadius(m_tick++);
if (m_tick > m_maxtick) m_tick = 10;
if(!m_bThreadDone) Thread.Sleep(40);
}
}

private void Form1_Closing(object sender, CancelEventArgs e)
{
m_bThreadDone = true;
Thread.Sleep(40);
}

// These are in my control:
public int CircleRadius
{
get
{
return m_circleSize;
}
set
{
m_circleSize = value;
this.Invalidate();
}
}

public int m_newCircleSize=10;

// public delegate void circleSizeDelegate();

protected void localSetCircleRadius(object Sender, EventArgs
args)
{
CircleRadius = m_newCircleSize;
}
public void asyncSetCircleRadius(int newRadius)
{
m_newCircleSize = newRadius;
this.Invoke(new EventHandler(localSetCircleRadius));
}

I didn't run any tests but have you tried?

if(!m_bThreadDone)
{
this.Invoke(new Eventhandler(localSetCricleRadius));
}

Although, I'm sure someone has a more elegant way to handle this
situation.
 
J

Jen C.

By putting in some global variable I found that by the time the
Form1.Closing event happens, the thread is stuck in Control.Invoke(),
and won't come out. I don't know why, but the following seems to
work. It doesn't seem like a very elegant solution. Does anybody
else have a better way?

What I do below is use this.BeginInvoke() instead, so that my thread
does not wait for the local function to get completed before returning
to the calling thread. The next time the thread calls I see if the
last call was completed and if so call EndInvoke(). Infact, in this
example, nCalledWhileStillBusy remains 0. However, this doesn't get
the exception that my first try does when I exit the app.


protected int m_newCircleSize=10;
protected IAsyncResult m_ar = null;
protected int m_nCalledWhileStillBusy=0;

protected void localSetCircleRadius(object Sender, EventArgs
args)
{
CircleRadius = m_newCircleSize; /* Set the size and
redraw the control */
}

public bool asyncSetCircleRadius(int newRadius)
{
m_newCircleSize = newRadius;
if (null != m_ar) /* Are we still in the handler since
the last call? */
{
if (m_ar.IsCompleted) /* See if we are in fact done */
{
EndInvoke(m_ar); /* If so call EndInvoke, and
note completion. */
m_ar = null;
}
else
{
/* If we land here, then localSetCircleRadius is
still busy */
m_nCalledWhileStillBusy++;
return false;
}
}
m_ar = this.BeginInvoke(new
EventHandler(localSetCircleRadius));
return true;
} // End asyncSetCircleRadius
}
}

-Jenny C.
 
J

Jen C.

Hi Jerod,
Thanks for the reply. I have tried many possible variations along
these lines, but it never works because it is stuck in this.Invoke()
at the time m_bThreadDone goes true.
-Jenny
 
J

Jerod Houghtelling

Hi Jerod,
Thanks for the reply. I have tried many possible variations along
these lines, but it never works because it is stuck in this.Invoke()
at the time m_bThreadDone goes true.
-Jenny

Threads are still a new concept that I haven't played around with a
lot. Other solutions might involve a Join on the thread,
AutoResetEvent, or a ManualResetEvent. You can use the ResetEvents to
flag when a thread has completed and then you can do a WaitOne on
them.

http://msdn2.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
http://msdn2.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

If you weren't aware of those classes I hope this helps. - Jerod
 
G

Guest

As a simple fix I typically just wrap the Invoke call with a try/catch
block.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
J

Jen C.

Thanks, Chris. That would be much simpler and if it never causes
any other problems I guess we can use that technique.

On a side note:
Thanks in general for being so active and helpful. It seems like
any time I do newsgroup searches to find an answer to a question, I
find helpful answers posted by you. As per the classification system
described in the paper: http://jcmc.indiana.edu/vol10/issue4/turner.html,
you are an Answer Person. (The definitions are about 3/4 of the way
through the doc). Answer People probably add more value to
newsgroups than any other. I am a Questioner, which is kind of lame,
but better than a Troll. :)

-Jenny
 

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