How can I get rid of jerkiness in WinForms scrolling animation?


Problem:

I'm writing a simple control in C# that works like a picture box, except the image is constantly scrolling upwards (and re-appearing from the bottom). The animation effect is driven by a timer (System.Threading.Timer) which copies from the cached image (in two parts) to a hidden buffer, which is then drawn to the control's surface in its Paint event.

The problem is that this scrolling animation effect is slightly jerky when run at a high frame rate of 20+ frames per second (at lower frame rates the effect is too small to be perceived). I suspect that this jerkiness is because the animation is not synchronized in any way with my monitor's refresh rate, which means that each frame stays on the screen for a variable length of time instead of for exactly 25 milliseconds.

Is there any way I can get this animation to scroll smoothly?

You can download a sample application here (run it and click "start"), and the source code is here. It doesn't look horribly jerky, but if you look at it closely you can see the hiccups.

WARNING: this animation produces a pretty weird optical illusion effect which might make you a little sick. If you watch it for awhile and then turn it off, it will look as if your screen is stretching itself vertically.

UPDATE: as an experiment, I tried creating an AVI file with my scrolling bitmaps. The result was less jerky than my WinForms animation, but still unacceptable (and it still made me sick to my stomach to watch it for too long). I think I'm running into a fundamental problem of not being synced with the refresh rate, so I may have to stick to making people sick with my looks and personality.


Solution:

You would need to wait for a VSYNC before you draw the buffered image.

There is a CodeProject article that suggests using a multimedia timer and DirectX' method IDirectDraw::GetScanLine().

I'm quite sure you can use that method via Managed DirectX from C#.

EDIT:

After some more research and googling I come to the conclusion that drawing via GDI doesn't happen in realtime and even if you're drawing in the exact right moment it might actually happen too late and you will have tearing.

So, with GDI this seems not to be possible.

Recent Tips

  1. Update MySQL table column from another table entities
  2. Shoot fireball once in unity C#
  3. Adding a table of contents to a Microsoft Word Document using vbs
  4. Change locale in android app (onto Hindi)
  5. How do I stop selenium automation if 20% or 1st 20 test cases test methods are failed?
  6. Sharepoint with silverlight app
  7. What's the best way to write robots.txt for github pages using multiple repos?
  8. Biopython: Cant use .count() for biopython
  9. How can I find out the token balance of an address?
  10. ref value is undefined in vue (modal, textarea, $refs)
  11. Azure - HDInsight Hbase Data Insertion Failed
  12. SignalR overwriting OnConnected(), OnDisconnected()
  13. DatePickerDialog displays with two borders
  14. "type 'double' is not a subtype of type 'int' in type cast" error in flutter. What should i do?
  15. hiding the autocomplete list when user click outside the textbox is not working as expected
  16. JSF IceFaces basic problem with redisplaying input value
  17. How to validate material ui TextField in reactjs?
  18. Go and MongoDB connection won't work with panic log "no reachable server"
  19. WordPress Posts Pagination Not Working
  20. F# sprintf won't print in interactive console
  21. Spring Integration get FTP files recursively with outbound-gateway
  22. Jade mixins not getting working from external file
  23. Can not access defined exports from the webpack bundle?
  24. Completely new to Node.js - API Programming
  25. Formatting Compare-Object Ouput
  26. Add dynamically added textbox value from User Control to main form
  27. Create a ByteBuf in Netty 4.0
  28. Is it possible to do computation before super() in the constructor?
  29. Q-learning Updating Frequency
  30. Wrong reload order when using Gulp and browserSync