Archive

Watch out for asynchronous events

This is the first post and it was inspired by the question on SO. To better describe the problem, let’s make a very simple App which will have three TextBoxes:

1

2

3

<TextBoxx:Name="FirstBox"InputScope="Number"Grid.Row="0"/>

<TextBoxx:Name="SecondBox"InputScope="Number"Grid.Row="1"/>

<TextBoxx:Name="ThirdBox"InputScope="Number"Grid.Row="2"/>

Pic. 1 Overlook

The main task of our App is that it should update all three TextBoxes, depending on the user input. So in the code behind we will create an event handler and subscribe it to TextBox.TextChanged event (in this simple example I’ll just put the text informing which TextBox was changed):

As you can see, I’ve subscribed Box_ChangedOne to all three TextBoxes – let’s update everything right after one of them changes (why not?). Here comes the first problem, just after we focus on any control and try to put text – our App hangs. Aha – longer look at the code and it turns out that we are in an infinite loop – our event fires another one (cause it is changing TextBox.Text) and so on. So we will improve the event handler with a flag which will inform if the change was invoked by user or from the code:

dontChangeFlag=true;// set the flag to prevent next fired event from further changing Boxes

FirstBox.Text=info;

SecondBox.Text=info;

ThirdBox.Text=info;

dontChangeFlag=false;// enable changing

}

}

Looks great, so we should test it. Oops, the program hangs – what is wrong? The solution comes with the MSDN: The TextChanged event is asynchronous. Our simple code is racy, and line
dontChangeFlag=false; is fired before the events – so we are again in an infinite loop. So why not delay a little our process and wait for other events to finish?

dontChangeFlag=true;// set the flag to prevent next fired event from further changing Boxes

FirstBox.Text=info;

SecondBox.Text=info;

ThirdBox.Text=info;

await Task.Delay(1000);// let's give some time to change Boxes

dontChangeFlag=false;// enable changing

}

}

This time we get what we wanted – our flag is working. So far so good – but how to predict how long will it take the phone to finish the events? The answer is – we can’t and don’t do it – let the event informs when it is finished. For this purpose I’ll use a SemaphoreSlim class. And here we will also improve our code (to show the next issue) – our first TextBox will be set up with the entered text:

dontChangeFlag=true;// set the lag to prevent next fired event from further changing Boxes

FirstBox.Text=enteredText;

await semWait.WaitAsync();// wait until finished changing

SecondBox.Text=info;

await semWait.WaitAsync();// wait until finished changing

ThirdBox.Text=info;

await semWait.WaitAsync();// wait until finished changing

dontChangeFlag=false;// enable changing

}

elsesemWait.Release();

}

Our semaphore should wait until it is released, and it does so, but if we just change the text in the FirstBox then we will see that something is worng – there is no change in other TextBoxes. Quick debug shows that the semaphore waits to be released – what is wrong? Again qucik look at MSDN shows what is going on – If the Text property is set to the same string as the content in the TextBox, the event is not raised. The simpliest way will be to check if the event is going to run:

dontChangeFlag=true;// set the lag to prevent next fired event from further changing Boxes

if(FirstBox.Text!=enteredText)

{

FirstBox.Text=info;

await semWait.WaitAsync();// wait until finished changing

}

if(SecondBox.Text!=info)

{

SecondBox.Text=info;

await semWait.WaitAsync();// wait until finished changing

}

if(ThirdBox.Text!=info)

{

ThirdBox.Text=info;

await semWait.WaitAsync();// wait until finished changing

}

}

elsesemWait.Release();

}

Finally our code is working as it should.

One may ask – what is the purpose of the slider in the picture? This is a simple test showing that not every event is run asynchronous – if we write a similar method like above, but for Slider’s change: