Solved

Animated Gif Starts But GUI Calls to Images, Progressbar Raise "Single-Apartment" Exception

Posted on 2013-05-31
9
558 Views
Last Modified: 2013-06-01
I would like to show an animated gif (WaitGif) while running heavy work in a class.   Below is the function that I call (waitgifimg), which starts the workers (loads waitgif, then starts a class constructor).  The parameters in the function waitgifimg, "Left" and "Top" are where I want the Gif on Form1.  (WaitGif is the animated gif.)

The function call successfully spawns the animated gif and the constructor and object are instantiated and work starts, but later in the instantiated object, a progressbar update and image drawing attempt result in a "Single-Apartment" exception.   Should I reverse the gif and work order in the worker routines so that Form1 can be accessible?  I looked at the apartment-state exception and its more complex.  


'In my code
 waitgifimg(Left, Top)
       
'In Form1 Class somewhere
AddHandler wrkDeploy.DoWork, AddressOf wrk_DoWork
AddHandler wrkDeploy.RunWorkerCompleted, AddressOf wrk_RunWorkerCompleted

Private wrkDeploy As New BackgroundWorker()
 
Private Sub wrk_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        ' Hide Gif and start normal UI process again
          WaitGif.Visible = False
End Sub

Private Sub wrk_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        ' Do all heavy work here
         Dim myobj as New MyClass()
End Sub

Private Sub waitgifimg(ByVal left As Integer, ByVal top As Integer)
        ' Show GIF and disable whatever you need to
         WaitGif.left = left
         WaitgGif.top = top
         WaitGif.Visible = True
         wrkDeploy.RunWorkerAsync()
End Sub

Open in new window

0
Comment
Question by:lep1
  • 5
  • 4
9 Comments
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 39211525
"but later in the instantiated object, a progressbar update and image drawing attempt result in a "Single-Apartment" exception."

How are you attempting to update the GUI from your class?  You should use the ReportProgress() method of your BackgroundWorker() which fires the ProgressChanged() event.
0
 

Author Comment

by:lep1
ID: 39211627
Previously, when the object was running, the picturebox and progressbar worked fine, as these calls were proceeded with "Form1.ProgressBar1.Value =..."

FYI, I also implemented invoking an asynch worker and callback, but when the gif loaded  and work started, the drain on resources froze the animation by the gif.   if the class was a subroutine instead it could be threaded, then this approach would work (as I have done this before -- that is running a sub via threading leaves the GUI alone and you can continue to do other work.

What would be good is to be able to update any control on Form1, using a global thread that could aborted.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 39211688
Are you doing "Form1.ProgressBar1.Value =..." from in your class?  Still don't have enough details to give you a good answer.

Possible approaches:

(1) Pass a reference to your BackgroundWorker() into your class and then use the ReportProgress() method I mentioned earlier.  You will need to wire up the ProgressChanged() event and set WorkerReportsProgress() to True.

(2) Make your class raise custom "progress" events that the main form subscribes to.  The handlers for these events would then in turn call ReportProgress() against the BackgroundWorker()...see (1).

(3) Pass a reference to the Form into your class and then use Invoke() and a Delegate to properly update the form from a different thread.
0
 

Author Comment

by:lep1
ID: 39211901
I already have a lot of #3 type delegates and invokes in the objects, which add nodes and images to a treenode.  When I tried using waitgif.visible=true in the node tree update routine (fired by a delegate from within instantiated objects) the gif froze at run-time.
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 

Author Comment

by:lep1
ID: 39211910
Can I start a thread within an instantiated object to call a routine in the object to perform the heavy calcutions?  This would keep the work away from the GUI.
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 39211952
"Can I start a thread within an instantiated object to call a routine in the object to perform the heavy calcutions?"

You sure can.

The gif freezing is an indicator that you somehow ended up either doing the heavy work in the main UI thread, or simply that your main UI thread is busy handling too many updates.

Be careful what you Invoke().  You should only invoke the small line or two that actually updates the GUI...don't invoke the entire routine.
0
 

Author Comment

by:lep1
ID: 39212252
Thanks Idle_Mind!  If you spawn a thread to a method within an object (constructor), I believe process flow would go right through the object, exit, causing the object to be a target for GC. After this, would it be fair to assume that there would be no connection between the dead object and the thread that was spawned -- shouldn't be(?)

Still not done.   Just realized that if I instantiate multiple objects, each of which spawn a thread to perform the work in that object, then I will need to spawn a new picturebox if I want an animated gif near the movable control (on which the user right clicked to select "Run" -- based on the contextmenustrip) then I will need to thread the newly created picture box?  

I could easily create a picturebox dynamically via invoke for each threaded object, but how would you kill a specific picturebox (visible=false) at the end of a method (spawned via a thread) from a dead object.   Can I include a picturebox name or tag in an invoke from a method to kill a specific picturebox on Form1?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 39212882
I don't see how starting a thread in the constructor would cause the object to be a candidate for garbage collection.  You would still have a reference to the class itself since you created it.

For the second issue, it sounds like you should look at developing a UserControl that encapsulates all the associated controls into one unit.  Then you can create different instances at design-time or dynamically at run-time.
0
 

Author Comment

by:lep1
ID: 39212953
I use usercontrols a lot. Let me make a new question about about usercontrols vs creating picture boxes dynamically.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In this video I am going to show you how to back up and restore Office 365 mailboxes using CodeTwo Backup for Office 365. Learn more about the tool used in this video here: http://www.codetwo.com/backup-for-office-365/ (http://www.codetwo.com/ba…

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now