Reputation: 96
I have a main form that contains an edit control that occupies the entire form. There is another worker thread that constantly writes log messages to this edit control. Now I want to show a dialog box with just a cancel button while the main UI's edit control is displaying stuff. The problem is that the cancel dialog is non-responsive while the updates are happening behind it and I cannot click on the cancel button. Any idea on how to resolve it. I was thinking of creating another UI thread and show the cancel button from it. Any other alternatives?
EDIT#1
void DisplayLogs()
{
lock (this)
{
while (logQueue.Count > 0)
{
string logMessagemessage = logQueue.Dequeue();
LogMessage(string.Concat(logMessagemessage, Environment.NewLine));
}
}
}
public void UpdateMessage( string message)
{
if (!txtLog.IsHandleCreated)
{
return;
}
if (txtLog.InvokeRequired)
txtLog.BeginInvoke( new UpdateLogDelegate( UpdateLog), message);
else
txtLog.AppendText(message);
}
Upvotes: 2
Views: 1256
Reputation: 2751
Your problem is that the your UI thread is ALWAYS busy. I am saying this assuming that the number of items in logQueue
is quite large. The while loop doesn't quit till the queue is empty. So it keeps hitting the UI thread with request for updates.
Also the if (txtLog.InvokeRequired)
is kind of pointless because you are always calling the method from a worker thread.
So, since a .net WinForm application has only a single UI, which in your case is too busy to process other notifications, the new window appears stuck (because the paint messages are stuck in the message queue and cannot be processed as it is already flooded with the text box update messages)
You could stick an Application.DoEvents
inside your loop which will give the message loop some time to process the pending notifications. However this is kind of a hack, in my opinion, as the UI behavior is sometimes not predictable. It may lead to things like stuttering while moving a dialog, delayed responses to click events etc.
Another point, MessageBox.Show
or a Form.ShowDialog
(if this is what you are using for the cancel button) is a blocking call. The thread on which you show it WILL hang till you dismiss the dialog. Try Form.Show
and set the parent property to the main form.
Another alternative is to add a timer and process only X notifications per Y seconds. This will give the UI thread some breathing room for performing other activities.
Upvotes: 0
Reputation: 611
You are going about this backwards. The main thread should, in theory, always be available to accept user input. Anything that may block for extended periods of time (heavy computation, database access, network access) should be done in a background thread. The idea is to have the edit control's data being computed and populated by a background thread (BackgroundWorker
objects work nicely here) so that the main thread is always available if the user clicks on the cancel button.
Upvotes: 0
Reputation: 64467
The main solution is to offload the expensive code onto a background worker and leave your UI thread responsive for UI actions. Your form can then simply show a modal dialog or something.
MSDN - How to use a Background Worker
Upvotes: 3
Reputation: 134
In this situation it's necessary to move the majority of the work to a new thread, and clear up the UI thread for cancel messages etc.
Upvotes: 0