Thursday, March 13, 2008

Silverlight Stocks

Ever since details of Silverlight 2.0 came out, I planned on re-doing my stocks app using it. This is an app that I first wrote for a GWT tutorial I did for IBM, and then re-wrote when I learned Flex last year. I wanted to write it in Silverlight last year, but Silverlight was not ready then. Now it is. Here's a picture of it.


This look-and-feel is all defaults. It looks like a web page! It's usually easy to spot Flex apps, but that is not as true with Silverlight. Everything works the same as with the Flex or GWT versions, except the color-coding for stocks that are up or down. I figured out how to define styles with Silverlight (more on that) but could programmatically set the style. Let's take a look at the code. First the UI code.


<UserControl x:Class="SilverStocks.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Enter Symbol "/>
<TextBox x:Name="symbol" Width="100" KeyDown="symbol_KeyDown"/>
<Button Click="Button_Click" Content="Get Info" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Company Name: "/>
<TextBlock x:Name="company"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Price: "/>
<TextBlock x:Name="price" Text="$"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Change: "/>
<TextBlock x:Name="change" Text=""/>
</StackPanel>
</StackPanel>
</UserControl>


Pretty similar to MXML, but distinctive. As with ASP.NET pages, Silverlight puts all code in a code-behind file:


public partial class Page : UserControl
{
const string url = "http://localhost:8080/Stocks/Stocks?symbol=";
public Page()
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
invokeStockService();
}

private void invokeStockService()
{
string symbol = this.symbol.Text;
WebClient service = new WebClient();
service.DownloadStringCompleted += new DownloadStringCompletedEventHandler(handler);
service.DownloadStringAsync(new Uri(url + symbol));
}

private void handler(object sender, DownloadStringCompletedEventArgs args)
{
if (args.Error == null)
{
this.showInfo(args.Result);
}
}

private void showInfo(string xmlContent)
{
XDocument root = XDocument.Parse(xmlContent);
var stocks = from xml in root.Descendants("stock")
select new Stock
{
Symbol = (string) xml.Element("symbol"),
Company = (string) xml.Element("companyName"),
Price = Decimal.Parse((string)xml.Element("price")),
Change = Decimal.Parse((string)xml.Element("change"))
};
foreach (Stock stock in stocks)
{
this.company.Text = stock.Company;
this.price.Text = stock.Price.ToString();
this.change.Text = stock.Change.ToString();
}
}

private void symbol_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
this.invokeStockService();
}
}
}


Notice that I used the LINQ-XML cleverness, as advocated by Scott Gu. Most dynamic language folks will probably favor ActionScript's E4X over using this lambda-ish query language and a statically defined class. Actually I'm sure I could refactor this to not use the class at all, and just set the text fields during the query.

Finally, the other major difference between the two is the Flex framework's mx:HttpService. This component encapsulates the call to the back-end and provides dynamic binding. There is no handler code in the Flex version because of the binding. Will data source bindings and components like mx:HttpService find their way in to Silverlight?

2 comments:

Anonymous said...

I've been at Robertjan's presentation on silverlight 2.0 for developers (http://www.robertjantuit.nl/) and he demoed databinding from a WCF to a Silverlight control and it was pretty straightforward. I can't remember the details, but I'm sure you can figure it out. I am now learning a bit of actionscript, but I find Silverlight easier since I already have some background on .NET.

Anonymous said...

Yes, .NET generally has straightforward databinding in many places, so Silverlight should be no different. For the stocks app, if you didn't use explicit binding to the mx:HttpService, you could create a data object and just annotate it with [Bindable]. This tells the framework to enhance the class with event publishers, so updates to controls happen automatically. I suppose the Silverlight way would be similar?