Solved

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

Posted on 2013-05-31
9
547 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
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

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

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
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…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

706 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

17 Experts available now in Live!

Get 1:1 Help Now