【问题标题】:Form opacity animation in C# with a BackgroundWorker在 C# 中使用 BackgroundWorker 形成不透明动画
【发布时间】:2010-10-27 09:14:15
【问题描述】:

在 BackgroundWorker 的帮助下,我为某种形式创建了不透明动画。

这种方法只有一个小问题,但我不明白问题出在哪里。动画速度是可配置的,即使速度值非常高,有时动画也会非常非常慢,出于某种奇怪的原因......

我说的“慢动画”并不是卡顿,动画其实很流畅,只是需要更多的时间来执行整个动画(从 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();
}

【问题讨论】:

    标签: c# multithreading animation backgroundworker opacity


    【解决方案1】:

    总的来说,至少乍一看,我认为没有什么值得改变的。如果您发现一些性能瓶颈,您可以尝试查看 Ants Profiler 或类似的代码分析工具,看看是否可以查明任何慢速部分。

    【讨论】:

    • 但是没有“缓慢的部分”,大多数时候,代码可以正常工作,它完全符合预期。在其他一些时候,不是那么频繁,它会以慢动作消失......
    【解决方案2】:

    每次更改窗体的不透明度时,Windows 都必须重绘它下面的所有窗口,即窗口本身,然后应用不透明度(Vista 这样做更快且缓冲)。由于您从 1...100 逐步完成每个不透明度状态,因此该过程必须完成 100 次。有时重绘你的窗口或它下面的窗口会很慢。

    无论你传递什么值,值 > 0 的 Thread.Sleep 方法都会从 0...~10ms 休眠。 Windows 上的线程调度程序计时器分辨率约为 10 毫秒(同样,Vista 和其他操作系统会更改和优化,因此并不准确),因此您无法安排比这更小的时间片。 100x10ms + 实际渲染的时间可能需要 2 整秒才能淡入/淡出。

    加快速度的方法是减少重绘次数。而不是为不透明度步进 +1,步进 +5、+10 等。这减少了所需的重新绘制的总数,并且会导致表单在 100 毫秒内褪色。

    【讨论】:

    • 我不认为这是正确的,因为我肯定看到 TOGGLE_EFFECT_SPEED = 1 (sleep(10)) 和 TOGGLE_EFFECT_SPEED = 10 (sleep(1)) 之间的渐变速度差异。而且我还看到这两者之间的差异,其值介于 1 和 10 之间。而且我认为您没有理解我所说的“慢”的意思,因为速度值无关紧要,我遇到的问题是在没有速度的情况下发生的值变化。
    • 您不会看到速度值 1 和 10 之间有太大差异,因为线程调度程序在大多数情况下不会休眠少于 10 毫秒 - 所以它们看起来是相同的速度.影响最大的是渲染窗口及其下方的窗口所花费的速度。
    猜你喜欢
    • 1970-01-01
    • 2010-09-25
    • 2018-05-27
    • 2011-03-24
    • 2019-06-16
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多