jordanpg
jordanpg

Reputation: 6516

Multiple asynchronous UI updates in Silverlight

How does one execute several UI updates from a Silverlight callback?

For example, I would like the user to click a button, have the UI make a change, do some work, then make another change... instead, the user clicks the button and the callback seems to execute in the background and then all of the UI changes flash before my eyes.

MainPage.xaml:

<Grid x:Name="LayoutRoot" Background="White" >
<TextBlock Height="23" Name="textBlock1" Text="TextBlock" VerticalAlignment="Top"/>
<Button Click="button1_Click" Content="Button" Height="23" Name="button1" Width="75"  />
</Grid>

MainPage.xaml.cs:

private void button1_Click(object sender, RoutedEventArgs e)
{
    textBlock1.Text = "1";
    // also tried Thread.Sleep(5000);
    Dispatcher.BeginInvoke(() => Thread.Sleep(5000));
    textBlock1.Text = "2";
}

Upvotes: 1

Views: 4447

Answers (2)

Ron Warholic
Ron Warholic

Reputation: 10074

Silverlight uses a queue of work items to handle rendering and logic on the UI thread. Since your logic also runs on the UI thread (in your button_Click handler) the renderer doesn't get a chance to draw the screen until your method is done executing AND the internal message loop gets around to drawing the screen.

Your BeginInvoke immediately places your function on the Silverlight work queue to execute on the UI thread (and returns immediately). The order Silverlight processes this is probably something like:

  • User clicks the button, placing a click event on the work queue
  • Silverlight sees the click event and calls button_Click (which places a new action on the work queue)
  • Process the next work queue item which is probably your Thread.Sleep action, pausing the UI thread for 5 seconds
  • Finally Silverlight gets around to painting the screen

What you want to do is start a new thread to do your work, then BeginInvoke back to the UI thread:

var thread = new Thread(() => {
  Thread.Sleep(5000);
  Dispatcher.BeginInvoke(() => { 
    // update UI 
    textBox.Text = "2";
  });
});

textBox.Text = "1";
thread.Start();

I should add that Silverlight 5 adds a composition thread that can perform certain actions to update the UI without blocking the UI thread like playing animations and doing GPU accelerated rendering where possible.

Upvotes: 0

Brad
Brad

Reputation: 1529

The BeginInvoke runs asynchronously and therefore will return and change the text.

Directly from MSDN Documentation: "BeginInvoke is asynchronous; therefore, control returns immediately to the calling object after it is called."

Instead in the BeginInvoke add the processing that you want to do. So you do Thread.Sleep and then add the change the textbox.

BackgroundWorker also can tie into events. So when the UI is updated aka BackGroundWorker completed event you can kick of the next item. Here is why you should use the BgroundWorker

i.e.

BackgroundWorker w = new BackgroundWorker();
w.DoWork += (sender, args) => 
{
    Thread.Sleep(5000);
    Dispatcher.BeginInvoke(() => {
    //your code here
    }); 
};
w.RunWorkerAsync();

Upvotes: 1

Related Questions