Program problem, seems simple...

S

Scooby

Okay, I'm a noob at C# and microsoft's IDE, but have a fairly long history
of programming (with, cough, Delphi). I'm writing a mobile app in C# with
Visual Studio 2005. I think there must be something fundamental that I'm
missing and could use a pointer in the right direction.

Below is a simplified version of a test program. I am using a namespace
provided from a dll file (used as MyNameSpace here). Anyway, I create a
component from within, which has a callback method. When I initiate the
process (button1_click), the callback happens just fine. However, I can not
seem to update any of the controls on the MainForm. As you will see, my
callback method has a call to Update Values. The call happens, but the
labels never get updated. However, initiating Button2_Click, will then call
UpdateValues and the labels will be updated.

It almost seems like my component is referencing a different instance of
MainForm. I would suspect this would be the behavior if I had not preceeded
my component with 'this' when creating it or the callback method. But, I
thought I got that right.

Anyway, anyone have an clues? Thanks for the help

Jim

============================================================

using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MyNameSpace;

namespace MyTestApp
{
public partial class MainForm : Form
{
private MyClass MyVar;

public MainForm()
{
InitializeComponent();
Int Val1, Val2;
this.MyVar = new MyClass();
this.MyVar.OnResponse += new
MyClass.OnResponseHandler(this.MyResponseHandler);
}

private void button1_Click(object sender, EventArgs e)
{
MyVar.SendRequest();
}

private void button2_Click(object sender, EventArgs e)
{
UpdateValues();
}

private void MyResonseHandler(object sender,
nsoftware.IPWorks.SnmpmgrResponseEventArgs e)
{
Val1 = System.Int64.Parse(MyVar.Value1);
Val2 = System.Int64.Parse(MyVar.Value2);
UpdateValues();
}

private void UpdateValues()
{
MessageBox.Show("Updating Values");
label1.Text = Convert.ToString(Val1);
label2.Text = Convert.ToString(Val2);
}

}
}
 
M

Marc Gravell

I tidied it up and added the missing code, and it works fine; are you sure
that the event is firing?

i.e. you should have something like:

public event EventHandler Response;
protected void OnResponse() {
EventHandler handler = Response;
if (handler != null) handler(this, EventArgs.Empty);
}
public void SendRequest() {
Value1--; // my random changes
Value2++;
OnResponse();
}

Oh - any by convention the event is named without the "On"; the "On"
preceeds the method used to fire the event - often protected and virtual.

Also - you might want to look at windows-forms bindings and making MyClass
implement INotifyPropertyChanged; this would allow you to tie MyClass to the
UI without any manual wiring required, yet get UI updates as the underlying
class is updated.

Marc
 
T

Tom Spink

Scooby said:
Okay, I'm a noob at C# and microsoft's IDE, but have a fairly long history
of programming (with, cough, Delphi). I'm writing a mobile app in C# with
Visual Studio 2005. I think there must be something fundamental that I'm
missing and could use a pointer in the right direction.

Below is a simplified version of a test program. I am using a namespace
provided from a dll file (used as MyNameSpace here). Anyway, I create a
component from within, which has a callback method. When I initiate the
process (button1_click), the callback happens just fine. However, I can
not
seem to update any of the controls on the MainForm. As you will see, my
callback method has a call to Update Values. The call happens, but the
labels never get updated. However, initiating Button2_Click, will then
call UpdateValues and the labels will be updated.

It almost seems like my component is referencing a different instance of
MainForm. I would suspect this would be the behavior if I had not
preceeded
my component with 'this' when creating it or the callback method. But, I
thought I got that right.

Anyway, anyone have an clues? Thanks for the help

Jim

============================================================
<snippedy-doo-dah>

Hi Jim,

Does your messagebox get shown? How are you invoking the callback? Are you
getting any exceptions about not being allowed to execute UI code from
another thread?

If you've got some cool cross-thread asynchronous code somewhere that
manages to invoke the callback from a thread other than the UI thread, then
you run into a problem. You'll need to invoke the code in the context of
the UI thread. Rename your 'UpdateValues' method to 'SafeUpdateValues' and
put the following code before it:

