Saturday, February 5, 2011

Working with threads in silverlight

Lets say that we have a silverlight application that gets updates from an outer service every X seconds. the application calls the service every X seconds and waits for the answer(async-way of course).

The most trivial way is to use a timer that every X seconds the Tick event will raise and call our service.

In order to do so we have got the System.Threading.Timer to use. the code will look like that:

       public MainPage()
       {
           InitializeComponent();

           var timer = new Timer(TimerTick, null, new TimeSpan(0, 0, 0, 1), new TimeSpan(0, 0, 0, 5));
       }

       private void TimerTick(object state)
       {
           var client = GetClient();
           client.GetUpdatesComplete += GetUpdate_OnComplete;

           client.GetUpdates();
       }

       private void GetUpdate_OnComplete(object sender, GetUpdatesCompleteEventArgs e)
       {
           if (e.Error == null)
           {
               MyTextBox.Text = "Hello world! the time is " + DateTime.Now;
           }
           else
           {
               MyTextBox.Text = "Error!";
           }

       }

But when we will run the code we will get an error:

"Cross-thread operation not valid: Control 'MyTextBox' accessed from a thread other than the thread it was created on."

The meaning of this error is that we are trying the access the UI from other thread rather than the UI thread. and in silverlight, this is not possible.

So what we do?? we use the method Dispatcher.BeginInvoke() that will change the property via the UI thread. the code will look like this:

        private void GetUpdate_OnComplete(object sender, GetUpdatesCompleteEventArgs e)
        {
            if (e.Error == null)
            {
                Dispatcher.BeginInvoke(() => MyTextBox.Text = "Hello world! the time is " + DateTime.Now);
            }
            else
            {
                ispatcher.BeginInvoke(() => MyTextBox.Text = "Error!");
            }

        }

This is all nice and pretty but there might be a problem. this thread will run no matter what is the state of the UI. even if the UI is stuck, because it runs from another thread….

If we want to use timer that will run on the UI thread we can use DispatcherTimer , and we won't have to call the Dispatcher.BeginInvoke().

Did you got confused?? lets summarize:

1) If you need to use threads that should run each X seconds, no matter what the UI state is, and don't want it to effect the UI – use Timer and Dispatcher.BeginInvoke().

2) If you want that your timer will not run while the UI is stuck or have al long processing to do – use DispatcherTimer.

No comments:

Post a Comment