Quickstart: Read data from a service (XAML)

Applies to Windows and Windows Phone

By using the Hub, Grid, or Split project template in Visual Studio, you can more effectively create an app that displays data from any service, database, or other data source. These templates share a data model that organizes information into Items and groups, and you can more easily add functionality to your app if you organize your data to follow that model.

This topic demonstrates how to create a sample app that's based on the Hub project template. The sample app shows real-time property values from a service that you can subscribe to in the Microsoft Azure Marketplace. You can also apply most of the data concepts in this topic to projects that are based on the Grid or Split template, and that use other kinds of data sources.

For clarity, this topic shows only the code or markup that highlights key points, but you can find the following complete samples in the MSDN Code Gallery:

SampleDescription
Universal Windows app that consumes data from the Azure MarketplaceUses a universal app project template to target Windows desktops and tablets as well as Windows 8.1 devices. This sample provides the C# version of the snippets that are featured in this topic.
Portable class library that consumes data from the Azure MarketplaceUses a portable class library to target Windows desktops and tablets as well as Windows 8.1 devices. This sample provides the Visual Basic version of the snippets that are featured in this topic.

 

To see how you can use Windows Communication Foundation (WCF) Data Services Client library to show data in your app, see Hub template sample that consumes data from the Azure Marketplace (Windows 8.1). None of the code from that sample appears in this topic.

As you create this app, you'll perform the following tasks:

Define your data

First, figure out what kind of data you want to show and where you can get it. The sample uses data from the Microsoft Azure Marketplace. After you find a data source, decide how you want to organize that data.

In this section, you'll learn how to do the following:

Find data

The sample uses data from the following services, which are available in the Microsoft Azure Marketplace:

ServiceDescription
PropertyDetailsAPIProvides data about a property, such as its estimated value, taxes, and the number of bedrooms and bathrooms it has.
NeighborhoodDetailsAPIProvides statistical data about the city in which the property is located, such as average tax rates, average home values, and percentage of flips.
Bing Search APIProvides search results. The sample uses this service only to obtain an image of the city the property is located in.

 

To use these services, you'll have to subscribe to them, and then you'll receive a key. Place that key in the code that you write to return results.

Organize your data into groups and items

The sample organizes the information that it retrieves from services into the following groups:

GroupItems
Primary houseprimary house
Comparable houses

comparable house # 1

comparable house # 2

comparable house # 3

comparable house # 4

comparable house # 5

comparable house # 6

 

The first group is named Primary house and contains only one item: the house that the user wants more information about. The group holds only one item because of the design of the page. Data sources might enforce how data is organized, but you can organize your groups and items however you want.

