How to update silverlight UI while processing - silverlight

I went through several examples posted online but I cant answer my question.
I have my 'p' variable that is being increased by 1 in the for loop. I want the UI to display the progress of calculation (to show how 'p' is increasing from 0 to 1000000). I do the calculation on the separate thread and the I call dispatcher to update the ResultBox in UI. Example:
int p=0;
...
private void GO(object sender, System.Windows.RoutedEventArgs e)
{
new Thread(delegate()
{
DoWork();
}).Start();
}
void DoWork()
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 10000; j++)
{
p++;
this.Dispatcher.BeginInvoke(delegate { ResultBox.Text = p.ToString(); });
}
}
}
For some reason this doesn't work. However when I put Thread.Sleep(1) just before this.Dispatcher... it works as intended. Does it mean that the UI update (Dispatcher) is called too frequently therefore it freezes?
Is there any other way to do it?
Thank you

Why not bind a property to your TextBox and the update the property value instead of poking at the textbox directly?

Yes only doing p++ in your loop will not take much of time and inside silverlight, Dispatcher is nothing but a simple queue with delegates, and before silverlight can even update and process its UI, you are pumping too many values on the queue. Imagin what will happen if you keep on adding queue way to faster then the queue is dequeued, then eventually it will hit max limit as well. And eventually it will just stop. If your p++ is replaced with more time consuming task, then you may get good result.
You must know that our eye usually can see only updates of 30 fps, more then 30 updates per second will not be of any use at all, I will suggest your view update should be reduced to max 10 updates per second for best performance.
And for showing progress, I think 1 update per second is also enough. First always display updates very slowly, like
void DoWork()
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 10000; j++)
{
p++;
if((p % 1000)==0){
this.Dispatcher.BeginInvoke(delegate
{ ResultBox.Text = p.ToString(); });
}
}
}
}
Now you can increaes/decrease 1000 to some suitable multipler of 10 to adjust your visual update.

Related

How to force WinForms into ->Show()

The following code fragment uses a WinForms instance with a button to start a countdown and a textbox to follow it. To simulate a calculation process of any duration, a Fibonacci number is calculated within each count. Regardless of how much time the form element has to react, the countdown is not displayed. Only when everything is finished, the result alone is displayed.
Put simply, I wonder where the event handler gets the idea that it has to wait for the whole process to finish. The calculation has nothing to do with the form element. Actually, it would make more sense to get the calculation 'politely' wait for the UI element, if it lacks the time to display the desired intermediate steps and thus pauses for a moment. Is there any other methode than ->Show() to force a Form window refresh or is this waiting direction perhaps 'default' and can be optionally reversed?
main.cpp
---
form1.h / form1.cpp
---
// sub.cpp ...
void App1::Form1::button1_Click(System::Object^ sender, System::EventArgs^ e) {
unsigned res,dur=40;
System::String^ s;
Form^ fo = Form::ActiveForm;
for(int i = 10;i >= 0;i--) {
res = fibo(dur); // Loop: dur 5|80 ~ instantan|endless
s = i.ToString();
fo->Controls[1]->Text = s;
if(1) fo->Show(); } /// 0|1 no difference ??
s = res.ToString();
fo->Controls[1]->Text = s; }
unsigned fibo(unsigned n) { // time consuming calculation placeholder
long result = 0;
if (n == 0) return 0;
else if (n < 2) result = 1;
else result = fibo(n - 1) + fibo(n - 2);
return result; }
On my way to this question I found articles dealing with 'backgraoundWorker', hence the Fibonacci numbers. But what if the 100% is not known? This complicity all just to show that the process is still alive seems to me a bit break a fly on the wheel. Isn't that done more simple?

How to add time delay to process more than 15 second in Actionscript?

