In the previous articles (see here) we discussed how to build standard progress dialogue in C/AL language. However, as mentioned at the end of the article, this way is definitely not applicable to a production environment due to the performance issues. In this article, we will look at how to build dialogues more efficiently with lower (and usually acceptable) impact on performance…
Let’s look at our example from the previous article.
Local variables: DialogVar (Dialog) MyRecord (Record of any table) -------------------- Code: DialogVar.OPEN('My own text'); REPEAT DialogVar.UPDATE(); UNTIL MyRecord.NEXT < 1 DialogVar.CLOSE();
What are the biggest drawbacks of this design? Definitely, one of them is performance. However, usually, the user needs (or want) to see more information about the progress. Using this code, the user sees only static text “My own text” and has no information about the current state of progress. Let’s look at both issues in more detail.
To show more details about current progress, we have two possible ways. One of them is to show custom string values (for example, document number, customer number, …). Another possibility is to show progress in percentage to indicate how many cycles (in comparison to the total number of cycles) has been done/remains.
To specify what should be shown and how the progress should be displayed, we use placeholders. Placeholders are special characters that are placed in the text we want to show in the position, where the value should be shown. The number of placeholder characters specifies the length of the variable field.
We have two types of placeholders. For custom string values, we use “#”, for percentage, we use “@”. In one text label, more values can be shown. To achieve it, the placeholders must be indexed. The index must be defined as a second character just after the first placeholder.
- First variable field that shows custom strings.
- Second variable field that shows percentage progress dialogue.
- The percentages are defined as values 0 to 9999. That means that to display a percentage progress indicator properly, we need to normalize the value to this range.
Once we have text with placeholders defined, we can change our UPDATE function usage and add parameters. As we discussed in the first article, the first parameter is the index of placeholder and the second one value. Let’s look at the example below.
Local variables: DialogVar (Dialog) MyRecord (Record of any table) Counter (Integer) TotalCounter (Integer) -------------------- Code: Counter := 1; TotalCounter := MyRecord.COUNT(); DialogVar.OPEN('Current doc. no #1####### \ Current progress @2@@@@@@'); REPEAT DialogVar.UPDATE(1, MyRecord."Document No."); DialogVar.UPDATE(2, (Counter / TotalCounter * 10000) DIV 1); Counter += 1; UNTIL MyRecord.NEXT < 1 DialogVar.CLOSE();
As mentioned above, the value of the percentage indicator has to be normalized to range 0 to 9999. In the example above, we did it using “(Counter / TotalCounter * 10000) DIV 1”. This statement calculates how many cycles have been done (in per cent), multiple it by 10000 to normalize it within 0-9999 and cast it as an integer value.
The biggest issue from performance point of view is the complexity of UPDATE method. Even if the indicator should shown the same value, the system still needs to update the UI. The update of UI makes UI responsible (so the user does not see unresponding application) but it is not necessary to update the dialog each time the function is run.
So, we have two ways how to solve it. We can update the dialog only each Xth run (for example every 100th run). I used it in the past, however, I found that it is not ideal solution. The biggest drawback is that for tasks where one run took a longer time, the application can still be unresponding.
Better approach, in my opinion, is to update UI every second. See example below.
Local variables: DialogVar (Dialog) MyRecord (Record of any table) Counter (Integer) TotalCounter (Integer) LastUpdateAt (DateTime) -------------------- Code: Counter := 1; TotalCounter := MyRecord.COUNT(); DialogVar.OPEN('Current doc. no #1####### \ Current progress @2@@@@@@'); REPEAT IF LastUpdateAt < (CURRENTDATETIME() - 1000) THEN BEGIN LastUpdateAt := CURRENTDATETIME(); DialogVar.UPDATE(1, MyRecord."Document No."); DialogVar.UPDATE(2, (Counter / TotalCounter * 10000) DIV 1); END; Counter += 1; UNTIL MyRecord.NEXT < 1 DialogVar.CLOSE();