Note: This is part of a series, you can find the related posts here…
This time, building on the last post, I’m going over the basics of getting data to the client. The order of the day is just get it working, I’ll come back later to address some issues.
I have to provide the service first. This is easiest done by adding a Silverlight-enabled WCF service, located in the “Create New Item” dialog, under the Silverlight group. It comes with the necessary configuration, ready to use. After defining the EF model, a first service operation delivering recently acquired books may look like this:
Note the Sleep. I like to stress the asynchronous nature of the SL client and I want the client code to handle this properly, thus the Sleep makes the time lag very apparent.
Note: This way I know very early where I should provide visual feedback, or disable controls. This is especially important considering that on my development machine I will hardly spot any delay, but once the application goes into production and network performance and latency demand their toll, this will likely change.
Thus I recommend you do the same, perhaps surrounding with #if DEBUG and making it configurable.
Calling a service
After running the web application, Cassini provided a live version, which I needed to create the client side proxy. This generates respective code, of course including the data defined in the contract. Those classes already (by default) implement INotifyPropertyChanged and use ObservableCollection<T>. It certainly will give you a head start if you can use these classes as your model.
For every service operation there is a respective MyOperationAsync() method that initiates the asynchronous call and a MyOperationCompleted event that delivers the result. (No synchronous version by design!)
One hint: Creating the client proxy also created a ServiceReferences.ClientConfig file in the service assembly. This file is needed in the UI project to be available for the client. It works quite well to include it in the UI project be setting a reference, rather than just copying the file (“add existing item”, “add as link”), and this way you won’t have to keep a copy in sync.
Wiring it Together
The idiom is documented well enough, thus without further ado, my first version looks like this:
The client instance is also used to detect whether the last call is still under way, and to suppress further calls.
The UI includes a button to trigger the server call (just for now, in this case the call will eventually be made from the c’tor), and the DataGrid to present the result:
The respective event handler is trivial as well:
Now, running the app looks like this:
Clicking the button… waiting… that’s why I put the Sleep in… . Oh, and I can click the button as I like? … Finally the result appears:
Regarding the “I can still click the button…”, I wanted to make this point specifically, because I have already seen people ignore that time lag too easily. It no only makes your application “feel unresponsive” in case of longer operations, because the user doesn’t get any indication whether the application has actually accepted his button click. It also may makes your logic more complex if it had to deal with multiple calls at the same time. My code simply ignored them, but there is no reason why they shouldn’t be processed as they come in. Even canceling the previous call may make sense, because it may be obsolete due to changed parameters (most operations are certainly not as simple as the one used in this example). You may want to cancel if the criteria actually changed and ignore the subsequent call if the criteria stayed the same… . See? Quickly the complexity adds up. The easy way around is disabling the button and making the user experience a sequential one.
Providing visual feedback
So, the logical step is to add a respective property CanLoadBooks and use it for the binding…
After that, disabling the button can be done via data binding the IsEnabled property:
And nicely my application provides visual feedback and at the same time prevents the user from redoing what he did:
This post sort of completes the initial setup of the stage for my Silverlight application. I have a solution, the basic layout is in place, the general application architecture and data binding strategy is set up, and with this post I can talk to the server.
From here I will go exploring various aspects, probably at random, but now I have the means to do so.
And there is a lot of aspects to cover anyway. The services part I addressed in this post is by no means covered exhaustively, neither is data binding. Other topics haven’t yet been mentioned at all, like basic application services, visual state manager, navigation, or configuration.
Anyway, I will have to work on it before I can write about it. So this series is certainly not coming to an end, however further posts may take some more time. And I have a small by-project running, some mischief I’m up too ;-)
That’s all for now folks,