new form not responding

G

Guest

Im finding problem with this code. When i try to display the newindow, its
not responding. It does create the new window, but doesnt respond at all.
Just stays blank. I'm fairly new to c#(just a weeks experience), so it could
be some basic issue that im not aware of.

Please let me know if any part is not clear.

namespace newprogram
{
public partial class form1: Form
{
public delegate void MessageDelegate(string message);
public static MessageProcessor messageProcessor;
public static Server servermsg = new Server();
public SLMessenger()
{
InitializeComponent();
servermsg.onmessage += new Sender.MsgCallback(ReceiveMessage);
}
private void buttonLogin_Click(object sender, EventArgs e)
{
backgroundWorkerLogin.RunWorkerAsync();
}
private void backgroundWorkerLogin_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
messageProcessor= new MessageProcessor();
}

private void receiveMessage(string message)
{
if (message.Length > 0)
{
MessageDelegate M = new
MessageDelegate(messageProcessor.Processmessage);
D(message);
}
}

}

public class MessageProcessor
{
public IMWindow neWindow;
public void Processmessage(string message)
{
neWindow = new Form2();
neWindow.Show();
}
}
}
 
P

Peter Duniho

Achilles____ said:
Im finding problem with this code. When i try to display the newindow, its
not responding. It does create the new window, but doesnt respond at all.
Just stays blank.

I am willing to bet that the Server.onmessage event is raised on a
thread other than your main thread. Since the "neWindow" form gets
created on that thread, and since that thread has no message pump, the
form never gets to draw or do anything else that a window normally would do.

Your best bet is to use Invoke() to execute the code that instantiates
the form. For example, somewhere in your receiveMessage() event
handler, call it like this:

Invoke((MethodInvoker)delegate()
{ messageProcessor.Processmessage(); });

There are some other odd things about the code you posted:

You appear to have a BackgroundWorker component added to your form.
However, I don't see the code for the DoWork event handler.

In your receiveMessage() method, you create a delegate instance and
store it in a local variable M. But you never use that local variable,
and you call a method "D" that isn't defined in the code you posted.

Thanks,
Pete
 
G

Guest

Peter Duniho said:
I am willing to bet that the Server.onmessage event is raised on a
thread other than your main thread. Since the "neWindow" form gets
created on that thread, and since that thread has no message pump, the
form never gets to draw or do anything else that a window normally would do.

Your best bet is to use Invoke() to execute the code that instantiates
the form. For example, somewhere in your receiveMessage() event
handler, call it like this:

Invoke((MethodInvoker)delegate()
{ messageProcessor.Processmessage(); });

There are some other odd things about the code you posted:

You appear to have a BackgroundWorker component added to your form.
However, I don't see the code for the DoWork event handler.

In your receiveMessage() method, you create a delegate instance and
store it in a local variable M. But you never use that local variable,
and you call a method "D" that isn't defined in the code you posted.

Thanks,
Pete

Yes you are absolutely right, Server.message is created in another thread.

Thanks for the tip, I'll try to use invoke. I used the background worker
thinking that it will make the thread safe. Guess not?

I just copy pasted the fragments in hurry, pls ignore those mistakes. It
should have been DoWork and "M".
 
G

Guest

Achilles____ said:
Yes you are absolutely right, Server.message is created in another thread.

Thanks for the tip, I'll try to use invoke. I used the background worker
thinking that it will make the thread safe. Guess not?

I just copy pasted the fragments in hurry, pls ignore those mistakes. It
should have been DoWork and "M".
Instead if i use a delegate, it will do the same job right?

I have to pass the server messages to the new form, guess invoke wont work
in that case right?
 
G

Guest

Yes, I created a delegate for messageProcessor.Processmessage. It solved the
problem.
Thanks a lot Peter, for pointing in the right direction
 
P

Peter Duniho

Achilles____ said:
Yes you are absolutely right, Server.message is created in another thread.

As they say, "that's your problem right there". :)
Thanks for the tip, I'll try to use invoke. I used the background worker
thinking that it will make the thread safe. Guess not?

Nope, not in the way you are using it.

BackgroundWorker does in fact address cross-thread calling issues, but
you have to use it properly for that to happen. In particular, only the
ProgressChanged and RunWorkerCompleted events run on the main UI thread
(and I suspect then only when the delegate subscribed to those events is
an instance member of a Control-derived class, but I haven't played with
it enough to be sure).

That said, I don't really see why you are using BackgroundWorker at all
in this case.

You didn't post the DoEvent event handler, and the RunWorkerCompleted
handler doesn't do anything except instantiate the MessageProcessor
instance you're using. You could just as easily instantiate your
MessageProcessor instance in the constructor of the form1 class as far
as controlling which thread that instantiation occurs goes (it would be
the same thread in each case), and the thread on which the
MessageProcessor is instantiated doesn't affect the thread on which your
call to the MessageProcessor.Processmessage() method occurs.
I just copy pasted the fragments in hurry, pls ignore those mistakes. It
should have been DoWork and "M".

"M" I get (though see my follow-up to your other reply). What should
have been DoWork?

Pete
 
P

Peter Duniho

Achilles____ said:
Instead if i use a delegate, it will do the same job right?

I'm not exactly clear on what you mean here. But based on the code you
posted, it seems like you expect that calling through a delegate somehow
handles the cross-thread issue.

If so, that expectation is wrong. A delegate itself has nothing to do
with threading per se. It's often used in a threading context, but the
delegate class isn't providing any of the cross-thread handling directly.

