开发者

ProgressBar disappears when changed from within a thread

Why does the progress bar disappear when the style is changed from within a thread and how can I avoid having this happen?

I have a thread that runs for an indeterminate (but potentially lengthy) amount of time, so I wanted to use the progress bar to track the thread's progress. I set the progress bar style to marquee before starting the thread to start, however once the thread finishes and sets the progress bar style back to blocks (which you can do from another thread by setting Form.CheckForIllegalCrossThreadCalls = false) the progress bar disappears from the form visually. Additionally, if I put a button on my form for the express purposes of changing the progress bar style back and forth,开发者_运维知识库 it will reappear, and change style back and forth as the button is pressed successively.


From MSDN remarks on the CheckForIllegalCrossThreadCalls property:

When a thread other than the creating thread of a control tries to access one of that control's methods or properties, it often leads to unpredictable results. A common invalid thread activity is a call on the wrong thread that accesses the control's Handle property. Set CheckForIllegalCrossThreadCalls to true to find and diagnose this thread activity more easily while debugging.

It's generally considered bad practice to access a control from a thread other than the UI thread, and typically is not allowed.

You should instead look at using the Control.Invoke method. I typically handle cross thread UI updates like this:

public void UpdateProgressBar(int NewValue) 
{
   if(InvokeRequired)
      Invoke(() => UpdateProgressBar(NewValue));
   else
      progressBar.Value = NewValue;
}

This moves the work over onto the UI thread, where the control is safe to access.


(which you can do from another thread by setting Form.CheckForIllegalCrossThreadCalls = false)

Bad. Bad bad bad. Baaaaaaaad. They're called illegal cross-thread calls for a reason.

The only thread you should ever update the UI from is the UI thread. No exceptions. To achieve this, you should either use a BackgroundWorker and call the ReportProgress method (and handle it with a ProgressChangedEventHandler which will guarantee execution on the UI thread).

If you're not using a BackgroundWorker, you can pass a delegate with the logic to update the progress bar to the Invoke method on your progress bar to ensure that code is being run on the UI thread.


Woah there! Stay the heck away from CheckForIllegalCrossThreadClass. That property, while Microsoft made it available and I'm sure there is a very, very, very rare (and I mean rare) use for it, don't ever touch it. It will literally bring your software harm.

You can use a simple ISyncronizeInvoke approach to update your UI, which I also wrote a blog post on (very simple one).

/// <summary>
/// Helper class that allows synchronized invoking to be performed in a single line of code.
/// </summary>
internal static class SynchronizedInvoke {
    /// <summary>
    /// Invokes the specified action on the thread that the specified sync object was created on.
    /// </summary>
    public static void Invoke(ISynchronizeInvoke sync, Action action) {
        if (!sync.InvokeRequired) {
            action();
        }
        else {
            object[] args = new object[] { };
            sync.Invoke(action, args);
        }
    }
}

The usage is easy.

private void MyThreadWork() {
    // Do some work
    SynchnronizeInvoke.Invoke(uxProgressBar, () => uxProgressBar.Style = ProgressBarStyles.Blocks);
}


Honestly I never listened before about Form.CheckForIllegalCrossTHreadCalls, but documentation says:

When a thread other than the creating thread of a control tries to access one of that control's methods or properties, it often leads to unpredictable results. A common invalid thread activity is a call on the wrong thread that accesses the control's Handle property.

Set CheckForIllegalCrossThreadCalls to true to find and diagnose this thread activity more easily while debugging.

You by setting it to false just say "shut up" to the problem you raise.

You can not change control from the thread other then UI. So do not use this property. Just use Form's Invoke to run the code on the main thread.

SO Example

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