2009-05-19 8 views
1

Avec l'aide de BackgroundWorker, j'ai créé une animation d'opacité pour une forme quelconque.Animation d'opacité de formulaire en C# avec un BackgroundWorker

Il y a seulement un petit problème avec cette approche mais je ne peux pas comprendre où est le problème. La vitesse d'animation est configurable et même si la valeur de la vitesse est très élevée, parfois les animations sont très, très lentes, pour une raison étrange ...

La "slow animation" dont je parle n'est pas bégayante, la l'animation est en fait très douce, il faut juste plus de temps pour réaliser l'animation entière (de 0% à 100%, ou vice versa). Cela arrive seulement de temps en temps. Il semble (pas sûr) que cela se produise lorsque l'ordinateur effectue une autre action de fond, quelque peu intensive.

Je dois corriger cela bien sûr mais j'aimerais aussi savoir s'il y a moyen d'améliorer ce code ou si vous le feriez différemment et/ou mieux.

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

Répondre

1

Chaque fois que vous modifiez l'opacité du formulaire, Windows doit redessiner toutes les fenêtres situées en dessous, la fenêtre elle-même, puis appliquer l'opacité (Vista le fait beaucoup plus rapidement et tamponné). Puisque vous passez par chaque état d'opacité de 1 à 100, ce processus doit se terminer 100 fois. Parfois, redessiner votre fenêtre ou une fenêtre en dessous sera lente.

La méthode Thread.Sleep avec une valeur> 0 va dormir de 0 ... ~ 10ms, quelle que soit la valeur que vous passez. La résolution du programmateur de threads sur Windows est d'environ 10 ms (Encore une fois, Vista et les autres systèmes d'exploitation changent et optimisent donc ce n'est pas exact) donc vous ne pouvez pas programmer une tranche de temps plus petite que cela. 100x10ms + le temps de rendu réel peut prendre 2 secondes entières pour faire un fondu entrant/sortant.

Le moyen de l'accélérer est de réduire le nombre de reprises. Plutôt que d'avancer +1 pour l'opacité, les étapes +5, +10, etc. Cela réduit le nombre total de re-tirages requis et entraînerait un fondu de forme en 100 ms à la place.

+0

Je ne pense pas que ce soit correct car je vois clairement une différence de vitesse de fondu entre TOGGLE_EFFECT_SPEED = 1 (sleep (10)) et TOGGLE_EFFECT_SPEED = 10 (sleep (1)). Et je vois aussi une différence entre ces deux avec une valeur entre 1 et 10. Et je ne pense pas que vous ayez ce que je voulais dire par "lent" parce que la valeur de vitesse n'a pas d'importance, le problème que j'ai est sans vitesse changement de valeur. –

+0

Vous ne verrez pas beaucoup de différence entre les valeurs de vitesse de 1 et 10 puisque le programmateur de threads ne dort pas pendant moins de 10 ms dans la plupart des cas - ils apparaîtront donc à la même vitesse. La chose qui aura le plus d'effet est la lenteur de la fenêtre et des fenêtres. –

0

Dans l'ensemble, je ne vois pas grand-chose qui justifierait un changement au moins au premier coup d'œil. Si vous constatez des goulots d'étranglement au niveau des performances, essayez d'utiliser Ants Profiler ou un outil de profilage de code similaire pour voir si vous pouvez identifier les sections lentes.

+0

Mais il n'y a pas de "sections lentes", la plupart du temps, le code fonctionne, il fait exactement ce qu'il est censé faire. D'autres fois, pas si souvent, ça s'estompe au ralenti ... –