svrcoder
svrcoder

Reputation: 96

Winforms C# - Show Cancel dialog when main UI thread is busy

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

  1. I should clarify that I already use a worker thread to do the work.
  2. DisplayLogs() is in a seperate thread.
  3. DisplayLogs() is called from other threads.
  4. LogMessage is the delegate that points to the method UpdateMessage in main UI.
  5. The control used is a TextBox. I have tried other controls like listview, richtextboxsand, etc. still the same result.

Worker Thread

void DisplayLogs()
{
    lock (this)
    {
        while (logQueue.Count > 0)
        {
            string logMessagemessage = logQueue.Dequeue();
            LogMessage(string.Concat(logMessagemessage, Environment.NewLine));
        }
    }
}

Main UI

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

Answers (4)

bobbyalex
bobbyalex

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

Michael Fox
Michael Fox

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

Adam Houldsworth
Adam Houldsworth

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

MBirchmeier
MBirchmeier

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

Related Questions