How to show program is working?

I have a clock out and clock in routine that is potentially looping through a lot of records. I want be able to show that progress is being made.

The first this I did was to add an epi shape and set to visible and enabled while in the loop. That works to let you know it’s started and working, but if it takes long enough, it still can seem like the system is locked up when it’s not. So I would like to add a record counter that is counting as the loop is progressing, and then updating some type of control while that is happening.

I tried added a counter variable and a text box and tried to set the value of the text from within the loop, but it doesn’t update visibly while the loop is going on.

Is this something that is possible? Or do I just have to accept the shape enable/visible as good enough (which honestly it is for 95% of the time)

Progress bar should be updated by another thread as the UI will stop responding when it is doing the computing work. You can use timer to achieve this.

1 Like

Progress bar is the best option but, as @TobyLai mentioned, in order to do this right, you’d need to update it from a thread. Also, Epicor (surprisingly) does not have native support for a progressbar although it is a standard .NET compenent. To add it, you will have to create it in code and add it the form controls.

Other options for showing progress:
multi line textbox. Keep adding new line of activity at top.
status panel - oTrans.PushStatusText(“My Text”, true); But you absolutely MUST pop the status after the message is done ala oTran.PopStatus();

I generally do:

 oTrans.PushStatusText("My Text", true);
try
{
// my operation
}
finally
{
 oTrans.PopStatus();
}

I have noted it is horrible for performance though, not sure why.

1 Like

OK, Thanks for the suggestion. Bummer it’s such a pain. I was hoping for a simple fix. I don’t think adding the code for the threading is worth the work for the tiny bit training needed to make a static indicator be acceptable. And I don’t want to hurt performance if the PopStatus is going to make things take longer.

I think the box thing works ok. At least it’s some feedback.

Does the looping have nesting? Or one main pass.

If a single pass try breaking it up like:

// records in array recArray
int i;

txtPassCtr.Text = "Records Processing"
for (i=0; i<recArray.length && 100; i++){
    //do processing
    }
txtPassCtr.Text = "100 Records Processed"
for (; i<recArray.length && 200; i++){
    //do processing
    }
txtPassCtr.Text = "200 Records Processed"
for (; i<recArray.length && 300; i++){
    //do processing
    }
// repeat  above, with the last one being
for (; i<recArray.length; i++){
    //do processing
    }

You can leave the initialization field of the 2nd thru nth For loops blank. Just dont use a super local variable like

for (int i=0; i<recArray.length; i++){

It’s just one pass. A high number would be something like 20-30 records. But that could take 30 seconds or so. That’s an interesting ideas about breaking it up. I will keep that in my back pocket if anyone complains. (or I get bored.)

I managed to do something similar using the BackgroundWorker Class.

But I did it by having a Modal Form with FormBorderStyle set to None.

Such that user cannot press any button while the form shows the status. PM if you need source code.

1 Like

Here’s a quick hack (workaround is more appropriate). Add an update to a TextBox or a Label or something like you did then you can “force” the screen to refresh.
Simply call the following right after you update your textbox.

myTextBox.Text =$"Processed {count} Records So Far";
Application.DoEvents();

This will show visible progress like you want, note that this is a HAMMER… and although it will do what you want it is causing an interrupt in the process to allow Windows to raise events, paint UI, and everything else. The issue here is that it is not selective so it will allow anything to happen.
This is generally not a huge deal but keep that in mind, also it slows down your process overall because… well you are effectively pausing execution to allow some paint on the walls to dry…
You can even use it with a progress bar without using a thread. Just do ProgressBar.PerformStep(); Application.DoEvents() and the progress bar will “progress”

Direct from microsoft

Calling this method causes the current thread to be suspended while all waiting window messages are processed. If a message causes an event to be triggered, then other areas of your application code may execute. This can cause your application to exhibit unexpected behaviors that are difficult to debug. If you perform operations or computations that take a long time, it is often preferable to perform those operations on a new thread. For more information about asynchronous programming, see Asynchronous Programming Overview.

So handle with care! and @Bart_Elia is probably yelling at me for even telling you this exists… #SorryBart

4 Likes

I always use the statusbar and I train the users to look at the statusbar, because Epicor uses it in various other screens. You cuold even add a progress bar to the statusbar.

// you can also use using()
this.oTrans.PushStatusText("Printing...", true); // Enable Mouse Hourglass
this.oTrans.PopStatus();
2 Likes

@josecgomez I won’t be yelling at you. Unfortunately that was the tricks used back int he day. As this internet thing has taken off and the web, async, streaming is the norm these day, the old school client / server mentality looks kind of quaint. Still very functional and a heck of a lot easier to wrap your head around than async, threads, streaming, iterating stream memory to obtain data. It’s all trade offs in the tech industry.
The interesting value add challenge that exists is can a platform give you an easy on boarding experience while talking ‘native cloud’ mechanisms.

2 Likes

In Jose’s defense, teaching async programming to programmers is bad enough, C# dabblers heads would explode.

3 Likes

Exactly my point

Another option

Ice.Lib.Framework.FormFunctions.LoadSplash("Printing Labels...");
Ice.Lib.Framework.FormFunctions.LoadSplash("Printing Labels " + _showSomePcnt);
Ice.Lib.Framework.FormFunctions.CloseSplash(); // Later
3 Likes

await AsyncClassFromChris();

I’m sorry but your calling function wasnt flagged as async. Compile failed.

2 Likes