How to detect when a process has completed
jbsound
Posts: 35
This is a general question:
Since we can start a process such as CompareDatabases and assign a status handler to monitor the progress, how do I detect when a certain process has finished.
I want to explicitly break the different process down and show the status of each to the user. The way I do this is by calling sub-routines (this is VS.NET 2005 using VB.NET) which all have status handlers.
However, what I am finding is that individual threads are started that may not necessarily be done when control is handed back to the UI so it can react. Thus the question of how to detect when an individual process has finished.
Hope this makes sense!
JB
Since we can start a process such as CompareDatabases and assign a status handler to monitor the progress, how do I detect when a certain process has finished.
I want to explicitly break the different process down and show the status of each to the user. The way I do this is by calling sub-routines (this is VS.NET 2005 using VB.NET) which all have status handlers.
However, what I am finding is that individual threads are started that may not necessarily be done when control is handed back to the UI so it can react. Thus the question of how to detect when an individual process has finished.
Hope this makes sense!
JB
Comments
From the example code, it's when the StatusEventHandler's percentage is -1. That's when you can check the message property to see what stage the database comparison is at.
I did notice the -1 status percentage code sample and have also used it in my application to update the progress bar. However, the problem is that the percentag = -1 cannot be reliably used to determine when the overall process has finished.
-1 is thrown in multiple times during the process (for the Compare) to indicate the completion of the individual sub-processes.
I am looking for a way to determine when the overall Compare process has finished.
Thanks,
JB
The percentage from the status event handler returns a percentage complete for wehatever method you hook it to. For example, you put a ststuseventhandler on a database object and do a database.register, the percentage will be the percentage of registration complete. If you hook it to the CompareDatabases method, you get the percentage of comapredatabases complete.
If you want to show the percentage of completion for the whole comparison and synchronization, you'd need to divide your progress bar into chunks and use the percentage for each statuseventhandler to figure out how far along you are.
To compare and synchronize a pair of databases, you could have five distinct tasks, all returning their own percentage complete:
1. Register Database1 0-20%
2. Register Database2 21-40%
3. Compare Database1 to Database2 41-60%
4. Generate a script to synchronize database1 to database2 61-80%
5. Run the synchronization of database1 to database2 81-100%
So you'd need to set up a progress report like:
0%|
20%
40%
60%
80%
|100%
Reg DB1 |Reg DB2|Compare | Script | Sync
Then use the statuseventhandler's percentage to figure out how much of each stage has been completed. For instance if you're registering DB1, and that's 50% done, you're 50/100*20/100 percent done (10%).
This is probably not the most accurate, but the best way I can think of.
I understand your point. What I was talking about though is the fact that for a single process such as db.register, the e.Percentage is showing -1 when a new e.message shows up.
Here is an example of what I mean:
I did a debug.writeline(e.message + " : " + e.percentage) to show each value during the progress update. This is what it shows for the db.register call:
There is more, but you get the picture. If I would use the e.Percentage = -1 value as a means to determine when the db.Register process has finished, it would occur every time a new message shows up.
Hope this makes sense.
JB
Maybe I was being a bit vague. The Database.Register method will go 0-100% to show how far the registration has got. There are also sub-tasks inside db.Register as you point out. Whenever a new subtask such as 'reading comments' kicks off, e.Percentage goes to -1 and there is (almost always) an e.Message to pick up about which sub-task is running. If you don't care that the sub-tasks are changing, just don't update your progress bar when e.Percentage is -1.
The -1 value is just there to notify you that you've entered a new sub-part of whatever method is running.
I understood your comments and you were not being vague. Remember, the topic was "How to detect when a process has completed". It is clear to me now that I can't really use e.Percentage to determine when a process has finished.
I did get some other information about some of the other processes that get started, which do not always go all the way up to 100%.
In a couple of other topics, we discussed threads and keeping a watch on when a process finishes through that methodology.
I started this topic before I discovered that reliably I needed to work with individual threads and monitor them for completion in order to determine when a process has finished.
The online help documentation is a bit vague about all this and my suggestion would be to create a walkthrough with a threaded approach.
Thanks again for your time and help!
JB
I'm not really sure how you would monitor them for completion and I just need a nudge in the right direction if possible.
Thanks in advance...
I'm sorry but I don't completely understand what you're trying to achieve.
What is considered a main process, and why would you need to use multiple threads to monitor the progress?
When I run the RegisterForDataCompare method on a database for example, this I would consider the main process. As mentioned above, there are sub-processes to this i.e. Reading Users and Reading Tables, which have to complete before the whole Registration method completes.
Basically, I have a sub that I call before and after the RegisterForDataCompare which writes an entry to a RichTextBox on a form informing the user what it's about to do and whether it succeeded or not. I want to also show the messages from the StatusEventHandler so the user gets a lot of information back.
The problem I have is that the application does not refresh so instead of the user actually getting live status updates; they just get nothing until it's finished... and then the lot. So I thought, right, I'll put a My.Application.DoEvents in StatusEventHandler so the app can catch up, but the problem with that is, that the lines in the caller sub fire before the messages from the StatusEventHandler.
It's a bit hard to explain. It's actually something I tried to do in a project back in 2006, but have now had to revisit. I don't know if you keep all your old emails, but we had a conversation about it via email. You sent me the first email on Wed 8th November 2006 telling me to try and Invoke my StatusEventHandler from a dummy sub in my Form. I don't know too much about it, but I thought this meant is was then running on another thread. No?
If you don't have the email still I can resend it to refresh your memory if you like and then perhaps we can post something up here for the benefit of anyone else trying to do it.
In conclusion, I would just like an easy way to find out when the RegisterForDataCompare method has finished, that way I can do a loop and wait for it until it has and still get all the messages from the StatusEventHandler beforehand.
Thanks again,
Rawden.
...and presumably you want to RegisterForDataCompare in a thread other than the main window's thread... otherwise you could just call RegisterForDataCompare synchronously in the main form's class. But I could see why you wouldn't want to do this as it would block user input on the main form, correct?
In order to see when a method (such as RegisterForDataCompare) has completed, I think your best bet would be a custom asynchronous method. This will kick off a method asynchronously, then run the method of your choice in the calling thread when the async method is complete. If I remember right, you program in the VB language so I made a quick and dirty example (you will probably need to plumb in some proper exception handling for when something goes wrong...). Imagine you have already created a Winforms project with a button (button1) and a TextBox (TextBox1) so that when the button is clicked, a Data Compare is done between WidgetDev and WidgetLive databases. For brevity, all that is done in the example is redister for data compare. You can enhance the DatabaseServices to support more Toolkit methods and add more classes that implement IAsyncResult to handle these methods.
Hopefully you didn't think this would be easy! :-)
Would I still leave the StatusEventHandler going to the form, or can I take it back to the same class now?
I tried it as it was (with the dummy sub) and the items were still in the wrong order and I also tried it just as dbSource.Status = New StatusEventHandler(AddressOf Me.StatusCallback) and that didn't seem to populate the textbox with any of the 'Minor' processes (i.e. Reading Users). I set a breakpoint in the StatusCallback and they were being passed, but some reason they were not updated on the textbox.
Did you get a StatusCallback working fine on your sample app?
I'll see if I can plumb in the StatusEventHandler and come up with another example.
I orignally had it wrapped up in a class. Would I need to change much on your code to get it working in a class. It's moaning about no InvokeRequired method etc.
InvokeRequired should be a property of your Windows Form -- it's the thing that prevents other threads from being able to update controls on the form. It should be built-in to the Form class, so I don't know why you would get a complaint that it's not implemented.
I have just two more questions:
1. What do I need to do to add in the other methods? (I am playing around with this now, so I may actually crack it with my limited knowledge anyway.)
and
2. If I want to give the user the ability to cancel the compare at any stage (now that you have sorted the user input side of things so they can actually press the button) would this cause problems if I were to call the CancelOperation methods?
I'm slowly going through this asynchronous stuff and getting my head round it. :shock:
Can you tell me if (and where) the Registration.Finish() function is called from. I can't seem to see a reference to it.
(or rather the DatabaseServices.EndRegisterForDataCompare function actually.)
Thanks,
Rawden.
You're right; the Finish methods never seem to run. Plus the DatabaseServices class seems to be entirely redundant. Here is an updated version that seems to be doing the job... The form has since grown a progress bar and a label; hopefully this doesn't introduce too much confusion...
I've changed the databases and session objects etc. to go in ByRef and that way when I cancel the operation on the form, they cancel in the Async methods as well. I can then also do away with the AsyncDatabaseMethod variables and the Finish functions.
:lol: