使用 BackgroundWorker 在 C# 中形成不透明动画
在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();
}
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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
每次更改窗体的不透明度时,Windows 都必须重新绘制其下方的所有窗口以及窗口本身,然后应用不透明度(Vista 执行此操作的速度要快得多,并且有缓冲)。 由于您要逐步执行从 1...100 的每个不透明度状态,因此该过程必须完成 100 次。 有时重绘窗口或其下方的窗口会很慢。
Thread.Sleep 方法的值 > > 无论您传递什么值,0 都会从 0...~10ms 休眠。 Windows 上的线程调度程序计时器分辨率约为 10 毫秒(同样,Vista 和其他操作系统会更改和优化,因此它并不准确),因此您无法安排比该值更小的时间片。 100x10ms + 实际渲染时间可能需要 2 秒才能淡入/淡出。
加快速度的方法是减少重新绘制的次数。 不是将不透明度步进 +1,而是步进 +5、+10 等。这会减少所需重新绘制的总数,并会导致表单在 100 毫秒内消失。
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.
总的来说,至少乍一看,我没有看到太多值得改变的地方。 如果您发现一些性能瓶颈,您可以尝试查看 Ants Profiler 或类似的代码分析工具,看看是否可以查明任何缓慢的部分。
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.