1

BackgroundWorkerの助けを借りて、あるフォームの不透明度アニメーションを作成しました。

このアプローチには小さな問題が1つだけありますが、どこに問題があるのか​​理解できません。アニメーションの速度は構成可能であり、速度の値が非常に高い場合でも、奇妙な理由でアニメーションが非常に遅い場合があります...

私が話している「遅いアニメーション」は、途切れることはなく、アニメーションは実際には非常にスムーズで、アニメーション全体を実行するのに時間がかかるだけです(0%から100%、またはその逆)。これは時々起こるだけです。コンピュータが他のやや集中的なバックグラウンドアクションを実行しているときに発生するようです(確かではありません)。

もちろんそれを修正する必要がありますが、とにかくこのコードを改善するかどうか、または別の方法やより良い方法でそれを行うかどうかも知りたいです。

これが私のコードです:

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

2 に答える 2

1

フォームの不透明度を変更するたびに、Windowsはその下にあるすべてのウィンドウ、ウィンドウ自体を再描画してから不透明度を適用する必要があります(Vistaはこれをはるかに高速に行い、バッファリングします)。各不透明度の状態を1...100からステップスルーしているため、このプロセスは100回完了する必要があります。ウィンドウまたはその下のウィンドウの再描画が遅くなることがあります。

値が0より大きいThread.Sleepメソッドは、どの値を渡しても0 ...〜10msからスリープします。Windowsのスレッドスケジューラタイマーの解像度は約10msです(ここでも、Vistaやその他のOSは変更されて最適化されるため、正確ではありません)。そのため、それよりも小さいタイムスライスをスケジュールすることはできません。100x10ms +実際にレンダリングする時間は、フェードイン/フェードアウトするのに2秒かかる場合があります。

それをスピードアップする方法は、再描画の数を減らすことです。不透明度を+1するのではなく、+ 5、+ 10などをステップします。これにより、必要な再描画の総数が減り、代わりに100ミリ秒でフォームがフェードします。

于 2009-05-19T19:22:29.320 に答える
0

全体として、少なくとも一見しただけで変更が必要になることはあまりありません。パフォーマンスのボトルネックが発生している場合は、Ants Profilerまたは同様のコードプロファイリングツールを調べて、遅いセクションを特定できるかどうかを確認してください。

于 2009-05-19T18:26:18.797 に答える