views:

1203

answers:

3

With the help of the BackgroundWorker, I created an opacity animation for some form.

There's only one tiny issue with this approach but I can't understand where is the problem. The animation speed is configurable and even if the speed value is very high, sometimes the animations is very, very slow, for some odd reason...

The "slow animation" I'm talking about it's not stutter, the animation is actually very smooth, it just takes more time to perform the whole animation (from 0% to 100%, or vice-verse). This only happens from time to time. It seems (not sure) that it happens when the computer is doing some other, somewhat intensive, background action.

I need to fix that of course but I also would like to know if there's anyway you would improve this code or if you would 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'S 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's not already running
    if(!NotesWindow.blendWorker.IsBusy) {
     NotesWindow.blendWorker.RunWorkerAsync(tagFlag);
    }

    // Activate and focus the main notes window?
    if(tagFlag) Program.NotesWindow.Activate();
}
A: 

Overall I don't see much that would warrant a change at least at first glance. If you are seeing some performance bottlenecks you might try having a look at Ants Profiler or a similar code profiling tool to see if you can pinpoint any slow sections.

Mitchel Sellers
But there are no "slow sections", most of the time, the code works, it does exactly what is supposed to do. Some other times, not that often, it fades in slow motion...
Nazgulled
+1  A: 

Each time you change the opacity of the form, Windows has to redraw all the windows below it, the window itself and then apply opacity (Vista does this much faster and buffered). Since you're stepping through each opacity state from 1...100 this process has to complete 100 times. Sometimes redrawing your window or a window below it will be slow.

The Thread.Sleep method with a value > 0 will sleep from 0...~10ms no matter what value you pass. The thread scheduler timer resolution on Windows is approx 10ms (Again, Vista and other OS change and optimize so it's not exact) so you can't schedule a time slice smaller than that. 100x10ms + the time to actually render might take 2 whole seconds to fade in/out.

The way to speed it up is to reduce the number of re-draws. Rather than stepping +1 for opacity, step +5, +10, etc. That reduces the total number of re-draws required and would result in a form fading in 100ms instead.

Paul Alexander
I don't think that's correct cause I definitely see a fade speed difference between TOGGLE_EFFECT_SPEED = 1 (sleep(10)) and TOGGLE_EFFECT_SPEED = 10 (sleep(1)). And I also see a difference between this two with value between 1 and 10. And I don't think you got what I meant by "slow" because the speed value doesn't matter, the problem I'm having happens without a speed value change.
Nazgulled
You won't see much of a difference between speed values of 1 and 10 since the thread scheduler doesn't sleep for less than 10 ms in most circumstances - so they will appear to be the same speed. The thing that's going to have the biggest effect is how slowly it takes to render your window and the windows beneath it.
Paul Alexander
A: 

Does anyone else have any more ideas?

Nazgulled