/// (Untested - I think my syntax is correct)
private delegate void SafeUpdateValuesDelegate ( );
private void UpdateValues ( )
{
if ( this.InvokeRequired )
this.Invoke( new SafeUpdateValuesDelegate( SafeUpdateValues ) );
else
SafeUpdateValues();
}
///

You should still make a call to UpdateValues, but that in turn will execute
the SafeUpdateValues method in the correct context.

Hope this helps,
-- Tom Spink
 
M

Marc Gravell

One other thought; it isn't shown in your code, but are you using multiple
threads? i.e. any of:

{delegate}.BeginInvoke
ThreadPool.QueueUserWorkItem
new Thread()
Anything else with "Begin..." in the name
?
If so, it it likely that the event is firing on a non-UI thread; any attempt
to talk to the Form's controls will then throw an exception, which may be
being absorbed by the calling code - especially if a matching "End..." isn't
being called (which in itself represents a leak - with the exception of
Control.EndInvoke).

If this is the case, post back and me (or somebody) will show you how to
switch threads in the form's event handler.

Marc
 
O

objectref

Thanks for the reply!

I initialize a stream writer on the server part to write something on the
socet that took the http request.
You mean that is something there that is not correct ?


Thanks again..
 
M

Marc Gravell

Well, something somewhere isn't playing nice...

Again - the biggest question in tracking this is: what (if anything) is
actually /invoking/ the event?

Start by putting a break-point in the event handler, and see if it ever
hits; if it doesn't then you have your answer; find out why the event isn't
being fired... if it /does/ hit, then try adding something to the debug
trace to check if your handler is crashing (typically because of threading
issues):

public SomeHandler(object sender, EventArgs args) {
Debug.WriteLine("Starting", "SomeHandler");
try {
// your existing code
Debug.WriteLine("Complete", "SomeHandler");
} catch (Exception ex) {
Debug.WriteLine("Failed:", "SomeHandler");
Debug.WriteLine(ex.Message, ex.GetType().Name);
throw;
}
}



And then it is a case of knowing what thread it is firing on;
 
S

Scooby

Tom Spink said:
<snippedy-doo-dah>

Hi Jim,

Does your messagebox get shown? How are you invoking the callback? Are
you
getting any exceptions about not being allowed to execute UI code from
another thread?

If you've got some cool cross-thread asynchronous code somewhere that
manages to invoke the callback from a thread other than the UI thread,
then
you run into a problem. You'll need to invoke the code in the context of
the UI thread. Rename your 'UpdateValues' method to 'SafeUpdateValues'
and
put the following code before it:

/// (Untested - I think my syntax is correct)
private delegate void SafeUpdateValuesDelegate ( );
private void UpdateValues ( )
{
if ( this.InvokeRequired )
this.Invoke( new SafeUpdateValuesDelegate( SafeUpdateValues ) );
else
SafeUpdateValues();
}
///

You should still make a call to UpdateValues, but that in turn will
execute
the SafeUpdateValues method in the correct context.

Hope this helps,
-- Tom Spink

Tom,

Wow, thanks to you and everyone that has responded. Okay, this does appear
to be on the right path, although this code successfully locks up my PDA.
However, the test for Invoke Required does happen when in the callback
function. So, I think this is a good start. I'll have a read up on these
keywords and see what debugging I can do. If you have anything else to add,
that would be great.

To all.... To answer your questions and elaborate a bit. This was a
watered down version of the app as I just wanted this to appear as simple as
possbile for the sake of troubleshooting. The dll I am using is 3rd party
and I don't have source code. My code in particular is not multithreaded
yet (although the end result will be). However, I believe the component
probably is. So, the comments as such are probably correct.

Yes, the MessageBox that is included in the trial app does get shown.
However, if I put a Messagebox after the label updates, it does not get
shown when in the callback. So, that does show that there is an exception
somewhere. However, I am not given any indication that an exception has
occured.

Thanks again everyone. Let me know if you have any more tips.

Jim
 
S

Scooby

Marc Gravell said:
One other thought; it isn't shown in your code, but are you using multiple
threads? i.e. any of:

{delegate}.BeginInvoke
ThreadPool.QueueUserWorkItem
new Thread()
Anything else with "Begin..." in the name
?
If so, it it likely that the event is firing on a non-UI thread; any
attempt to talk to the Form's controls will then throw an exception, which
may be being absorbed by the calling code - especially if a matching
"End..." isn't being called (which in itself represents a leak - with the
exception of Control.EndInvoke).

If this is the case, post back and me (or somebody) will show you how to
switch threads in the form's event handler.

Marc

Marc,

Detail in another post (response to Tom). I believe this is probably the
case. So, just how do I switch back to the main thread?

Thanks,

Jim
 
T

Tom Spink

Scooby said:
Tom,

Wow, thanks to you and everyone that has responded. Okay, this does
appear to be on the right path, although this code successfully locks up
my PDA. However, the test for Invoke Required does happen when in the
callback
function. So, I think this is a good start. I'll have a read up on these
keywords and see what debugging I can do. If you have anything else to
add, that would be great.

To all.... To answer your questions and elaborate a bit. This was a
watered down version of the app as I just wanted this to appear as simple
as
possbile for the sake of troubleshooting. The dll I am using is 3rd party
and I don't have source code. My code in particular is not multithreaded
yet (although the end result will be). However, I believe the component
probably is. So, the comments as such are probably correct.

Yes, the MessageBox that is included in the trial app does get shown.
However, if I put a Messagebox after the label updates, it does not get
shown when in the callback. So, that does show that there is an exception
somewhere. However, I am not given any indication that an exception has
occured.

Thanks again everyone. Let me know if you have any more tips.

Jim

Hi Jim,

Interesting that your code locks up. There's another way to execute code in
the context of the UI thread, it's slightly more complex, however:

using System.Threading;

public class MainForm : Form
{
private SynchronizationContext _context;

public MainForm ( )
{
_context = SynchronizationContext.Current;

if ( _context == null )
_context = new SynchronizationContext();

// Other constructor code
}

...

public void UpdateValues ()
{
if ( this.InvokeRequired )
{
_context.Send( delegate
{
SafeUpdateValues();
}, null );
}
else
SafeUpdateValues();
}

private void SafeUpdateValues ( )
{
...
}
}

So, I've put an ellipsis in where the original code should be. Again this
makes use of the 'SafeUpdateValues' routine, to contain the actual updating
code and the "unsafe" routine 'UpdateValues'.

Let us know if you have any problems,
-- Tom Spink
 
S

Scooby

Tom Spink said:
Interesting that your code locks up. There's another way to execute code
in
the context of the UI thread, it's slightly more complex, however:

using System.Threading;

public class MainForm : Form
{
private SynchronizationContext _context;

public MainForm ( )
{
_context = SynchronizationContext.Current;

if ( _context == null )
_context = new SynchronizationContext();

// Other constructor code
}

...

public void UpdateValues ()
{
if ( this.InvokeRequired )
{
_context.Send( delegate
{
SafeUpdateValues();
}, null );
}
else
SafeUpdateValues();
}

private void SafeUpdateValues ( )
{
...
}
}

So, I've put an ellipsis in where the original code should be. Again this
makes use of the 'SafeUpdateValues' routine, to contain the actual
updating
code and the "unsafe" routine 'UpdateValues'.

Let us know if you have any problems,
-- Tom Spink

Well, Tom... Again, good info, but it doesn't seem to do it for me.
Apparently, this is not available in the Compact Framework. Arg. But, I
have found a work around. Instead of having the callback, I can have the
component wait for a response. It locks up the app during the call (really
only when it doesn't get a response - until the timeout), but I can now plan
on placing the component itself in a separate thread, which I had planned on
doing anyway to accomplish mulitple instances. At least I can manage the
thread process at that point rather than relying on the component to do it.

Anyway, I have learned a lot here that will help in the process. I should
be able to use the commands that you provided when I do it that way. So,
thanks for everyone's info.

Jim
 

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