Amazon.com Widgets

Data focused Silverlight demo

Yet still more time on traveling, I thought I'd do a little demo of a data oriented scenario with Silverlight.

Here is what we are after:

image

The data for the app is loaded from a Linq model and sent to the Silverlight client via a WCF services.
As the user makes changes to the grid, we asynchronously update the Linq model on the service.
The app uses local storage to cache the data on the local machine to reduce network calls.

Create a new Silverlight application and associated web site.

image

Let's start by creating a data model in the web site.

image

Then drag over the Employees table. 

image

Then, Select Photo and delete it.  It is a large binary blob that we don't want to be sending back and forth. 

Then, because we are going to expose this over a WCF service, let's make it Serializable. 

image

Now let's add the WCF service.  Be sure to select the Silverlight-enabled WCF service. 

image

Then the implantation is straight forward. In this method you can customize based on the user's role, do paging, etc.  For now, I will just take the first 15 for this demo.

[OperationContract]
public IEnumerable<Employee> GetAllEmployees()
{
    var context = new NorthwindDataContext();
    var q = from employee in context.Employees
            select employee;
    return q.Take(15).ToList();
}

Now in the client, we need to add a reference to this service.

image

Then define a very simple UI...

        <StackPanel>
            <Button x:Name="btn1" Width="100" Height="50" Content="Load Grid" Click="btn1_Click" RenderTransformOrigin="0.5,0.5"></Button>
            <my:DataGrid x:Name="dataGrid" ></my:DataGrid>    
            <TextBlock x:Name="label"></TextBlock>
        </StackPanel>

And handle the button click

private void btn1_Click(object sender, RoutedEventArgs e)
{
    var client = new EmployeeService.EmployeesServiceClient();
    client.GetAllEmployeesAsync();
    client.GetAllEmployeesCompleted += new EventHandler<GetAllEmployeesCompletedEventArgs>(client_GetAllEmployeesCompleted);
    label.Text = "Sending Request";
}

void client_GetAllEmployeesCompleted(object sender, GetAllEmployeesCompletedEventArgs e)
{
    dataGrid.ItemsSource = e.Result;
    label.Text = "Got results from network";
}

Now let's send up the changes as the user changes the values in the grid.

What we want to do is sign up for changes on each row.  The interesting thing here is that we recycle the rows, so we have to be careful to not sign up for an event more than once.  The solution we came up with was to listen for the Loading and Unloading row events and register, unregiser the events on each. 

So DataGrid looks like this:

            <my:DataGrid Width="600" Height="200" x:Name="dataGrid" UnloadingRow="dataGrid_UnloadingRow" LoadingRow="dataGrid_LoadingRow" AutoGenerateColumns="True"></my:DataGrid>

And the code:

    private void dataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
    {
        ((Employee)e.Row.DataContext).PropertyChanged +=
new PropertyChangedEventHandler(Page_PropertyChanged);
    }

    private void dataGrid_UnloadingRow(object sender, DataGridRowEventArgs e)
    {
        ((Employee)e.Row.DataContext).PropertyChanged -= 
            new PropertyChangedEventHandler(Page_PropertyChanged);

    }
    void Page_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Employee ep = sender as Employee;
        label.Text = "Employee " + ep.EmployeeID + " changed. Updating network";
    }

With this, as the user changes values in the grid, this PropertyChanged event is called.

image

Now all we need to do is call the server with the changed data. 

To do that, let's go back and add a new web service.

public void UpdateEmployee(Employee employee)
 {
     NorthwindDataContext context = new NorthwindDataContext();
     var oldEmployee = (from e in context.Employees
                        where e.EmployeeID == employee.EmployeeID
                        select e).First();

     oldEmployee.FirstName = employee.FirstName;
     oldEmployee.LastName = employee.LastName;
     // add the rest of the properites 

     context.SubmitChanges();
 }

Note: There are of course easier\better ways to do this sort of updating in linq... http://msdn.microsoft.com/en-us/library/bb425822.aspx

Then back to the Silverlight client and update the reference

image 

Now, add a few lines to call this method and we are set. 

void Page_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    Employee ep = sender as Employee;
    label.Text = "Employee " + ep.EmployeeID + " changed. Updating network";
    var client = new EmployeeService.EmployeesServiceClient();
    client.UpdateEmployeeCompleted += new EventHandler<AsyncCompletedEventArgs>(client_UpdateEmployeeCompleted); 
client.UpdateEmployeeAsync(ep,ep.EmployeeID); } void client_UpdateEmployeeCompleted(object sender, AsyncCompletedEventArgs e) { label.Text = "Employee ID"+e.UserState+" successfully updated"; }

Run it and it works great!

image

Make changes, refresh to be sure the changes are reflected in the underlying datamodel.

OK, for a final step, let's see if we can cache this data offline in Silverlight's per-application Isolated Storage. 

Add the following to the page class

private IsolatedStorageSettings appSettings = 
    IsolatedStorageSettings.ApplicationSettings;