In the Comparable houses group, each item (for example, comparable house #1) contains several fields, such as Street, ZipCode, YearBuilt, and ImagePath. For a complete list of fields, see the sample.

Show data in your pages as you design them

To view sample data in your designer as you customize the layout of your pages, perform these tasks:

Add fields to the sample data classes

The data model contains a group class and an item class, and you can add your fields to those classes.

To find the group and item classes, open Solution Explorer, and then expand the Data Model node of your project. The group and item classes are in the SampleDataSource.cs or SampleDataSource.vb file.

The following code shows the group and item classes in the sample.


public class SampleDataGroup
{
    public SampleDataGroup(String uniqueId, String title)
    {
        this.UniqueId = uniqueId;
        this.Title = title;
        this.Items = new ObservableCollection<SampleDataItem>();
    }
}    

public class SampleDataItem
{
    public SampleDataItem(String uniqueId, String title, String imagePath, String street, String zipcode, String city,
        String state, String taxassessment, String yearbuilt, String lotsizesqft,
        String finishedsqft, String bathrooms, String bedrooms, String lastsolddate, String lastsoldprice,
        String zestimateamount, String zestimatevaluechange, String zestimatevaluechangeduration,
        String chartMedianCondoValue, String chartMedianHomeValue, String chartDollarsPSquareFt,
        String chartZillowHomeValueIndex, String chartHomeType, String chartOwnRent, 
        String chartHomeSize, String chartYearBuilt, string neighborhoodImage)
    {
        this.UniqueId = uniqueId;
        this.Title = title;
        this.ImagePath = imagePath;
        this.Street = street;
        this.ZipCode = zipcode;
        this.City = city;
        this.State = state;
        this.TaxAssessment = taxassessment;
        this.YearBuilt = yearbuilt;
        this.LotSizeSqFt = lotsizesqft;
        this.FinishedSqFt = finishedsqft;
        this.Bathrooms = bathrooms;
        this.Bedrooms = bedrooms;
        this.LastSoldDate = lastsolddate;
        this.LastSoldPrice = lastsoldprice;
        this.ZestimateAmount = zestimateamount;
        this.ZestimateValueChange = zestimatevaluechange;
        this.ZestimateValueChangeDuration = zestimatevaluechangeduration;
        this.ChartMedianCondoValue = chartMedianCondoValue;
        this.ChartMedianHomeValue = chartMedianHomeValue;
        this.ChartDollarsPSquareFt = chartDollarsPSquareFt;
        this.ChartZillowHomeValueIndex = chartZillowHomeValueIndex;
        this.ChartHomeType = chartHomeType;
        this.ChartOwnRent = chartOwnRent;
        this.ChartHomeSize = chartHomeSize;
        this.ChartYearBuilt = chartYearBuilt;          
        this.NeighborhoodImage = neighborhoodImage;
    }


Add sample data

As you design pages, add the data that you want your designer to display. The Hub project template contains a file that already has sample data in it. That file is named SampleData.json, and you can find it in the Data Model node of your project.

To show your data, modify SampleData.json. The following example shows sample data for only one group and one item in that group. This example doesn't show the entire sample data file.


{"Groups":[
  {
    "UniqueId": "houseItems",
    "Title": "Your Selected Home",
    "Items":
    [
      {
        "UniqueId": "houseOfInterest",
        "Title": "Your Selected Home",
        "ImagePath": "Assets/PhotoNotAvailable.jpg",
		 "Street" : "4567 Main St",
		 "ZipCode" : "98052",
		 "City" : "Buffalo",
		 "State" : "NY",
	     "TaxAssessment" : "288500.0",
	     "YearBuilt" : "2007",
		 "LotSizeSqFt" : "6969",
		 "FinishedSqFt" : "2530",
		 "Bathrooms" : "3.0",
		 "Bedrooms" : "3",
		 "LastSoldDate" : "10/11/2007",
	     "LastSoldPrice" : "444000",
		 "ZestimateAmount" : "$391,357",
		 "ZestimateValueChange" : "13977",
		 "ZestimateValueChangeDuration" : "30",
		 "ChartMedianCondoValue" : "http://www.zillow.com/app?chartType=affordability_avgCondoValue&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartMedianHomeValue" : "http://www.zillow.com/app?chartType=affordability_avgHomeValue&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartDollarsPSquareFt" : "http://www.zillow.com/app?chartType=affordability_pricePerSqft&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartZillowHomeValueIndex" : "http://www.zillow.com/app?chartType=affordability_ZindexByDistribution&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartHomeType" : "http://www.zillow.com/app?chartType=home_homeType&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartOwnRent" : "http://www.zillow.com/app?chartType=home_ownVsRent&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartHomeSize" : "http://www.zillow.com/app?chartType=home_homeSize&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "ChartYearBuilt" : "http://www.zillow.com/app?chartType=home_yearBuilt&graphType=barChart&regionId=17222&regionType=6&service=chart",
		 "NeighborhoodImage" : "http://www.hanifworld.com/Buffalo/15-Downtown%20Buffalo-New%20York.JPG"
      }
    ]
  },


Bind controls in the page to sample data

Each hub section in your HubPage.xaml file contains a reference to your sample data file. For example, the first hub section of the sample contains the following set of attribute values:


d:DataContext="{Binding Groups[0], Source={d:DesignData Source=/DataModel/SampleData.json, 
Type=data:SampleDataSource}}"


The d:DataContext property is the design-time data context. This property specifies the data that will appear in your designer as you modify pages. The property contains three attributes .

AttributePurpose
TypeThe name of the type in your project that contains the property that you'll refer to in the Binding attribute. In the sample, the name of the type is SampleDataSource. The name of the group is Groups. Notice the prefix data: in front of the term SampleDataSource. This prefix is an XML namespace that's defined as follows at the top of the XAML file for the hub page: xmlns:data="using:ZillowHub.Data". The prefix data: is just a short way to refer to that namespace.
BindingThe property you'd like to bind to. This example binds to the first group in the Groups collection.
SourceA reference to the sample data file.

 

To show data in your hub page, bind the Text property of any field to a corresponding field in your sample data file. For example, the Text property of the following field is bound to the City field of the first item in the group.


<TextBlock Style="{StaticResource SubheaderTextBlockStyle}" Grid.Row="0" Grid.Column="0" 
    Margin="0,10,0,0" TextWrapping ="Wrap" Text="{Binding Items[0].City, Mode=OneWay}"  />


Remember that the group in context is the group to which you bound the entire hub section in the previous example.

Get data from a service

So far, you've configured the project to show sample data in your designer. This configuration helps you design your pages and lays some of the groundwork for the steps that follow. However, you'll want users to view live data when they run your app. To enable this functionality, follow these steps:

Query a service

Services in the Microsoft Azure Marketplace return information as OData feeds. The easiest way for your app to consume an OData feed is to use an HttpWebRequest object. The following example uses an HTTPWebRequest object to request data from a service, and then obtains a response object that contains a JSON-formatted response.



        private async Task<dynamic> getDataFromService(string queryString) 
        { 
            try 
            { 
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(queryString); 
 
                request.Credentials = new NetworkCredential("<Your account key goes here>", 
                                    "<Your account key goes here>"); 
 
                var response = await request.GetResponseAsync().ConfigureAwait(false); 
                var stream = response.GetResponseStream(); 
 
                var streamReader = new StreamReader(stream); 
                string responseText = streamReader.ReadToEnd(); 
 
                dynamic data = JsonConvert.DeserializeObject(responseText); 
 
                return data; 
            } 
            catch (Exception) 
            { 
                return null; 
            } 
             
        } 


Populate groups and items

This example performs the following tasks to organize data into groups and items:

  • Gets service data.
  • Populates an item object by using data from the service response.
  • Adds the item to a group, and then returns that group to the caller.


        public async Task<SampleDataGroup> GetHouse(string address, string cityStateZip) 
        { 
            // Get house. 
            string queryString =  
                "https://api.datamarket.azure.com/data.ashx/Zillow/PropertyDetailsAPIs/v1/GetDeepSearchResults?" + 
                "Address='" + address + "'&CityStateAndZipCode='" + cityStateZip + 
                "'&$format=json"; 
 
            dynamic results = await getDataFromService(queryString).ConfigureAwait(false); 
 
            if (results == null) 
            { 
                return null; 
            } 
 
            dynamic house = results["d"]["results"][0]; 
 
            SampleDataGroup myGroup = new SampleDataGroup("house", ""); 
 
            SampleDataItem item = new SampleDataItem((string)house["ZillowPropertyId"], 
                                                       "", "Assets/PhotoNotAvailable.jpg", 
                                                       (string)house["Street"], 
                                                       (string)house["ZipCode"], 
                                                       (string)house["City"], 
                                                       (string)house["State"], 
                                                       (string)house["TaxAssessment"], 
                                                       (string)house["YearBuilt"], 
                                                       (string)house["LotSizeSqFt"], 
                                                       (string)house["FinishedSqFt"], 
                                                       (string)house["Bathrooms"], 
                                                       (string)house["Bedrooms"], 
                                                       (string)house["LastSoldDate"], 
                                                       (string)house["LastSoldPrice"], 
                                                       (string)house["ZestimateAmount"], 
                                                       (string)house["ZestimateValueChange"], 
                                                       (string)house["ZestimateValueChangeDuration"], 
                                                       "", 
                                                       "", 
                                                       "", 
                                                       "", 
                                                       "", 
                                                       "", 
                                                       "", 
                                                       "", 
                                                       ""); 
       
 
            // get an image of the house. 
            queryString =  
                "https://api.datamarket.azure.com/data.ashx/Zillow/PropertyDetailsAPIs/v1/GetUpdatedPropertyDetails?" + 
                "ZillowPropertyID=" + house["ZillowPropertyId"] + "&$format=json";  
 
            results = await getDataFromService(queryString).ConfigureAwait(false); 
 
            if (results != null) 
            { 
                dynamic houseImage = results["d"]["results"][0]; 
                item.ImagePath = (string)houseImage["ImageUrl"]; 
            } 
            else 
            { 
                item.ImagePath = "Assets/PhotoNotAvailable.jpg"; 
            } 
             
            // get demographic data for the city. 
 
            queryString =  
                "https://api.datamarket.azure.com/data.ashx/Zillow/NeighborhoodDataAPIs/v1/GetDemographicsByCity?" + 
                "City='" + item.City + "'&State='" + item.State + "'&$format=json"; 
 
            results = await getDataFromService(queryString).ConfigureAwait(false); 
 
            if (results != null) 
            { 
                dynamic demographics = results["d"]["results"]; 
 
                item.ChartMedianCondoValue = (string)demographics[0]["ChartUrl"]; 
                item.ChartMedianHomeValue = (string)demographics[1]["ChartUrl"]; 
                item.ChartDollarsPSquareFt = (string)demographics[2]["ChartUrl"]; 
                item.ChartZillowHomeValueIndex = (string)demographics[3]["ChartUrl"]; 
                item.ChartHomeType = (string)demographics[4]["ChartUrl"]; 
                item.ChartOwnRent = (string)demographics[5]["ChartUrl"]; 
                item.ChartHomeSize = (string)demographics[6]["ChartUrl"]; 
                item.ChartYearBuilt = (string)demographics[7]["ChartUrl"]; 
            } 
            else 
            { 
                item.ChartMedianCondoValue = "None found"; 
                item.ChartMedianHomeValue = "None found"; 
                item.ChartDollarsPSquareFt = "None found"; 
                item.ChartZillowHomeValueIndex = "None found"; 
                item.ChartHomeType = "None found"; 
                item.ChartOwnRent = "None found"; 
                item.ChartHomeSize = "None found"; 
                item.ChartYearBuilt = "None found"; 
            } 
 
 
 
            // get image of the city. 
            queryString =  
                "https://api.datamarket.azure.com/Bing/Search/v1/Image?Query='" + 
                item.City + ", " + item.State + "'&$format=json"; 
 
            results = await getDataFromService(queryString).ConfigureAwait(false); 
 
            if (results != null) 
            { 
                dynamic images = results["d"]["results"][0]; 
                item.NeighborhoodImage = (string)images["MediaUrl"]; 
            } 
            else 
            { 
                item.NeighborhoodImage = "Assets/PhotoNotAvailable.jpg"; 
            } 
             
            myGroup.Items.Add(item); 
 
            return myGroup; 
 
        } 


Enable the hub page to consume groups of data

The SampleDataSource file of your project already contains a method named GetGroupsAsync that returns groups of data to the hub page of your project. The following example modifies the GetGroupsAsync method.


        public static async Task<IEnumerable<SampleDataGroup>> GetGroupsAsync(string address, string cityStateZip) 
        { 
            // if you are returning from an item details page, then there should already be groups in the collection. 
            if (address == "") 
            { 
                return _sampleDataSource.Groups; 
            } 
            _sampleDataSource.Groups.Clear(); 
 
            var houseGroup = await _sampleDataSource.GetHouse(address, cityStateZip).ConfigureAwait(false); 
             
            if (houseGroup != null) 
            { 
                _sampleDataSource.Groups.Add(houseGroup); 
            } 
            
            // If no house is found, then there is no need to look for comparable houses and demographics. 
            if (_sampleDataSource.Groups.Count != 0) 
            { 
                var comparableGroup = await _sampleDataSource.GetComparableHouses(_sampleDataSource.Groups[0].Items[0].UniqueId).ConfigureAwait(false); 
 
                if (comparableGroup != null) 
                { 
                    _sampleDataSource.Groups.Add(comparableGroup); 
                } 
            }            
            return _sampleDataSource.Groups; 
 
        } 


Consume data in the hub page

Now you're ready to show data from groups and items in your hub page by associating groups of data with the default view model of that page. The default view model is basically a name/value pair that's associated with the page. See Navigation model (using C#/VB/C++ and XAML). You'll bind controls in your page to information that's associated with your default view model. In the sample app, users can also search for properties. In this section, you'll learn how to do the following:

Enable users to search for a property

You can add controls to an app bar so that users can search for information in the sample app. For general information about how to create and modify app bars, see Adding app bars. The following example adds two text boxes and a button to the app bar.

Note  This example is from a Windows version of the hub page. See the samples described at the beginning of this topic to view a Windows Phone version.



<Page.BottomAppBar >
    <AppBar x:Name="MyAppBar" IsOpen="true" IsSticky="True">
        <Grid>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                <TextBlock x:Name="ErrorText" FontSize="16" Foreground="#FFFD0404" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0" />
                <ProgressRing x:Name="Progress" FontSize="20" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <TextBlock Grid.Row="0" Grid.Column="0" Text="Address: " VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="18" Margin="0,0,10,0" />
                    <TextBox x:Name="AddressTextBox" Grid.Row="1" Grid.Column="0"  VerticalAlignment="Center" Width="400" HorizontalAlignment="Right" FontSize="20" />
                    <TextBlock Grid.Row="0" Grid.Column="1" Text="City, State or Zip: " VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="18" Margin="10,0" />
                    <TextBox x:Name="CityStateZipTextBox" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Width="250" HorizontalAlignment="Left" FontSize="20" Margin="10,0,0,0" />
                    <Button Grid.Row="1" Grid.Column="2" FontSize="20" Content="Search" Margin="10,0,0,0" Click="Button_Click"/>
                </Grid>
            </StackPanel>
        </Grid>
    </AppBar>
</Page.BottomAppBar>

Populate the default view model

The following example populates the default view model of the hub page when users search for a property. The code performs these actions:

  • Passes the address and city, state, or zip code to the GetGroupsAsync method of your data model and returns a collection of groups.
  • Associates the group that contains the house with a key that's named "houseItems".
  • Associates the group that contains comparable houses with a key that's named "comparableHouseItems".

This example also caches search terms, manages user interface (UI) indicators, and performs other tasks.

Note  This example is from a Windows version of the hub page. See the sample described at the beginning of this topic to view the Windows Phone version.



#region "Populate the view model by querying the data model"
private async void Button_Click(object sender, RoutedEventArgs e)
{

    if (AddressTextBox.Text == "")
    {
        ErrorText.Text = "Please enter an address";
    }
    else if (CityStateZipTextBox.Text == "")
    {
        ErrorText.Text = "Please enter city and state or a zip code";
    }
    else
    {
        Windows.Storage.ApplicationDataContainer roamingSettings =
            Windows.Storage.ApplicationData.Current.RoamingSettings;

        roamingSettings.Values["address"] = AddressTextBox.Text;
        roamingSettings.Values["cityStateZip"] = CityStateZipTextBox.Text;

        pageTitle.Text = "Searching ...";
        pageTitle.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
        titleProgressRing.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
        titleProgressRing.IsActive = true;

        var groups = await SampleDataSource.GetGroupsAsync(AddressTextBox.Text, CityStateZipTextBox.Text);

        if (groups.Count() > 0)
        {
            this.DefaultViewModel["houseItems"] = groups.ElementAt(0);
            this.DefaultViewModel["comparableHouseItems"] = groups.ElementAt(1);
            pageTitle.Text = "Real Estate Hub";
            pageTitle.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
            titleProgressRing.IsActive = false;
        }
        else
        {
            ErrorText.Text = "Please search for a property";
        }

    }
}

#endregion

Populate the default view model whenever the page loads

If a user chooses an item in the hub page, an items page appears. If you want data to appear in the hub page when users return to it, you must write code that restores the default view model. Because the groups and items in your data model maintain state between page views, you can reuse data in the groups and items that you've already populated. They're still in memory. The following example restores the values of the default view model by performing these actions:

  • If the user is opening the page for the first time, finds cached search terms.
  • If the user is opening the page by returning from an items page, calls the GetGroupsAsync method with empty search terms. That method returns groups and items that are already in memory.
  • Associates the "houseItems" and "ComparableHouseItems" keys with the appropriate groups.

Note  This example is from a Windows version of the hub page. See the sample described at the beginning of this topic to view the Windows Phone version.



#region "Populate page controls every time the page loads"
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    string address = "";
    string cityStateZip = "";
           
    // First time page is loaded. See if we've saved the results of a previous search.
    if (e.PageState == null)
    {
        Windows.Storage.ApplicationDataContainer roamingSettings =
            Windows.Storage.ApplicationData.Current.RoamingSettings;

        if (roamingSettings.Values.ContainsKey("address") &&
            roamingSettings.Values.ContainsKey("cityStateZip"))
        {
            address = roamingSettings.Values["address"].ToString();
            cityStateZip = roamingSettings.Values["cityStateZip"].ToString();
        }
        houseItemSection.Visibility = Visibility.Collapsed;
        comparableSection.Visibility = Visibility.Collapsed;
        demographicSection.Visibility = Visibility.Collapsed;
        pageTitle.Text = "Loading Page...";
        titleProgressRing.IsActive = true;
        titleProgressRing.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
        ErrorText.Text = "";
        Progress.IsActive = false;
    }
    var groups = await SampleDataSource.GetGroupsAsync(address, cityStateZip);

    ErrorText.Text = "";
    Progress.IsActive = false;
    titleProgressRing.IsActive = false;
    pageTitle.Text = "Real Estate Hub";
    houseItemSection.Visibility = Visibility.Visible;
    comparableSection.Visibility = Visibility.Visible;
    demographicSection.Visibility = Visibility.Visible;

    if (groups.Count() > 0)
    {
        this.DefaultViewModel["houseItems"] = groups.ElementAt(0);
        this.DefaultViewModel["comparableHouseItems"] = groups.ElementAt(1);
    }
    else
    {
        ErrorText.Text = "Please search for a property";
    }

}
#endregion

Bind controls on the hub page to the view model

To show data in your hub page, you must set the data context of each section to a key in your default view model. For example, if you want a hub section to show data from the group that's associated with the "houseItems" key, set the DataContext attribute of your hub section as follows: DataContext="{Binding houseItems}. In the sample, the entire section declaration appears like this:


<HubSection x:Name="houseItemSection" Width="500" x:Uid="houseItems" 
Header="Featured House" IsHeaderInteractive="True" 
DataContext="{Binding houseItems}" d:DataContext="{Binding Groups[0], 
Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}">

You can bind the controls in the section to fields in the appropriate item of a group. In this case, you bind to fields in the first item in the "houseItems" group because that group contains only one item. For example, add the following XAML code to show the name of the city where the property is located: <TextBlock Text="{Binding Items[0].City >.

Related topics

Accessing data and files
How to customize Visual Studio template data (XAML)
C#, VB, and C++ project templates
Universal Windows app that consumes data from the Azure Marketplace
Portable class library that consumes data from the Azure Marketplace
Hub template sample that consumes data from the Azure Marketplace (Windows 8.1)
Build apps that target Windows and Windows Phone by using Visual Studio
Cross-Platform Development with the Portable Class Library
Sharing code accross platforms

 

 

Show:
© 2014 Microsoft