So I have the following script to get all combination of an array :
'''
var value = new Array(40)
for (var i=0;i<value.length;i++){
value[i]=i;
}
var comb_list = getAllComb(value,24);
trace(comb_list)
function getAllComb(values:Array, r:int):Array{
var n = values.length;
var result = new Array();
var a = new Array(r);
// initialize first combination
for (var i = 0; i < r; i++) {
a[i] = i;
}
i = r - 1; // Index to keep track of maximum unsaturated element in array
// a[0] can only be n-r+1 exactly once - our termination condition!
var count = 0;
while (a[0] < n - r + 1) {
// If outer elements are saturated, keep decrementing i till you find unsaturated element
while (i > 0 && a[i] == n - r + i) {
i--;
}
result.push(a.slice())// pseudo-code to print array as space separated numbers
count++;
a[i]++;
// Reset each outer element to prev element + 1
while (i < r - 1) {
a[i + 1] = a[i] + 1;
i++;
}
}
return result;
}
'''
Running above script will get me:
Error: Error #1502: A script has executed for longer than the default timeout period of 15 seconds.
How to add time delay each 14 seconds passed so that I can run the script? So, after 14 seconds passed, the program will wait for 50ms then continue.
Any help appreciated.
So, there's a simple (well, pretty much so) and working example of how to separate the heavy calculations part from the main thread so the main thread (which also handles UI and external events like user input) would run smoothly, while being able to read the progress and the results of the heavy calculations going under the hood. It also is in a form of a single class, this could be a bit confusing (until you understand how it works) but still easy to handle and modify.
Although the background AVM goes along the same execution flow (code execution > graphics rendering > code execution > graphics rendering > and so on), there are no graphics to render hence there's no need to anyhow limit the code execution time. As a result Worker thread is not a subject to 15 seconds limit, which, somehow, solves the problem.
package
{
import flash.events.Event;
import flash.display.Sprite;
import flash.utils.ByteArray;
import flash.concurrent.Mutex;
import flash.system.Worker;
import flash.system.WorkerDomain;
public class MultiThreading extends Sprite
{
// These variables are needed by both the main and
// subservient threads and will actually point to
// the very same object instances, though from
// the different sides of this application.
private var B:ByteArray;
private var W:Worker;
private var M:Mutex;
// Constructor method.
public function MultiThreading()
{
super();
// This property is 'true' for the main thread
// and 'false' for any Worker instance created.
if (Worker.current.isPrimordial)
{
prepareProgress();
prepareThread();
startMain();
}
else
{
startWorker();
}
}
// *** THE MAIN THREAD *** //
private var P:Sprite;
private var F:Sprite;
// Prepares the progress bar graphics.
private function prepareProgress():void
{
F = new Sprite;
P = new Sprite;
P.graphics.beginFill(0x0000FF);
P.graphics.drawRect(0, 0, 100, 10);
P.graphics.endFill();
P.scaleX = 0;
F.graphics.lineStyle(0, 0x000000);
F.graphics.drawRect(0, 0, 100, 10);
F.x = 10;
F.y = 10;
P.x = 10;
P.y = 10;
addChild(P);
addChild(F);
}
// Prepares the subservient thread and shares
// the ByteArray (the way to pass messages)
// and the Mutex (the way to access the shared
// resources in a multi-thread environment
// without stepping on each others' toes).
private function prepareThread():void
{
M = new Mutex;
B = new ByteArray;
B.shareable = true;
B.writeObject(incomingMessage);
W = WorkerDomain.current.createWorker(loaderInfo.bytes);
W.setSharedProperty("message", B);
W.setSharedProperty("lock", M);
}
// Starts listening to what the background thread has to say
// and also starts the background thread itself.
private function startMain():void
{
addEventListener(Event.ENTER_FRAME, onFrame);
W.start();
}
private var incomingMessage:Object = {ready:0, total:100};
private function onFrame(e:Event):void
{
// This method runs only 20-25 times a second.
// We need to set a lock on the Mutex in order
// to read the shared data without any risks
// of colliding with the thread writing the
// same data at the same moment of time.
M.lock();
B.position = 0;
incomingMessage = B.readObject();
M.unlock();
// Display the current data.
P.scaleX = incomingMessage.ready / incomingMessage.total;
P.alpha = 1 - 0.5 * P.scaleX;
// Kill the thread if it signalled it is done calculating.
if (incomingMessage.terminate)
{
removeEventListener(Event.ENTER_FRAME, onFrame);
W.terminate();
B.clear();
B = null;
M = null;
W = null;
}
}
// *** THE BACKGROUND WORKER PART *** //
// I will use the same W, M and B variables to refer
// the same Worker, Mutex and ByteArray respectively,
// but you must keep in mind that this part of the code
// runs on a different virtual machine, so it is the
// different class instance thus its fields are not
// the same quite as well.
// Initialization.
private function startWorker():void
{
W = Worker.current;
M = W.getSharedProperty("lock");
B = W.getSharedProperty("message");
// Before starting the heavy calculations loop
// we need to release the main thread which is
// presently on W.start() instruction. I tried
// without it and it gives a huuuge lag before
// actually proceeding to intended work.
addEventListener(Event.ENTER_FRAME, onWorking);
}
private function onWorking(e:Event):void
{
removeEventListener(Event.ENTER_FRAME, onWorking);
var aMax:int = 10000000;
// Very very long loop which might run
// over the course of several seconds.
for (var i:int = 0; i < aMax; i++)
{
// This subservient thread does not actually need to
// write its status every single loop, so lets don't
// explicitly lock the shared resources for they
// might be in use by the main thread.
if (M.tryLock())
{
B.position = 0;
B.writeObject({ready:i, total:aMax});
M.unlock();
}
}
// Let's notify the main thread that
// the calculations are finally done.
M.lock();
B.position = 0;
B.writeObject({ready:i, total:aMax, terminate:true});
M.unlock();
// Release the used variables and prepare to be terminated.
M = null;
B = null;
W = null;
}
}
}
The error is not related to your script needing a time delay, the problem is your while loops are making your script unresponsive for more than 15 seconds, triggering the script timeout error. Action Script only allows 15 seconds for your script to execute.
Your first while loop looks problematic, and I'm unclear how the value of a[0] changes to end the loop. Add a break to the loop or make sure the condition changes to allow the loop to end, and you should solve your problem. You can also considering adding continue statements to your embedded while loops if they are only supposed to run one time after they find an unsaturated value.
Personally, since you are using ActionScript, I'd suggest using objects and listeners for value changes instead of iterating over arrays checking for changes.
You could also add a manual timeout for your while loop, but would need to include logic for it to pick up where it left off.
//Set timer to 14 seconds
timeout = getTimer() + 14000;
while(true && timeout > getTimer()){
trace("No Error");
}
If you were used Adobe Animate (Flash), you could change the "Script Time Limit" from Publish setting page.

