Silverlight on Devices
We'll look at how the power of XAML can be brought to Windows Mobile device applications
by using server-side rendering. This allows the creation of a better user experience by
making use of the new user interface technologies (XAML, WPF, etc).
Even if the latest user interface technologies
(XAML, Windows Presentation Foundation,
Silverlight, etc) are not yet available on Windows Mobile devices,
there is still a (sometimes even greater) need to bring a better user experience
to mobile applications. By using the new technologies on the server, and bringing
the result in the form of an image to the mobile device, a part of the problem
is solved. Still, the interactive features of the new technologies are not
available using this approach.
This article is about how this can be done, so let's have a look at the sample.
Get the sample source code!
Device XAML Sample
The sample shows how to bring XAML output to a Windows Mobile application.
This sample application is built for
.NET CF with
Visual Studio 2005
and it looks like this:

Figure 1. Device XAML Sample
The sample simply calls the web server to create the chart and show the result on the device.
Code Walkthrough
To start on the server side, the following is the code for the ASP.NET web application:
private static MemoryStream m = new MemoryStream();
static AutoResetEvent autoEvent;
protected void Page_Load(object sender, EventArgs e)
{
autoEvent = new AutoResetEvent(false);
Thread test = new Thread(
new ParameterizedThreadStart(getImageFromXaml));
test.SetApartmentState(ApartmentState.STA);
test.Start(getXaml());
autoEvent.WaitOne();
Response.ContentType = "image/png";
m.Seek(0, SeekOrigin.Begin);
byte[] data = new byte[m.Length];
int count = m.Read(data, 0, (int)m.Length);
Response.OutputStream.Write(data, 0, (int)m.Length);
}
private void getImageFromXaml(object xaml)
{
object o = (UIElement)XamlReader.Load(
new XmlTextReader(new StringReader((string)xaml)));
UIElement canvas = (UIElement)o;
canvas.Arrange(new Rect(new System.Windows.Point(0, 0),
new System.Windows.Size(320, 188)));
canvas.InvalidateVisual();
canvas.UpdateLayout();
RenderTargetBitmap bmp = new RenderTargetBitmap(
320, 188, 96, 96, PixelFormats.Pbgra32);
bmp.Render(canvas);
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
encoder.Save(m);
autoEvent.Set();
}
The main action happens in the getImageFromXaml method where the XAML is loaded
(from a string returned from the getXaml method) and parsed on a UIElement
(canvas). Then a bitmap is created and
the XAML is rendered on it. Finally, the bitmap is encoded in the desired format
and streamed to a memory stream that is later return to the client. Note that the
PngBitmapEncoder is used here, but there are several other encoders available
(for GIF, JPEG, etc).
Much of the other code is related to the fact that many WPF
objects can only be created on STA threads. Because the ASP.NET application is
MTA-threaded, we need to create another thread to use the WPF objects.
The code on the client side looks like this:
HttpWebRequest request
= (HttpWebRequest)HttpWebRequest.Create(
new Uri("http://www.businessanyplace.net/Xaml2Image.aspx")); HttpWebResponse response = (HttpWebResponse)request.GetResponse();
pictureBox.Image = new Bitmap(response.GetResponseStream());
Here the result from the web request is used to create a bitmap and show it in a PictureBox control.
Now, let's have a look at the XAML to produce the bar chart:
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="320" Height="188">
<Grid Width="320" Height="188">
<Rectangle Stroke="Black"
StrokeThickness="0">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0"
EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="RoyalBlue"
Offset="0" />
<GradientStop Color="#99ccff"
Offset="1" />
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Viewbox Margin="1"
Stretch="Uniform">
<StackPanel Orientation="Horizontal">
<!-- This is where the bars go. -->
</StackPanel>
</Viewbox>
</Grid>
</Canvas>
This is the chart area with the gradient background. A StackPanel is used to host the individual bars,
and for each bar, the following XAML is used:
<Grid VerticalAlignment="Bottom" Width="40">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<Rectangle Grid.Row="0"
Height="{Binding XPath=@Cost}"
Margin="10,10,10,0"
Fill="#33000000"
RadiusX="2"
RadiusY="2">
<Rectangle.RenderTransform>
<TranslateTransform X="1"
Y="1" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Grid.Row="0"
Height="{Binding XPath=@Cost}"
Margin="10,10,10,0"
RadiusX="2"
RadiusY="2"
Stroke="black"
StrokeThickness="0.5">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="LimeGreen"
Offset="0" />
<GradientStop Color="DarkGreen"
Offset="1" />
</GradientStopCollection>
</GradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Grid.Row="0"
Height="{Binding XPath=@Cost}"
Margin="11,12,11,0"
RadiusX="1"
RadiusY="1">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0"
EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#aaffffff"
Offset="0" />
<GradientStop Color="transparent"
Offset="1" />
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Viewbox Grid.Row="1"
Width="30"
Margin="2">
<TextBlock Grid.Row="1"
Width="100"
FontSize="20pt"
FontFamily="Arial"
TextAlignment="center"
TextTrimming="WordEllipsis"
Text="{Binding XPath=@Description}" />
</Viewbox>
<TextBlock Margin="0,3,0,3"
FontSize="5pt"
FontFamily="Arial"
TextAlignment="center"
Foreground="white"
Text="{Binding XPath=@Cost}" />
</Grid>
Each binding (Cost and Description) is replaced with the actual values for each bar.
Conclusion
The new user interface technologies can partially be brought to mobile device
applications using plain web technologies. So, why not do the best of things and
make your applications look better while waiting for the technologies to arrive
on the device?
Any comments?
|