Animating the opacity of a form in C # with BackgroundWorker
Using the BackgroundWorker, I created an opacity animation for some shape.
There is only one tiny problem with this approach, but I cannot figure out where the problem is. The animation speed is configurable and even if the speed value is very high, sometimes the animation is very, very slow, for some odd reason ...
The "slow animation" I'm talking about doesn't stutter, the animation is actually very smooth, the whole animation takes the longest to complete (0% to 100% or vice versa). It happens from time to time. It seems (not sure) that this happens when the computer is doing some other, somewhat intense background activity.
I need to fix this, of course, but I would also like to know if you will improve this code anyway, or if you do it differently and / or better.
Here's my code:
private const int TOGGLE_EFFECT_SPEED = 10;
private void blendWorker_DoWork(object sender, DoWorkEventArgs e) {
bool blendIn = (bool)e.Argument;
// Loop through all opacity values
for(double value = 1; value <= 100; value += 1) {
// Report the current progress on the worker
blendWorker.ReportProgress(0, blendIn ? value : 100 - value);
// Suspends the current thread by the specified blend speed
System.Threading.Thread.Sleep(11 - TOGGLE_EFFECT_SPEED);
}
// Set the worker result as the inverse tag value
e.Result = !blendIn;
}
private void blendWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
double opValue = (double)e.UserState;
// Show and repaint the whole main notes window?
if(opValue == 1.0) {
Show();
Invalidate(true);
}
// Set the main notes window opacity value
Opacity = (double)e.UserState / 100;
}
private void blendWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
bool tagFlag = (bool)e.Result;
// Hide the main notes window?
if(tagFlag) {
Hide();
}
// Set the main notes window tag value
Tag = tagFlag;
}
/*
THE FOLLOWING METHOD IS PART OF A DIFFERENT CLASS.
ACTUALLY, IT THE "PROGRAM" CLASS WHERE MAIN()
IS LOCATED. THIS METHOD IS CALLED TO SHOW/HIDE
THE MAIN APPLICATION FORM WITH AN OPACITY ANIMATION
*/
internal static void ToggleNotesWindow() {
// Get the tag value converted to boolean type
bool tagFlag = Convert.ToBoolean(NotesWindow.Tag, CultureInfo.InvariantCulture);
// Bring the main notes window to front?
if(tagFlag) Program.NotesWindow.BringToFront();
// Run the blend effect if it not already running
if(!NotesWindow.blendWorker.IsBusy) {
NotesWindow.blendWorker.RunWorkerAsync(tagFlag);
}
// Activate and focus the main notes window?
if(tagFlag) Program.NotesWindow.Activate();
}
a source to share
Every time you change the opacity of the form, Windows has to redraw all the windows below it, the window itself, and then apply the opacity (Vista does this much faster and is buffered). Since you are going through each opacity from 1 ... 100, this process must be done 100 times. Sometimes redrawing the window or the window below it will be slow.
The Thread.Sleep method with a value> 0 will fall off from 0 ... ~ 10ms no matter what value you pass. The thread scheduler timer resolution on Windows is about 10ms (Again, Vista and other OSs change and optimize so are not precise), so you cannot schedule a slice less than that. 100x10ms + actual rendering time may take 2 whole seconds to fade out.
The way to speed this up is to reduce the number of re-draws. Instead of typing +1 for opacity, step +5, +10, etc. This reduces the total number of re-draws required and results in a form freeze of 100ms instead.
a source to share