Portable Library Tools

With the introduction of Windows Phone 7.0 a new opportunity emerged for Silverlight developers, this new platform uses Silverlight (a version of Silverlight 3.0) as the main framework to build applications on the phone. When building applications for Silverlight and WP7 you will find that you can reuse some of the code across the two platforms, Linked source files were used to share code between WP7 and Silverlight projects along with the use of compilation directives.

Microsoft introduced a new way to create code that targets multiple platforms, it’s a Visual Studio Add-In called Portable Library Tools (Available here)

Portable Library Tools is a new Visual Studio add-in from Microsoft that enables you to create C# and Visual Basic libraries that run on a variety of .NET-based platforms without recompilation.

In this post we are going to build a sample application for WP7 and Silverlight that uses the Portable Class Library Tools.

We will create a CustomersExplorer application that will allow the user to display and edit the customers from the AdventureWorks database, Let’s start by creating new solution we will add a web application project called CustomersExplorer.Web, in this project we will have an Entity Framework model that exposes the customers in the AdventureWorks database (the EF model will use ADO.NET self tracking entities), we will expose the model through a WCF service that uses webHttpBinding. the service code is shown below

[ServiceContract]
    public interface ICustomerService
    {
           [OperationContract]
          List<Customer> GetCustomers();
           [OperationContract]
          OperationStatus SaveCustomer(Customer customer);

           [OperationContract]
          Customer GetCustomer(int custID);
    }
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class CustomerService : ICustomerService
    {
        public List<Customer> GetCustomers()
        {
            return new CustomerRepository().GetCustomers();
        }

        public OperationStatus SaveCustomer(Customer customer)
        {
            return new CustomerRepository().SaveCustomer(customer);
        }

        public Customer GetCustomer(int custID)
        {
            return new CustomerRepository().GetCustomer(custID);
        }
    }

We will add three more projects to the solution:

1. CustomersExplorer.Core: a Portable Class Library Project that will contain the shared code to be used in the Silverlight and windows phone apps

Portable Class Library Project

2. CustomersExplorer.Silverlight: the Silverlight application

3. CustomersExplorer.WP: the windows phone 7 application

The layout of the solution should be like the following

Solution Layout

The CustomersExplorer.Core project will be used by the Silverlight and the Windows Phone applications, so we will add a reference to this project to the Silverlight and Windows Phone Projects.

Next we’ll change the settings of the CustomersExplorer.Core

project. By default when you create a new Portable Class Library project its settings is set to target the .Net 4.0, Silverlight 4.0 and Windows Phone 7.0 frameworks, we will change this to target Silverlight and Windows Phone. Go to the properties of the project and click Change button in the target frameworks section

Portable Class Library Project Target Frameworks

In the dialog, choose Windows Phone 7.0 and Silverlight 4.0

Target Frameworks

We need to add a reference to the System.Windows assembly, this assembly contains the ObservableCollection type that we need in the Silverlight and WP applications, the dll is located in this path “C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\” 

Next we need to add a service reference for the CustomersService, for some unknown reason If you tried to add a reference to the Customers service in the Portal Class Library project, the generated proxy class will not use ObservableCollection as the collection type, so we will use the SLsvcutil tool to create the proxy class, the slsvcutil tool is located in the folder C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Tools”

Run the tool with the following command line

  1. slsvcutil  /edb /namespace:"*,CustomerExplorer.Core.CustomersService" /ct:System.Collections.ObjectModel.ObservableCollection`1 /r:"C:\PROGRAM FILES (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\System.Windows.dll" /directory:C:\Users\Mohamed\Desktop\generated\

Take the generated file CustomerService.cs and add it to the CustomersExplorer.Core project, the other generated file (ServiceReferences.ClientConfig) must be copied to the 

CustomersExplorer.Silverlight and CustomersExplorer.WP projects.

In the CustomersExplorer.Core project we will create the CustomersViewModel, which exposes a property Customers of type ObservableCollection<Customer> , and a property CurrentCustomer of type Customer, two commands are exposed UpdateCustomerCommand and DeleteCustomerCommand that forward these actions to the Customers WCF service.

#region "Commands"
        public RelayCommand UpdateCustomerCommand
        {
            get;
            private set;
        }

        public RelayCommand DeleteCustomerCommand
        {
            get;
            private set;
        }
        #endregion
        
        #region "Properties"
        public const string CustomersPropertyName = "Customers";
        private ObservableCollection<Customer> _customers = null;
        public ObservableCollection<Customer> Customers
        {
            get
            {
                return _customers;
            }
            set
            {
                if (_customers == value)
                {
                    return;
                }
                 _customers = value;
                RaisePropertyChanged(CustomersPropertyName);
            }
        }


        public const string CurrentCustomerPropertyName = "CurrentCustomer";
        private Customer _currentCustomer = null;
        public Customer CurrentCustomer
        {
            get
            {
                return _currentCustomer;
            }

            set
            {
                if (_currentCustomer == value)
                {
                    _statusMessage = "";
                    return;
                }
                _currentCustomer = value;
                RaisePropertyChanged(CurrentCustomerPropertyName);
                UpdateCustomerCommand.RaiseCanExecuteChanged();
                DeleteCustomerCommand.RaiseCanExecuteChanged();
            }
        }


        public const string StatusMessagePropertyName = "StatusMessage";
        private string _statusMessage = "";
        public string StatusMessage
        {
            get
            {
                return _statusMessage;
            }

            set
            {
                if (_statusMessage == value)
                {
                    return;
                }
                _statusMessage = value;
                RaisePropertyChanged(StatusMessagePropertyName);
            }
        }
        #endregion

The Silverlight application is very simple, it has a single page with no code behind, the page creates an instance of the view model

<UserControl.Resources>
        <ViewModels:CustomersViewModel x:Key="ViewModel"/>
    </UserControl.Resources>

The main grid DataContext property is bound to the View model

<Grid x:Name="LayoutRoot" Background="White"
          DataContext="{Binding Source={StaticResource ViewModel}}" >

A combo box is used to display the customers

<ComboBox Height="23" HorizontalAlignment="Left" Margin="158,88,0,0" Name="CustomersComboBox"
                  VerticalAlignment="Top" Width="173" DisplayMemberPath="FullName"
                  ItemsSource="{Binding Path=Customers}"
                  SelectedItem="{Binding Path=CurrentCustomer, Mode=TwoWay}" />

and a bunch of Text Boxes are used to display the details of the view model CurrentCustomer property

<TextBox Height="23" HorizontalAlignment="Left" Margin="158,225,0,0" VerticalAlignment="Top" Width="219" Text="{Binding CurrentCustomer.FirstName, Mode=TwoWay}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="158,270,0,0" VerticalAlignment="Top" Width="219" Text="{Binding CurrentCustomer.LastName, Mode=TwoWay}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="158,316,0,0" VerticalAlignment="Top" Width="219" Text="{Binding CurrentCustomer.CompanyName, Mode=TwoWay}"/>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="158,366,0,0" VerticalAlignment="Top" Width="219" Text="{Binding CurrentCustomer.EmailAddress, Mode=TwoWay}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="158,416,0,0" VerticalAlignment="Top" Width="219" Text="{Binding CurrentCustomer.EmailAddress, Mode=TwoWay}" />

Two buttons “Delete” and “Updated” are bound to the view model DeleteCusotmer and UpdateCustomer commands

<Button Content="Update" Height="23" HorizontalAlignment="Left" Margin="51,480,0,0" Name="UpdateButton" VerticalAlignment="Top" Width="75"
                Command="{Binding Path=UpdateCustomerCommand}" />
        <Button Content="Delete" Height="23" HorizontalAlignment="Left" Margin="158,480,0,0" Name="DeleteButton" VerticalAlignment="Top" Width="75"
                Command="{Binding Path=DeleteCustomerCommand}" />

In the Windows Phone 7 project the View Model is defined in the application resources, cause we will have two pages that use the same view model. The first page has a list box that is bound to the view model Customers property

<ListBox Name="customersList" ItemsSource="{Binding Customers}"
                      SelectedItem="{Binding Path=CurrentCustomer, Mode=TwoWay}"
                     SelectionChanged="customersList_SelectionChanged" >
                <ListBox.ItemTemplate>
                    <DataTemplate >
                        <TextBlock Text="{Binding FullName}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

The second page displays the details of the CurrentCustomer

<StackPanel x:Name="ContentPanel" >
                <TextBlock Text="CustomerID:"/>
                <TextBlock Name="CustomerIDTextBlock" Text="{Binding CurrentCustomer.CustomerID}" />
                <TextBlock Text="First Name:"/>
                <TextBox Text="{Binding CurrentCustomer.FirstName, Mode=TwoWay}" />
                <TextBlock Text="Last Name:"/>
                <TextBox Text="{Binding CurrentCustomer.LastName, Mode=TwoWay}" />
                <TextBlock Text="Company Name:"/>
                <TextBox Text="{Binding CurrentCustomer.CompanyName, Mode=TwoWay}"/>
                <TextBlock Text="Email:"/>
                <TextBox Text="{Binding CurrentCustomer.EmailAddress, Mode=TwoWay}" />
                <TextBlock Text="Phone:"/>
                <TextBox Text="{Binding CurrentCustomer.Phone, Mode=TwoWay}" />
                <StackPanel Orientation="Horizontal">
                      <Button Content="Update" Name="UpdateButton"
                cmd:ButtonBaseExtensions.Command="{Binding UpdateCustomerCommand}"/>
                    <Button Content="Delete" Name="DeleteButton"
                cmd:ButtonBaseExtensions.Command="{Binding DeleteCustomerCommand}" />
                </StackPanel>

Here are some screen shots of the running applications

CustomersExplorer.Silverlight 

Customers List Customer Details

You can download the source code from here

Comments

TheRohan said…
Download Bubble Level Starlight v1.0
Guys,
Bubble Level, a simple Silverlight example demonstrating the use of accelerometer sensors to calculate the inclination of the device and present it as a traditional bubble level is available at developer.nokia.com.
To download, check
bit.ly/p50NYL

The application is compatible with Windows Phone 7.0, HTC 7 Mozart, LG Optimus 7, Samsung Omnia 7.
Anonymous said…
The reason why the portable library did not use ObservableCollection is because when you select to support .NET framework, silverlight and windows phone 7, that class is not supported. It is only supported if Windows Phone 7 is not checked.... (which doesn't make sense since it does support it)

Popular posts from this blog

Documentum DQL Query Custom Data Extension For SQL Server Reporting Services

Portable Class Library Projects and MVVM Light

Using taco to create Ionic projects for the Windows platform