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();
}

      

+1


a source to share


2 answers


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.

+1


a source


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



0


a source







All Articles