Having not done much with Silverlight I thought I’d give it a go today building a very simple application that would periodically go off to a webservice, retrieve a new item and insert it into a list. The UI which you can see below is very basic – it has a Start and Stop button and a list which is gradually populated with items. Clicking the start button initiates the request process which periodically (approx every 2 secs) makes the web service request.
This all seems simple enough and you would have throught the following would work:
Private service As SimpleServices2.SimpleService2SoapClient Private Sub Start_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) If service Is Nothing Then Dim temp = New SimpleServices2.SimpleService2SoapClient service = temp AddHandler temp.HelloWorldCompleted, AddressOf SimpleCallBack temp.HelloWorldAsync() End If End Sub Private Sub SimpleCallBack(ByVal sender As Object, ByVal e As SimpleServices2.HelloWorldCompletedEventArgs) Static count As Integer count += 1 Me.mItemList.Items.Insert(0, e.Result & " " & count.ToString)
Dim temp = service If temp Is Nothing Then Return temp.HelloWorldAsync() End Sub Private Sub Stop_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) If service IsNot Nothing Then Dim temp = service service = Nothing RemoveHandler temp.HelloWorldCompleted, AddressOf SimpleCallBack End If End Sub
Whilst this would appear to work the UI appears to be very unresponsive. Sure enough if you put a breakpoint in you will see that SimpleCallBack gets executed on the UI thread – most unusual if you are used to WinForms programming where the call back would generally not be on the UI thread. Ok, so the thing to do here would be to create a background thread to do the periodic web service call.
Wrong again! Unfortunately as Simon points out there is a dependency that requires service calls to be made on the UI thread (urgh you say). So, now we have to code around this in order to jump to a background thread to sleep (so as not to block the UI thread), then jump back again to the UI thread to execute the web service request. Of course ideally a bit of refactoring would result in us initiating a background thread that simply makes a synchronous call but unfortunately there is no synchronous method on the service proxy.
What we end up with is the following:
Private Sub SimpleCallBack(ByVal sender As Object, ByVal e As SimpleServices2.HelloWorldCompletedEventArgs) Static count As Integer count += 1 Me.mItemList.Items.Insert(0, e.Result & " " & count.ToString) Dim t As New System.Threading.Thread(AddressOf WaitThenRetrieve) t.Start() End Sub Private Sub WaitThenRetrieve() System.Threading.Thread.Sleep(2000) Me.mItemList.Dispatcher.BeginInvoke(New System.Threading.ThreadStart(AddressOf RetrieveNewItem)) End Sub Private Sub RetrieveNewItem() Dim temp = service If temp Is Nothing Then Return temp.HelloWorldAsync() End Sub
This ain’t a great looking solution but I’ll leave it to you to work out how you can abstract this into a background thread, or better still into a wrapper class that handles the rubbish stuff for you…..Perhaps the Silverlight team might want to FIX this as it’s a royal pain at the moment.