Index was out of range using 2 picturebox lists

I'm making a little game involving 2 picturebox lists and collision detection.
What I have is:
List<PictureBox> spells = new List<PictureBox>();
List<PictureBox> enemy = new List<PictureBox>();
I then use functions to dynamically create new pictureboxes for each of these lists with their appropriate images.
Then the collision detection using a timer:
private void timer1_Tick(object sender, EventArgs e)
{for (int i = 0; i <= spells.Count-1 ; i++)
{
for (int j = 0; j <= enemy.Count-1 ; j++)
{
if (spells[i].Top == enemy[j].Top &&
spells[i].Right > enemy[j].Left &&
spells[i].Tag.ToString()=="Fire" && enemy[j].Tag.ToString()=="Frostenemy")
{
Controls.Remove(enemy[j]);
enemy[j].Dispose();
enemy.Remove(enemy[j]);
Controls.Remove(spells[i]);
spells[i].Dispose();
spells.Remove(spells[i]);
}
And repeat for the other types of picutreboxes. This works OK if there are less than 3 pictureboxes from the "enemy" list, which are generated by another timer, but as soon as there are more than 3 on the screen and I try to create a picturebox from the "spells" list, I get the following error:
"Index was out of range. Must be non-negative and less than the size of the collection."
I have looked up other solutions to this problem but I haven't really had any luck so far.
As an experiment, try making your timer longer (slower, fewer ticks per minute) to see if the problem improves, but doesn't go away.
The timer may be firing off simultaneous runs of your function there -- which could cause all sorts of logical problems.

Continuing the most outer loop from the most nested one

Is there a way to continue the most outer loop from the most nested one in ABAP?
Example in Java. There is a construct in this language using labels (most people do not know of it anyway) which allows me to continue the most outer loop from the nested one.
public class NestedLoopContinue {
public static void main(String[] args) {
label1: for (int i = 0; i < 5; i++) {
for (int j = 0; j < 2; j++) {
if (i == 3) {
continue label1;
}
}
System.out.println(i + 1);
}
}
}
This outputs
1
2
3
5
Now, how can I do it in ABAP in a smart way? One solution would be to use TRY. ENDTRY. block but it is rather a hacking one. Any other ideas?
DATA: l_outer_counter TYPE i.
DO 5 TIMES.
l_outer_counter = sy-index.
TRY.
DO 2 TIMES.
IF l_outer_counter = 4.
RAISE EXCEPTION TYPE cx_abap_random.
ENDIF.
ENDDO.
WRITE / l_outer_counter.
CATCH cx_abap_random.
CONTINUE.
ENDTRY.
ENDDO.
Or maybe there is a way to tell whether the DO. ENDO. ended with an EXIT statement (without introducing an own variable of course, like SYST global variable)?
DATA: l_outer_counter TYPE i.
DO 5 TIMES.
l_outer_counter = sy-index.
DO 2 TIMES.
IF l_outer_counter = 4.
EXIT.
ENDIF.
ENDDO.
IF sy-last_loop_ended_with_exit = abap_true. "???
CONTINUE.
ENDIF.
WRITE / l_outer_counter.
ENDDO.
I don't know of an ABAP-specific solution, but I've used a general programming solution to handle this before; simply use a boolean and check at the end of the inner loop whether or not to continue.
In Java:
public class NestedLoopContinue
{
public static void main(String[] args)
{
for (int i = 0; i < 5; i++)
{
boolean earlyBreak = false;
for (int j = 0; j < 2; j++)
{
if (i == 3)
{
earlyBreak = true;
break;
}
}
if (earlyBreak)
{
continue;
}
System.out.println(i + 1);
}
}
}
And in ABAP:
DATA: l_outer_counter type i,
early_break type FLAG.
DO 5 TIMES.
l_outer_counter = sy-index.
DO 2 TIMES.
IF l_outer_counter = 4.
early_break = ABAP_TRUE.
EXIT.
ENDIF.
ENDDO.
IF early_break = ABAP_TRUE.
CLEAR early_break.
CONTINUE.
ENDIF.
WRITE / l_outer_counter.
ENDDO.
I've read that the reason label-based breaks exist in Java in the first place is because GOTO statements explicitly do not, and the case covered by label-based break was one of the few "good" uses of GOTO that the team wanted to maintain.
In general, though, this is a very awkward construction. Is there no potential way to refactor your code (perhaps swapping the inner-ness of the loops) to remove the need for this in the first place?
When working with nested loops, I often find the best way to improve readability, and avoid using more unusual approaches (such as breaking to a label, which is not only controversial because of its goto-like nature, but also reduces readability because a lot of people are not familiar with them) is to extract the inner loop into a separate function. I do not know how this is done in ABAP, but the refactored Java equivalent would be:
public class NestedLoopContinue {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
NestedLoopContinue.innerLoop(i)
}
}
static void innerLoop(int i) {
for (int j = 0; j < 2; j++) {
if (i == 3) {
return;
}
}
System.out.println(i + 1);
}
}
I would argue that in this example, this actually becomes less readable because it is harder to follow the logic across the two methods. However, if this was a real-world example (where the methods and variables had some actual meanings and appropriate names to go with them), then the result of extracting the inner loop into a separate method would be more readable than using a label.
Based on the robjohncox answer, the ABAP code might look like this.
CLASS lcl_nested_loop_continue DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS:
main.
PRIVATE SECTION.
CLASS-METHODS:
inner_loop
IMPORTING
i_index TYPE i.
ENDCLASS.
CLASS lcl_nested_loop_continue IMPLEMENTATION.
METHOD main.
DO 5 TIMES.
lcl_nested_loop_continue=>inner_loop( sy-index ).
ENDDO.
ENDMETHOD.
METHOD inner_loop.
DO 2 TIMES.
IF i_index = 4.
RETURN.
ENDIF.
ENDDO.
WRITE / i_index.
ENDMETHOD.
ENDCLASS.

Flash AS 3 Loader OnComplete Inside a Loop

As a followup to the question, How to get associated URLRequest from Event.COMPLETE fired by URLLoader, how can I make the function work for loader object in a loop?
Here is my existing (rough) code; I always get the mylabel from the last element of the array.
var _loader = new Loader();
for (j = 0; j < 5; j++) {
//mylabel variable is correct setup in the loop
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
doneLoad(e, mylabel);
});
_loader.load(new URLRequest(encodeURI(recAC[j].url)));
}//for loop
As per the comments above, this won't work because:
1) You're just adding the same event listener 5 times to the loader.
2) You're just reseting your same loader object 5 times.
The final output will just be as though you only called it the last time.
There are a variety of ways to address this - loading stuff asynchronously is one of the great mindfucks of learning to code - but the simplest way is probably just to create five separate loaders.
I'd do something like this:
var loaders:Array = [];
var labels:Array = ["label1", "label2", "label3", "label4", "label5"];
for (var j:int = 0; j < 5; j++) {
loaders[j] = new Loader();
loaders[j].contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loaders[j].load(new URLRequest(encodeURI(recAC[j].url)));
}
function completeHandler(e:Event):void {
doneLoad(e.currentTarget, labels[loaders.indexOf(e.currentTarget)]);
}
The confusing part is finding a good way to keep track of which load is associated with which label etc, since in theory your loads can finish in any order. That's why I've got a separate label array there, and then you just match up the desired label with the loader that just finished loading.
I hope that helps!
the line belove should work but it returns -1, always.
loaders.indexOf(e.currentTarget);
Here my code
for(i; i < total; i++){
imgLoaderArray[i] = new Loader();
imgLoaderArray[i].contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, urlError);
imgLoaderArray[i].contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
imgLoaderArray[i].load(new URLRequest(xmlList[i].image));
}
function loaded(e:Event):void{
trace("index: "+imgLoaderArray.indexOf(e.currentTarget)); // return -1 every time
}

Resources