.net 2010 从自定义控件库中调用 DoEvents(是的,我想)

发布于 2024-09-24 11:10:31 字数 355 浏览 3 评论 0 原文

我有一个自定义控件的库。现在有一个看起来像面板的控件,当它打开时,我想为其垂直生长设置动画,如下所示:

For h As Single = 0 To finalHeight Step 0.5
    Me.Height = CInt(h)
    '  HERE I WANT TO CALL DoEvents'
Next
Me.Height = finalHeight 

如果我不在循环中调用 DoEvents,则不会显示动画,我只能获得最终高度,而无需沿途视觉反馈。

我可以从我的主 WinForm 项目中调用 DoEvents,但不能在库中调用。

我怎样才能做到这一点,而不被淹没在深水里?

I have a custom control's library. Now there's a control which looks like a panel, and when it opens up I want to animate its vertical growing like this:

For h As Single = 0 To finalHeight Step 0.5
    Me.Height = CInt(h)
    '  HERE I WANT TO CALL DoEvents'
Next
Me.Height = finalHeight 

If I don't call DoEvents in the loop then the animation is not shown, I only get the final height without a visual feedback along the way.

I can call DoEvents from inside my main WinForm project, but can't inside a library.

How can I do that, without drowning into the deep threads waters?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

甜柠檬 2024-10-01 11:10:31

抱歉,在这里完全不可能安全地使用 DoEvents。当用户在动画运行时关闭表单时,不会发生任何好事。它将导致程序因 ObjectDispose 异常而崩溃。要确保 DoEvents 安全,需要将表单的 Enabled 属性设置为 false,以便用户不会意外导致此类事故。控件无法合理地将表单的 Enabled 属性设置为 false,尤其是对于动画。

解决方法很简单,只需使用间隔为 15 毫秒的计时器即可。速度足够快,可以让动画看起来很流畅。您将在我的答案中找到执行此操作的示例代码 此帖子

Sorry, but it is completely impossible to make using DoEvents safe here. Nothing good is going to happen when the user closes the form while your animation is going. It will crash the program with an ObjectDisposed exception. Making DoEvents safe requires setting the form's Enabled property to false so that the user cannot accidentally cause mishaps like this. A control can not reasonable set the form's Enabled property to false, especially not for an animation.

The workaround is simple enough, just use a Timer with an Interval of 15 msec. Plenty fast enough to make the animation look smooth. You'll find sample code that does this in my answer in this thread.

浅笑依然 2024-10-01 11:10:31

也许您只是缺少对 System.Windows.Forms 的引用(或导入)? DoEventsApplication 的静态方法,因此您也应该能够从库中调用它。

Imports System.Windows.Forms

...

    Application.DoEvents()

(您似乎已经知道使用 DoEvents 是一件危险的事情,所以我将在这里跳过通常的讲座。)

Maybe you are just missing a reference to (or import of) System.Windows.Forms? DoEvents is a static method of Application, so you should be able to call it from a library as well.

Imports System.Windows.Forms

...

    Application.DoEvents()

(You already seem to know that using DoEvents is a dangerous thing, so I'll skip the usual lecture here.)

后eg是否自 2024-10-01 11:10:31

是的,您应该能够

System.Windows.Forms.Application.DoEvents()

在代码库中调用 From 。看来您明白 DoEvents 是一个坏主意,所以我不确定您为什么要调用它。我猜测您已将其放入 OnVisibleChanged 或 OnPaint 之类的覆盖中 - 如果是这种情况,您很可能不会得到您想要的结果,因为在这些操作期间控件刷新将被暂停。

您可能想要做的是创建一个单次滴答计时器,并在滴答时增加控件的高度 - 然后在达到最终高度时禁用计时器,或者如果没有达到则安排另一个滴答。或者,创建一个计时器并在每次滴答时将上面的循环放入其中。确保您了解 InvokeRequired 和跨线程调用,具体取决于您使用的计时器类型。

Yes, you should be able to call

System.Windows.Forms.Application.DoEvents()

From within your code library. It seems that you understand that DoEvents is a Bad Idea, so I'm not sure why you're calling it. I'm guessing that you have this put inside an override like OnVisibleChanged, or OnPaint - if this is the case you will most likely not get the results you are after, as control refreshing will be suspended during these operations.

What you probably want to do is create a single-tick timer, and on tick increase the height of the control -then disable the timer when finalheight is reached, or schedule another tick if not. Or, create a timer and put your above loop in it on each tick. Make sure you're aware of InvokeRequired and cross-thread calls depending on what type of timer you use.

李白 2024-10-01 11:10:31

无法重现。

刚刚在程序集中使用简单的设置 UserControl 进行了测试。

当 UC 在循环中调用 DoEvents() 时,MainForm 上的计时器会持续计时。

所以:再看看你的问题,它不是你想象的地方。

Failure to reproduce.

Just tested with a simple setup, UserControl in an assembly.

A timer on the MainForm keeps ticking when the UC calls DoEvents() in a loop.

So: Look again for your problem, it isn't where you think it is.

自演自醉 2024-10-01 11:10:31

在原始 for 循环中,将 Me.Refresh 放置在您要调用 doevents 的位置。

For h As Single = 0 To finalHeight Step 0.5
    Me.Height = CInt(h)
    Me.refresh
Next
Me.Height = finalHeight

In your original for loop, place Me.Refresh where you wanted to call the doevents.

For h As Single = 0 To finalHeight Step 0.5
    Me.Height = CInt(h)
    Me.refresh
Next
Me.Height = finalHeight
落墨 2024-10-01 11:10:31

这就是我发现的:计时器即使间隔很快,它也非常慢。我不知道为什么,但计时器的动画非常跳跃。简化的代码:

 rolex = New Timer()
 rolex.Interval = 150
 AddHandler rolex.Tick,
            Sub(sender As Object, e As EventArgs)

                Me.Height += 5

                If Me.Height < finalHeight Then Exit Sub

                rolex.Stop()
                rolex = Nothing

                Me.Height = finalHeight 
            End Sub
 rolex.Start()

没有计时器,我使用循环:

For i As Single = 0 To finalHeight Step 0.5
            Height = CInt(i)
            Application.DoEvents()
Next
Height = finalHeight 

它现在可以工作,但问题是动画速度太多取决于执行循环的机器。由于这个原因,我想使用计时器,但正如我所说,它太慢了。

有什么提示吗?

This is what I've found: the timer, even at fast intervals, it is really slow. I don't know why but the animation is very jumpy with the timer. Simplified code:

 rolex = New Timer()
 rolex.Interval = 150
 AddHandler rolex.Tick,
            Sub(sender As Object, e As EventArgs)

                Me.Height += 5

                If Me.Height < finalHeight Then Exit Sub

                rolex.Stop()
                rolex = Nothing

                Me.Height = finalHeight 
            End Sub
 rolex.Start()

Without the timer I use a loop:

For i As Single = 0 To finalHeight Step 0.5
            Height = CInt(i)
            Application.DoEvents()
Next
Height = finalHeight 

It works now, but the problem is that the animation speed too much depends on the machine where the loop is executed. For this reason I'd like to use a Timer, but as I said it's too slow.

Any hints?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文