It seems like in the code you posted, you are thinking that by wrapping
the call to the Processmessage() method that would somehow address the
cross-thread issue, but it doesn't. In fact, wrapping the call in a
delegate is for all intents and purposes identical to calling the method
directly. That's the point of the delegate; the actual call to the
method the delegate refers to occurs in whatever context the code
calling the delegate exists, so wrapping a method in a delegate and then
using the delegate immediately is the same as just calling the method
directly.
I have to pass the server messages to the new form, guess invoke wont work
in that case right?

I don't know what you mean here. If the Server.onmessage event is
raised on a different thread, not only will Invoke work for your
purposes, it is the most natural and easy way to get those messages
handled on the correct thread.

Without seeing the DoWork event handler, I can't say for sure. But I
suspect that the BackgroundWorker is not needed at all, and that what
you really need to do is use Invoke() in the receiveMessage() method.
What you do in that method exactly isn't clear to me; the code you
posted instantiates a new Form2 each time the Processmessage() method is
called, but from the above is sounds as though what you really want is
to instantiate the form once and then update the previously created form
with new messages.

But at the very least, I suspect you don't need the BackgroundWorker,
while you _do_ need Invoke().

Pete
 
G

Guest

Peter Duniho said:
I'm not exactly clear on what you mean here. But based on the code you
posted, it seems like you expect that calling through a delegate somehow
handles the cross-thread issue.

If so, that expectation is wrong. A delegate itself has nothing to do
with threading per se. It's often used in a threading context, but the
delegate class isn't providing any of the cross-thread handling directly.

It seems like in the code you posted, you are thinking that by wrapping
the call to the Processmessage() method that would somehow address the
cross-thread issue, but it doesn't. In fact, wrapping the call in a
delegate is for all intents and purposes identical to calling the method
directly. That's the point of the delegate; the actual call to the
method the delegate refers to occurs in whatever context the code
calling the delegate exists, so wrapping a method in a delegate and then
using the delegate immediately is the same as just calling the method
directly.


I don't know what you mean here. If the Server.onmessage event is
raised on a different thread, not only will Invoke work for your
purposes, it is the most natural and easy way to get those messages
handled on the correct thread.

Without seeing the DoWork event handler, I can't say for sure. But I
suspect that the BackgroundWorker is not needed at all, and that what
you really need to do is use Invoke() in the receiveMessage() method.
What you do in that method exactly isn't clear to me; the code you
posted instantiates a new Form2 each time the Processmessage() method is
called, but from the above is sounds as though what you really want is
to instantiate the form once and then update the previously created form
with new messages.

But at the very least, I suspect you don't need the BackgroundWorker,
while you _do_ need Invoke().

Pete

Thanks, Now i understand why it works. Its the invoke thats creating the new
UI thread right? I couldnt use the methodinvoker, as i had to pass parameters
to messageprocessor.

and this code

private void backgroundWorkerLogin_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
messageProcessor= new MessageProcessor();
}

it should have been.
private void backgroundWorkerLogin_DoWorkCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
messageProcessor= new MessageProcessor();
}

I coded it this way in my actual program. Got it wrong while creating the
sample.

Even if i use backgroundworker, i guess it wont create a ui thread right?
 
G

Guest

:

What you do in that method exactly isn't clear to me; the code you
posted instantiates a new Form2 each time the Processmessage() method is
called, but from the above is sounds as though what you really want is
to instantiate the form once and then update the previously created form
with new messages.

In my actual code, i have a dictionay <key,form2> that strores all forms
created, that took care of storing all active form related information. The
key used is a unique session id. Is there a better way than using a
dictionay?
 
P

Peter Duniho

Achilles____ said:
Thanks, Now i understand why it works. Its the invoke thats creating the new
UI thread right?

Invoke() doesn't _create_ a UI thread. It uses the one that already
exists. That's the whole point.

It is theoretically possible to create additional UI threads, but you
still wind up with the same cross-thread restrictions, and UI objects
created on a given UI thread still must be accessed from the UI thread
on which they were created.

Creating a new UI thread would just add to the complication.
I couldnt use the methodinvoker, as i had to pass parameters
to messageprocessor.

The use of MethodInvoker to cast the anonymous method is not mutually
exclusive with passing parameters to the code being called. In fact, it
really doesn't matter what the line of code you want to execute is; if
you wrap it in an anonymous method, cast the resulting delegate to
MethodInvoker and pass it to Invoke(), it will work. Even if the line
of code you want to execute includes parameters to pass.
and this code

private void backgroundWorkerLogin_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
messageProcessor= new MessageProcessor();
}

it should have been.
private void backgroundWorkerLogin_DoWorkCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
messageProcessor= new MessageProcessor();
}

I don't understand the difference. Both methods are the same; they just
have different names.

My point is that I don't see any need for the BackgroundWorker at all.
It only seems to be an added complication. Your previous post implies
that you used it as a way of trying to address the cross-thread issue,
but it doesn't do that, and so unless you have some _other_ reason for
also wanting to use the BackgroundWorker, you should just remove that
altogether.
I coded it this way in my actual program. Got it wrong while creating the
sample.

Even if i use backgroundworker, i guess it wont create a ui thread right?

No. Creating a UI thread is a very specific thing, and usually a
program has only a single UI thread, created by default via the code
provided by the Form-based application template. You don't need to
write any new code to create a UI thread; you just need to make sure you
write the code so that the UI thread that already exists is used correctly.

Pete
 
P

Peter Duniho

Achilles____ said:
In my actual code, i have a dictionay <key,form2> that strores all forms
created, that took care of storing all active form related information. The
key used is a unique session id. Is there a better way than using a
dictionay?

That should be fine. The point is to not create a new Form2 for every
single Processmessage() execution; if you are matching Form2 instances
to a session ID via a Dictionary<> class (instantiating a Form2 if not
found, I assume), that should work.

Pete
 
G

Guest

Thanks a lot Peter, you cleared the misconceptions about invoke and delegates.

Thanks again.
 

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