In one of my SL apps, client need to
1) connect (via ConnectAsync/ConnectCompleted) to a WCF server so as to subscribe to a stream of server-push heartbeat messages. These heartbeats must update the screen if screen is ready.
2) client also need a timer to drive periodic pings using getXXXAsync/getXXXCompleted. If ping succeeds/fails, we would like to update the status bar. Therefore the callbacks had batter come after screen setup.
3) at start time client makes one-time get1Async/get1Completed, get2Async/get2Completed, get3Async/get3Completed calls to receive initial static data so as to populate the GUI. I wrapped these calls in a static Download6() method.
*) basically all these data from server (either server-pushed or callbacks) “WANT” to update screen provided static data is loaded, which is done by D6 callbacks. So D6 callbacks had better happen before heartbeats come in, or heartbeat processing would hit empty static data and cause problems. Also, D6 callbacks must execute after screen setup, because those callbacks need to update screen.
That’s basically the requirements. In my initial (barely working) solution everything except timer stuff happens on the main thread.
1) at start time, main thread invokes D6. The callbacks would come back and wait for the main thread to execute them — troublesome but doable
2) main thread makes initial ConnectAsync. The callback would hit main thread too
3) before these callbacks, main thread finishes painting the screen and setting up the view model objects.
4) now the D6 and ConnectCompleted callbacks hit main thread in random order. D6 callbacks tend to happen before server pushes heartbeats.
5) upon ConnectCompleted, we subscribe to heartbeats
6) Timer has an initial delay (about 10s) so usually starts pinging after the dust settles. The Async and Completed calls execute on 2 different non-main-threads.
All the “scheduling” depends on event firing. It’s not possible to “do step 1, then at end of it do step 2…” on main thread.
I now prefer to move the connect, d6 etc off main thread, so the callbacks would hit some other threads. More importantly, this way I have a chance to utilize locks/wait-handles/events to properly serialize the Get/Connect calls, the timer-start and the subscription to server-push heartbeats. This means Step B starts only after Step A completes all callbacks. This was not possible earlier as it would block the main thread and freeze the screen.