Program problem, seems simple... | | |
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);
}
}
} | | | | re: Program problem, seems simple...
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 | | | | re: Program problem, seems simple...
Scooby wrote:
[color=blue]
> 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
>
> ================================================== ==========[/color]
<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 | | | | re: Program problem, seems simple...
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 | | | | re: Program problem, seems simple...
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..
"Marc Gravell" <marc.gravell@gmail.com> wrote in message
news:%238L9nBglGHA.2392@TK2MSFTNGP04.phx.gbl...[color=blue]
>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
>[/color] | | | | re: Program problem, seems simple...
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; | | | | re: Program problem, seems simple...
"Tom Spink" <tspink@gmail.com> wrote in message
news:OB7OrGglGHA.1972@TK2MSFTNGP05.phx.gbl...[color=blue]
> <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[/color]
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 | | | | re: Program problem, seems simple...
"Marc Gravell" <marc.gravell@gmail.com> wrote in message
news:OoalAIglGHA.1832@TK2MSFTNGP04.phx.gbl...[color=blue]
> 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[/color]
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 | | | | re: Program problem, seems simple...
Scooby wrote:
[color=blue]
> "Tom Spink" <tspink@gmail.com> wrote in message
> news:OB7OrGglGHA.1972@TK2MSFTNGP05.phx.gbl...[color=green]
>> <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[/color]
>
> 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[/color]
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 | | | | re: Program problem, seems simple...
Tom has already shown 2 ways of doing this
Marc | | | | re: Program problem, seems simple...
"Tom Spink" <tspink@gmail.com> wrote in message
news:O53ayEjlGHA.3740@TK2MSFTNGP02.phx.gbl...[color=blue]
> 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[/color]
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 |  | Similar C# / C Sharp bytes | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,510 network members.
|