.NET Forum / Languages / C# / August 2007
new form not responding
|
|
Thread rating:  |
Achilles____ - 31 Aug 2007 01:42 GMT 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(); } } }
Peter Duniho - 31 Aug 2007 02:43 GMT > 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
Achilles____ - 31 Aug 2007 03:38 GMT > > 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. [quoted text clipped - 23 lines] > 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".
Achilles____ - 31 Aug 2007 03:44 GMT > > > 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. [quoted text clipped - 31 lines] > 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?
Achilles____ - 31 Aug 2007 04:00 GMT Yes, I created a delegate for messageProcessor.Processmessage. It solved the problem. Thanks a lot Peter, for pointing in the right direction
Peter Duniho - 31 Aug 2007 04:26 GMT > 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
Achilles____ - 31 Aug 2007 14:20 GMT > > Instead if i use a delegate, it will do the same job right? > [quoted text clipped - 37 lines] > > 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?
Peter Duniho - 31 Aug 2007 17:28 GMT > 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 > [quoted text clipped - 10 lines] > 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
Achilles____ - 31 Aug 2007 18:42 GMT Thanks a lot Peter, you cleared the misconceptions about invoke and delegates.
Thanks again.
Achilles____ - 31 Aug 2007 14:28 GMT
> 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?
Peter Duniho - 31 Aug 2007 17:30 GMT > 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
Peter Duniho - 31 Aug 2007 04:12 GMT > 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
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|