代码之家  ›  专栏  ›  技术社区  ›  vulkanino

.NET 2010从自定义控件库内部调用DoEvents(是的,我希望如此)

  •  0
  • vulkanino  · 技术社区  · 15 年前

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

    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,但不能在库中调用。

    我怎么能做到,而不淹没在深丝线的水中?

    6 回复  |  直到 13 年前
        1
  •  3
  •   Hans Passant    15 年前

    对不起,但是在这里使用DoEvents是完全不可能的。当用户在动画运行时关闭窗体时,不会发生什么好事。它将使程序崩溃,并出现一个ObjectDisposed异常。使doEvents安全需要将窗体的enabled属性设置为false,这样用户就不会意外地导致类似这样的事故。控件无法合理设置 窗体的 启用属性为false,特别是对于动画。

    解决方法非常简单,只需使用间隔为15毫秒的计时器。足够快使动画看起来平滑。您将在我的答案中找到这样做的示例代码 this thread .

        2
  •  2
  •   Heinzi    15 年前

    也许您只是缺少了对(或导入)的引用 System.Windows.Forms ? DoEvents 是一种静态方法 Application ,所以您也应该能够从库中调用它。

    Imports System.Windows.Forms
    
    ...
    
        Application.DoEvents()
    

    (你似乎已经知道使用 事件发生 这是件危险的事情,所以我将跳过通常的讲座。)

        3
  •  2
  •   Philip Rieck    15 年前

    是的,你应该可以打电话

    System.Windows.Forms.Application.DoEvents()
    

    从代码库中。你似乎明白“做事情”是个坏主意,所以我不知道你为什么这么称呼它。我猜你已经把这个放在了一个覆盖中,比如onVisibleChanged或者onPaint——如果是这样的话,你很可能不会得到你想要的结果,因为在这些操作中控制刷新将被暂停。

    您可能想要做的是创建一个单勾选计时器,并在勾选时增加控件的高度-然后在达到最终权重时禁用计时器,或者如果没有,则计划另一个勾选。或者,创建一个计时器,并将上面的循环放到每个标记上。确保你知道 InvokeRequired 根据您使用的计时器类型,跨线程调用。

        4
  •  1
  •   Henk Holterman    15 年前

    无法复制。

    刚刚测试了一个简单的设置,用户控件在一个程序集中。

    当UC在一个循环中调用doEvents()时,主窗体上的计时器会一直在计时。

    所以:再看看你的问题,它不是你想的那样。

        5
  •  0
  •   Toon Krijthe    13 年前

    在原始for循环中,放置 Me.Refresh 你想打电话给DoEvents的地方。

    For h As Single = 0 To finalHeight Step 0.5
        Me.Height = CInt(h)
        Me.refresh
    Next
    Me.Height = finalHeight
    
        6
  •  -1
  •   vulkanino    15 年前

    这就是我所发现的:计时器,即使是在很快的时间间隔内,也很慢。我不知道为什么,但动画中的定时器非常紧张。简化代码:

     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 
    

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

    有什么暗示吗?