In this recipe, we'll build a very simple Silverlight application that uses techniques that are explained in much more detail later on in the book. We'll be using data binding, which is a technique to easily connect data to the user interface (UI) and connect to a Windows Communication Foundation (WCF) service.
However, the main goal is to get a grip on the basics of Silverlight by trying to answer questions such as how a Silverlight application is built, what the project structure looks like, what files are created, and what is their use.
To get started with Silverlight application development, make sure that you have installed Visual Studio along with the necessary tools and libraries as outlined in the previous recipe.
We are building this application from the ground up. However, the finished product can be found in the Chapter01/SilverlightHotelBrowser
folder in the code bundle that is available on the Packt website.
Our first Silverlight application allows the user to view the details of a hotel that is selected in a ComboBox
control. The hotel information is retrieved over a service and is used for filling the ComboBox
and the details shown in several TextBlock
controls that are placed in a grid.
The following screenshot shows the interface of the application:
To start building any Silverlight application, we'll need to perform the following steps:
1. Open Visual Studio 2010 with the Silverlight 4 tools installed. Once inside the Integrated Development Environment (IDE), go to File | New | Project.... In the New Project dialog that appears, select the Silverlight node under Visual C# and select Silverlight Application. Name the application as SilverlightHotelBrowser and click the OK button. In the dialog that appears as shown in the next screenshot, select ASP.NET Web Application Project as the type of web project that will be used to host the Silverlight application. Also, make sure that Silverlight 4 is selected as the target version of Silverlight 4.
3. Our service will return the hotel information. A hotel can be represented by an instance of the
Hotel
class. This class should be included in the web project—SilverlightHotelBrowser.Web
.There are a few things to note about this class:
This class has a
DataContract
attribute attached to it. This attribute is required to specify that this class can be serialized when sent over the wire to the client application.Each property is attributed with the
DataMember
attribute. When adding this attribute to a property, we specify that this property is a part of the contract and that it should be included in the serialized response that will be sent to the client.
The following code defines this class:
[DataContract] public class Hotel { [DataMember] public string Name { get; set; } [DataMember] public string Location { get; set; } [DataMember] public string Country { get; set; } [DataMember] public double Price { get; set; } }
4. We'll now add a WCF service to the web project as well. Right-click on
SilverlightHotelBrowser.Web
and select Add | New Item.... Add a Silverlight-enabled WCF Service by selecting the Silverlight node under Visual C# and name it as HotelService. Click the Add button. Two files are added, namely,HotelService.svc
andHotelService.svc.cs
.5. In this service class, we can now add a method that returns a hardcoded list of hotels. Remove the
DoWork
method and replace it with the following code:[ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class HotelService { [OperationContract] public List<Hotel> GetHotels() { return new List<Hotel> { new Hotel { Name = "Brussels Hotel", Price = 100, Location = "Brussels", Country = "Belgium" }, new Hotel { Name = "London Hotel", Price = 200, Location = "London", Country = "United Kingdom" }, new Hotel { Name = "Paris Hotel", Price = 150, Location = "Paris", Country = "France" }, new Hotel { Name = "New York Hotel", Price = 230, Location = "New York", Country = "USA" } }; } }
Note the attributes that have been used in this class. The
ServiceContract
attribute specifies that the class contains a service contract that defi nes what functionality the service exposes. TheOperationContract
attribute is added to operations which can be invoked by clients on the service. This effectively means that if you add methods to the service without this attribute, it can't be invoked from a client6. Now we'll build the solution and if no errors are encountered, we're ready for takeoff—takeoff for writing Silverlight code.
Let's first make the service known to the Silverlight application. Right-click on the Silverlight application and select Add Service Reference.... In the dialog box that appears, as shown in the following screenshot, click on Discover and select your service. As it is in the same solution, the service will appear. Enter HotelService in the Namespace field.
Click on the OK button to confirm. The service is now usable from the Silverlight application.
7. The UI was shown earlier and is quite easy. The XAML code for the
Grid
namedLayoutRoot
inside theMainPage.xaml
file is as follows:<Grid x:Name="LayoutRoot" Width="400" Height="300" Background="LightGray"> <Grid.RowDefinitions> <RowDefinition Height="50"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <ComboBox x:Name="HotelComboBox" Width="250" SelectionChanged="HotelComboBox_SelectionChanged" DisplayMemberPath="Name" VerticalAlignment="Center"> </ComboBox> <Grid x:Name="HotelDetailGrid" Grid.Row="1" VerticalAlignment="Top"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock x:Name="NameTextBlock" Grid.Row="0" Grid.Column="0" FontWeight="Bold" Text="Name: " HorizontalAlignment="Right"> </TextBlock> <TextBlock x:Name="NameValueTextBlock" Grid.Row="0" Grid.Column="1" Text="{Binding Name}"> </TextBlock> <TextBlock x:Name="LocationTextBlock" Grid.Row="1" Grid.Column="0" FontWeight="Bold" Text="Location: " HorizontalAlignment="Right"> </TextBlock> <TextBlock x:Name="LocationValueTextBlock" Grid.Row="1" Grid.Column="1" Text="{Binding Location}"> </TextBlock> <TextBlock x:Name="CountryTextBlock" Grid.Row="2" Grid.Column="0" FontWeight="Bold" Text="Country: " HorizontalAlignment="Right"> </TextBlock> <TextBlock x:Name="CountryValueTextBlock" Grid.Row="2" Grid.Column="1" Text="{Binding Country}"> </TextBlock> <TextBlock x:Name="PriceTextBlock" Grid.Row="3" Grid.Column="0" FontWeight="Bold" Text="Price: " HorizontalAlignment="Right"> </TextBlock> <TextBlock x:Name="PriceValueTextBlock" Grid.Row="3" Grid.Column="1" Text="{Binding Price}"> </TextBlock> </Grid> </Grid>
8. In the code-behind class, MainPage.xaml.cs, we connect to the service and the results are used in a data binding scenario. We won't focus here on what's actually happening with the service call and the data binding; all this is covered in detail later in this book.
public MainPage() { InitializeComponent(); HotelService.HotelServiceClient proxy = new SilverlightHotelBrowser.HotelService.HotelServiceClient(); proxy.GetHotelsCompleted += new EventHandler <SilverlightHotelBrowser.HotelService. GetHotelsCompletedEventArgs> (proxy_GetHotelsCompleted); proxy.GetHotelsAsync(); } void proxy_GetHotelsCompleted(object sender, SilverlightHotelBrowser.HotelService. GetHotelsCompletedEventArgs e) { HotelComboBox.ItemsSource = e.Result; } private void HotelComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { HotelDetailGrid.DataContext = (sender as ComboBox) .SelectedItem as HotelService.Hotel; }
8. We will compile the solution again and then press the F5 button. The application should now run, allowing us to select a hotel in the
ComboBox
. Each selection change will trigger an event that shows the details of the selected item using data binding.
Silverlight applications always have to run in the context of the browser. That's the reason why Visual Studio prompts us initially by asking how we want to host the Silverlight content.
Note
Note that Silverlight 3 added out-of-browser capabilities to its previous version, thereby allowing Silverlight applications to run "standalone". However, they still run inside the browser sandbox. Silverlight 4 added the option to run a Silverlight application out of browser with elevated permissions, thereby giving it more permissions on the local system. We'll be looking at these later on in this book.
The default option is the ASP.NET Web Application Project. This option gives us the maximum number of possibilities for the configuration of the host project. It's the option that we will be using the most throughout this book because of the configuration options it offers towards working with services. The second option is ASP.NET Web Site and is a file-based website known from ASP.NET 2.0. Finally, we can also uncheck the Host the Silverlight application in a new Web site checkbox. This will result in Visual Studio generating an empty HTML page containing the Silverlight application whenever we build our solution. This option is not well suited for building Silverlight applications that work with services as we have no control over the generation process.
A new Silverlight solution thus contains normally two projects—a Silverlight project and a hosting application. Let's first take a look at the Silverlight project:
Silverlight applications contain XAML and C# (or VB.NET) files, among others. The XAML files contain the UI and are linked at runtime to the partial classes that make up the code-behind. By default, one page is added for free—called MainPage
. It's not really a page, but a user control that is hosted. We can add UI code (such as controls, grids, and so on) to this file. We add UI logic in the code-behind.
One special case is the App.xaml
file. It's the entry point of an application and is responsible for loading an instance of the MainPage
, executing logic when an error occurs, and so on. Also, it can contain global resources such as styles that should be available over the entire application.
While building the solution, the Silverlight project is compiled into an assembly. In turn, this assembly—along with a manifest file that contains general information about the application and possible other resources—are wrapped into an XAP file. This XAP file is then copied into the hosting application. It shows up under the ClientBin
directory in the web project as shown in the following screenshot:
The XAP file is basically a ZIP (archive) file. When renaming the SilverlightHotelBrowser.xap
file to SilverlightHotelBrowser.zip
, we can see the original files (manifest and assembly
). The following screenshot shows the contents of the ZIP file:
The generated ASPX page as well as the HTML page refer to the XAP file located in the ClientBin
directory.
Data is not readily available to a Silverlight application on the client side. So we need to retrieve it from the server. In Silverlight, this is done using services. Services need to be accessed asynchronously in Silverlight, hence the declaration of the callback method—proxy_GetHotelsCompleted
. Silverlight has many options to communicate with services. These are covered in the recipes of this book.
We use the rich data binding features available in Silverlight to connect the data with the UI in this application. Data binding allows us to bind properties of objects (the data) to properties of controls. In this particular example, we bind a list of Hotel
instances to the ComboBox
using the ItemsSource
property. While changing the selection in the control, the HotelComboBox_SelectionChanged
event handler fires and the selected item—a Hotel
instance—is set as the DataContext
for the HotelDetailGrid
. This grid contains the controls in which we want to show the details. Each of these controls uses a Binding
markup extension in XAML to specify which property needs to be bounded.