ImageAnimator InvalidOperationException

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Gonger96.

    ImageAnimator InvalidOperationException

    Tag,

    ich muss im Moment animierte Gifs darstellen bzw abspielen. Der ImageAnimator schien gut dafür, da ich ein Event schmeißen muss wenn der letzte Frame dargestellt wird und die Gifs beliebig oft abspielen möchte nicht nur looping. Ich hab mir schön ein Usercontrol dafür gemacht und auf die Form platziert, wenn ich aber jetzt die Größe der Form oder die Location oder irgendwas ändere wird mir eine InvalidOperationException geschmissen weils in einem anderen Thread läuft was ich nicht so ganz verstehe. Mit Invoke passiert garnichts oder es friert die Form weg. Ausserdem gibt GDI+ auch manchmal den Geist auf selbe Exception, nur mit dem Unterschied das diesmal das Image von einem anderen Thread gebraucht wird.
    Ich hoffe hier kann mir jemand sagen warum die Exceptions auftreten und wie ichs beheben kann.

    Grüße
    Das ist das AnimationControl
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class AnimControl
    2. Inherits Control
    3. Private animimg As Image = Nothing
    4. Public Event LastFrameDisplayed As EventHandler
    5. Public Event FirstFrameDisplayed As EventHandler
    6. Public Property Image As Image
    7. Get
    8. Return animimg
    9. End Get
    10. Set(value As Image)
    11. animimg = value
    12. If animimg IsNot Nothing Then
    13. Dim fd As New FrameDimension(Me.Image.FrameDimensionsList(0))
    14. frCount = Me.Image.GetFrameCount(fd) - 1
    15. Try
    16. If Me.Image.Size.Width <> 0 AndAlso Me.Image.Size.Height <> 0 Then
    17. Me.Invoke(Sub() Me.Size = Size.Add(Me.Image.Size, New Size(10, 10)))
    18. End If
    19. Catch : End Try
    20. End If
    21. Me.Invalidate()
    22. End Set
    23. End Property
    24. Public ReadOnly Property FrameCount As Integer
    25. Get
    26. Return frCount
    27. End Get
    28. End Property
    29. Private frCount As Integer = 0
    30. Private nTime As Integer
    31. Private CurrentFrame As Integer = 1
    32. Private IsPlaying As Boolean = False
    33. Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
    34. e.Graphics.FillRectangle(Brushes.Fuchsia, Me.ClientRectangle)
    35. If Me.Image IsNot Nothing Then
    36. e.Graphics.DrawImage(Me.Image, 0, 0)
    37. If FrameCount = 0 Then
    38. RaiseEvent LastFrameDisplayed(Me, EventArgs.Empty)
    39. End If
    40. End If
    41. MyBase.OnPaint(e)
    42. End Sub
    43. Public Sub Play(ByVal _nTimes As Integer)
    44. If Me.Image IsNot Nothing Then
    45. nTime = _nTimes
    46. ImageAnimator.Animate(Me.Image, AddressOf OnFrameChange)
    47. End If
    48. End Sub
    49. Private Sub OnFrameChange(ByVal sender As Object, ByVal e As EventArgs)
    50. If CurrentFrame = 1 Then
    51. RaiseEvent FirstFrameDisplayed(Nothing, EventArgs.Empty)
    52. End If
    53. If FrameCount * nTime = CurrentFrame Then
    54. ImageAnimator.UpdateFrames()
    55. Try
    56. If Me.Image.Size.Width <> 0 AndAlso Me.Image.Size.Height <> 0 Then
    57. Me.Invoke(Sub() Me.Size = Size.Add(Me.Image.Size, New Size(10, 10)))
    58. End If
    59. Catch : End Try
    60. Me.Invalidate()
    61. CurrentFrame = 1
    62. ImageAnimator.StopAnimate(Me.Image, AddressOf OnFrameChange)
    63. RaiseEvent LastFrameDisplayed(Me, New EventArgs)
    64. Else
    65. ImageAnimator.UpdateFrames()
    66. Try
    67. If Me.Image.Size.Width <> 0 AndAlso Me.Image.Size.Height <> 0 Then
    68. Me.Invoke(Sub() Me.Size = Size.Add(Me.Image.Size, New Size(10, 10)))
    69. End If
    70. Catch : End Try
    71. Me.Invalidate()
    72. CurrentFrame += 1
    73. End If
    74. End Sub
    75. Public Sub New()
    76. InitializeComponent()
    77. Me.DoubleBuffered = True
    78. End Sub
    79. End Class
    Zu 1.
    Das bringt mir nicht viel ich brauch sowieso nur die Image Property, da wäre erben von Picturebox unsinnig.

    Zu 2.
    Wird gemacht

    Und zu 3.
    Das ist auch eine Notlösung die nicht bleiben soll. Mir wird halt immer die Exception geschmissen und ich versteh nicht wieso

    Gonger96 schrieb:

    und ich versteh nicht wieso

    Das wirst du auch nie, wenn du sie immer "wegfängst".

    ---
    Laut MSDN funktioniert das so:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.Drawing
    3. Imports System.Windows.Forms
    4. Public Class animateImage
    5. Inherits Form
    6. 'Create a Bitmpap Object.
    7. Private animatedImage As New Bitmap("SampleAnimation.gif")
    8. Private currentlyAnimating As Boolean = False
    9. 'This method begins the animation.
    10. Public Sub AnimateImage()
    11. If Not currentlyAnimating Then
    12. 'Begin the animation only once.
    13. ImageAnimator.Animate(animatedImage, _
    14. New EventHandler(AddressOf Me.OnFrameChanged))
    15. currentlyAnimating = True
    16. End If
    17. End Sub
    18. Private Sub OnFrameChanged(ByVal o As Object, ByVal e As EventArgs)
    19. 'Force a call to the Paint event handler.
    20. Me.Invalidate()
    21. End Sub
    22. Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    23. 'Begin the animation.
    24. AnimateImage()
    25. 'Get the next frame ready for rendering.
    26. ImageAnimator.UpdateFrames()
    27. 'Draw the next frame in the animation.
    28. e.Graphics.DrawImage(Me.animatedImage, New Point(0, 0))
    29. End Sub
    30. Public Shared Sub Main()
    31. Application.Run(New AnimateImage)
    32. End Sub
    33. End Class


    Da musst du jetzt ein paar Zeilen umschreiben und dann hast du schon dein "Custom-Control".

    btw: Die PictureBox kann auch GIF's anzeigen.

    Edit:
    Wenn sich die Klasse mal im Reflektor anschaut, sieht man wo das Threading herkommt:
    Spoiler anzeigen

    Quellcode

    1. // <devdoc>
    2. /// Worker thread procedure which implements the main animation loop.
    3. /// NOTE: This is the ONLY code the worker thread executes, keeping it in one method helps better understand
    4. /// any synchronization issues.
    5. /// WARNING: Also, this is the only place where ImageInfo objects (not the contained image object) are modified,
    6. /// so no access synchronization is required to modify them.
    7. /// </devdoc>
    8. [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
    9. static void AnimateImages50ms() {
    10. Debug.Assert(imageInfoList != null, "Null images list");
    11. while( true ) {
    12. // Acquire reader-lock to access imageInfoList, elemens in the list can be modified w/o needing a writer-lock.
    13. // Observe that we don't need to check if the thread is waiting or a writer lock here since the thread this
    14. // method runs in never acquires a writer lock.
    15. rwImgListLock.AcquireReaderLock(Timeout.Infinite);
    16. try {
    17. for (int i=0;i < imageInfoList.Count; i++) {
    18. ImageInfo imageInfo = imageInfoList[i];
    19. // Frame delay is measured in 1/100ths of a second. This thread
    20. // sleeps for 50 ms = 5/100ths of a second between frame updates,
    21. // so we increase the frame delay count 5/100ths of a second
    22. // at a time.
    23. //
    24. imageInfo.FrameTimer += 5;
    25. if (imageInfo.FrameTimer >= imageInfo.FrameDelay(imageInfo.Frame)) {
    26. imageInfo.FrameTimer = 0;
    27. if (imageInfo.Frame + 1 < imageInfo.FrameCount) {
    28. imageInfo.Frame++;
    29. }
    30. else {
    31. imageInfo.Frame = 0;
    32. }
    33. if( imageInfo.FrameDirty ){
    34. anyFrameDirty = true;
    35. }
    36. }
    37. }
    38. }
    39. finally {
    40. rwImgListLock.ReleaseReaderLock();
    41. }
    42. Thread.Sleep(50);
    43. }
    44. }
    /nicht getestet

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „rotherford“ ()

    Das Image wird doch garnet ausgelagert. Außerdem tritt der Fehler ja nicht nur dort auf, auch auf der Parentform. Wenn ich die größe der Form ändere -> selbe Exception. Versteh ich überhaupt nicht ich hab z.B. eine Prozedur in der Klasse der Form diese wird durch einen Button gefeuert und darin wird nur die Größe der Form geändert und schon fliegt die Exception.

    @rotherford
    Den Code hab ich auch schon gesehen und zu meinem Zweck umgeschrieben, dass ist der den ich gepostet hab. Ich muss das Gif nur n-male abspielen nicht dauerhaft deswegen hilft die Picturebox nicht. Und ich muss ein Event werfen wenn das letzte Frame angezeigt wurde. Die Exception hab ich abgefangen um zu sehen obs überhaupt etwas anzeigt.