To client_GetAllEmployeesCompleted  add

appSettings["backStore"] = e.Result;
appSettings.Save();

This saves the backStore into the local store.

To the Page constructor add

if (appSettings.Contains("backStore"))
{
    label.Text = "loading data from local store";
    dataGrid.ItemsSource = appSettings["backStore"] as IEnumerable;
}
else
{
    label.Text = "No local data";
}

If there is data in the store, we use it. 

Run it... the first time, no data..

image

Hit load and refresh and you should have local data

image

Now, just to be sure things are working the way we expect, right click on the Silverlight control, select Application Storage and Delete this one for this app.  Notice it says zero as a rounding issue,there is so data there.

image

Hit refresh and it is back to no data.  Just as we expected. 

In this post we:

Got the data for the app is loaded from a Linq model and sent to the Silverlight client via a WCF services.
As the user makes changes to the grid, we asynchronously update the Linq model on the service.
The app uses local storage to cache the data on the local machine to reduce network calls.

Download the full sample here.

Published 26 June 08 09:41 by BradA
Filed under: ,

Comments

# mixed up said on June 26, 2008 2:45 PM:

thanks for the sample. really enjoyed your presentations and demos at mix johannesburg.

# Fredrik said on June 26, 2008 3:54 PM:

I really enjoyed your presentation in Cape Town today. Am I correct in saying VS 2008 Intellisense picks up your CSS classes? So when you type class="<classname>", for example, it shows the classes you created and you can just select it. Was that a feature in VS 2005?

# David Fauber said on June 27, 2008 9:32 AM:

"cash the data" - Think the word you're going for is "cache"

# Community Blogs said on June 27, 2008 6:12 PM:

Jaime Rodriguez on DeepZoom, Pete Brown on on Publish/Subscribe pattern in SL, Shawn Wildermuth on XAML

# BradA said on June 29, 2008 3:59 AM:

Fredrik -  Yes, you are correct abou the CSS support in VS2008 picking up the class names.. I beleive this is new in 2008...  Enjoy!

David - Thanks, I have fixed it.  

# Buster said on June 29, 2008 8:50 PM:

Brad, I have gone through your sample, which is something I'm interested in because i work with a lot of web enabled reporting. But I am getting this error when trying to add a reference to this service to the client:

There was an error downloading 'http://localhost:1123/SilverlightApplication1Web/App_Code/Service.svc'.

The request failed with HTTP status 403: Forbidden.

Metadata contains a reference that cannot be resolved: 'http://localhost:1123/SilverlightApplication1Web/App_Code/Service.svc'.

The HTTP request was forbidden with client authentication scheme 'Anonymous'.

The remote server returned an error: (403) Forbidden.

If the service is defined in the current solution, try building the solution and adding the service reference again.

I've looked in other forums but the posts I see are realted to ssl, but I'm not using ssl. Can you suggest a solution or workaround for this? I'd like to be able to implement your example.

Thanks,

Buster

# Robert Folkesson said on July 1, 2008 5:24 PM:

Idag körde jag Silverlight 2-sommarkollo tillsammans med Carl Kenne från Dotway och Anders Rundqvist

# SASilver said on July 25, 2008 3:52 AM:

Hi Brad,

I have this problem which i cant just solve.

Components I have in my project are

1) A Service - from another project

2) A Silverlight UI application

3) A Web UI

4) A WCF service application

Now i am referring the service in my WCF service app and tried adding it to my Silverlight project as a Service reference.

I am not able to see the client stubs to access and create a proxy.

It instead exposes the classes i have written. Have checked my config files. Have written the  Service contract,datacontract...

When i run the service in the browser,it works fine.

Any views ?

# 男性下着 said on August 13, 2008 3:53 AM:

<a href="http://www.propaganda-web.com/design/gcom285/mens.htm">男性下着</a> のことならプロパガンダ。他にも<a href="http://www.propaganda-web.com/design/gcom285/mens.htm">男性下着</a> 、ビキニ、<a href="http://www.propaganda-web.com/design/gcom285/mens.htm">男性下着</a> 、トランクスからセクシー系まで<a href="http://www.propaganda-web.com/design/gcom285/mens.htm">男性下着</a> のことならお任せください。"

# Ozzy said on August 13, 2008 10:44 AM:

I like your simple and clean samples. These are very helpful.

Another sample that I would find helpful would be to take this simple code and add robust error handling.  I would like to see the proper way to handle expected and unexpected errors (exceptions) when calling web services from silverlight.

Thanks again!

# 品川デリヘル said on August 19, 2008 6:23 AM:

<a href="http://celeb-t.com">品川デリヘル</a>高級デリヘル, <a href="http://celeb-t.com">品川デリヘル</a>品川の<a href="http://celeb-t.com">品川デリヘル</a>店「<a href="http://celeb-t.com">品川デリヘル</a>東京」では高級感ある極上なひとときをご提供します。

New Comments to this post are disabled

Search

Go

This Blog

Syndication

Page view tracker