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
    Private Shared _baseUri As New Uri("ms-appx:///")

    Public Sub New(uniqueId As String, title As String)
        Me.UniqueId = uniqueId
        Me.Title = title
        Me.Items = New ObservableCollection(Of SampleDataItem)()
    End Sub
End Class

Public Class SampleDataItem
    Private Shared _baseUri As New Uri("ms-appx:///")

    Public Sub New(uniqueId As String, title As String, imagePath As String, street As String, zipcode As String, _
        city As String, state As String, taxassessment As String, yearbuilt As String, lotsizesqft As String, _
        finishedsqft As String, bathrooms As String, bedrooms As String, lastsolddate As String, _
        lastsoldprice As String, zestimateamount As String, zestimatevaluechange As String, _
        zestimatevaluechangeduration As String, chartMedianCondoValue As String, chartMedianHomeValue As String, _
        chartDollarsPSquareFt As String, chartZillowHomeValueIndex As String, chartHomeType As String, _
        chartOwnRent As String, chartHomeSize As String, chartYearBuilt As String, neighborhoodImage As String)
            Me.UniqueId = uniqueId
            Me.Title = title
            Me.ImagePath = imagePath
            Me.Street = street
            Me.ZipCode = zipcode
            Me.City = city
            Me.State = state
            Me.TaxAssessment = taxassessment
            Me.YearBuilt = yearbuilt
            Me.LotSizeSqFt = lotsizesqft
            Me.FinishedSqFt = finishedsqft
            Me.Bathrooms = bathrooms
            Me.Bedrooms = bedrooms
            Me.LastSoldDate = lastsolddate
            Me.LastSoldPrice = lastsoldprice
            Me.ZestimateAmount = zestimateamount
            Me.ZestimateValueChange = zestimatevaluechange
            Me.ZestimateValueChangeDuration = zestimatevaluechangeduration
            Me.ChartMedianCondoValue = chartMedianCondoValue
            Me.ChartMedianHomeValue = chartMedianHomeValue
            Me.ChartDollarsPSquareFt = chartDollarsPSquareFt
            Me.ChartZillowHomeValueIndex = chartZillowHomeValueIndex
            Me.ChartHomeType = chartHomeType
            Me.ChartOwnRent = chartOwnRent
            Me.ChartHomeSize = chartHomeSize
            Me.ChartYearBuilt = chartYearBuilt
            Me.NeighborhoodImage = neighborhoodImage
        End Sub
End Class


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 Function getDataFromService(queryString As String) As Task(Of JObject) 
            Try 
                Dim request As HttpWebRequest = DirectCast(WebRequest.Create(queryString), HttpWebRequest) 
 
                request.Credentials = New NetworkCredential("<Your account key goes here>", 
                                                            "<Your account key goes here>") 
 
                Dim response = Await request.GetResponseAsync().ConfigureAwait(False) 
                Dim stream = response.GetResponseStream() 
 
                Dim streamReader = New StreamReader(stream) 
                Dim responseText As String = streamReader.ReadToEnd() 
 
                Dim data As JObject = JsonConvert.DeserializeObject(responseText) 
 
                Return data 
 
            Catch generatedExceptionName As Exception 
                Return Nothing 
 
            End Try 
 
        End Function 


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 Function GetHouse(address As String, cityStateZip As String) As Task(Of SampleDataGroup) 
            ' Get house. 
            Dim queryString As String = "https://api.datamarket.azure.com/data.ashx/Zillow/PropertyDetailsAPIs/v1/GetDeepSearchResults?" & "Address='" & address & "'&CityStateAndZipCode='" & cityStateZip & "'&$format=json" 
 
            Dim results As JObject = Await getDataFromService(queryString).ConfigureAwait(False) 
 
            If results Is Nothing Then 
                Return Nothing 
            End If 
 
            Dim house = results("d")("results")(0) 
 
            Dim myGroup As New SampleDataGroup("house", "") 
 
 
            Dim item As New SampleDataItem(house("ZillowPropertyId").ToString(), "", "Assets/PhotoNotAvailable.jpg", house("Street").ToString(), house("ZipCode").ToString(), house("City").ToString(), _ 
                house("State").ToString(), house("TaxAssessment").ToString(), house("YearBuilt").ToString(), house("LotSizeSqFt").ToString(), house("FinishedSqFt").ToString(), house("Bathrooms").ToString(), _ 
                house("Bedrooms").ToString(), house("LastSoldDate").ToString(), house("LastSoldPrice").ToString(), house("ZestimateAmount").ToString(), house("ZestimateValueChange").ToString(), house("ZestimateValueChangeDuration").ToString(), _ 
                "", "", "", "", "", "", _ 
                "", "", "") 
 
 
            ' get an image of the house. 
            queryString = ("https://api.datamarket.azure.com/data.ashx/Zillow/PropertyDetailsAPIs/v1/GetUpdatedPropertyDetails?" & "ZillowPropertyID=") + house("ZillowPropertyId").ToString() & "&$format=json" 
 
            results = Await getDataFromService(queryString).ConfigureAwait(False) 
 
            If results IsNot Nothing Then 
                Dim houseImage = results("d")("results")(0) 
                item.ImagePath = houseImage("ImageUrl").ToString() 
            Else 
                item.ImagePath = "Assets/PhotoNotAvailable.jpg" 
            End If 
 
            ' 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 IsNot Nothing Then 
                Dim demographics = results("d")("results") 
 
                item.ChartMedianCondoValue = demographics(0)("ChartUrl").ToString() 
                item.ChartMedianHomeValue = demographics(1)("ChartUrl").ToString() 
                item.ChartDollarsPSquareFt = demographics(2)("ChartUrl").ToString() 
                item.ChartZillowHomeValueIndex = demographics(3)("ChartUrl").ToString() 
                item.ChartHomeType = demographics(4)("ChartUrl").ToString() 
                item.ChartOwnRent = demographics(5)("ChartUrl").ToString() 
                item.ChartHomeSize = demographics(6)("ChartUrl").ToString() 
                item.ChartYearBuilt = demographics(7)("ChartUrl").ToString() 
            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" 
            End If 
 
 
 
            ' 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 IsNot Nothing Then 
                Dim images = results("d")("results")(0) 
                item.NeighborhoodImage = images("MediaUrl").ToString() 
            Else 
                item.NeighborhoodImage = "Assets/PhotoNotAvailable.jpg" 
            End If 
 
            myGroup.Items.Add(item) 
 
            Return myGroup 
 
        End Function 

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 Shared Async Function GetGroupsAsync(address As String, cityStateZip As String) As Task(Of IEnumerable(Of SampleDataGroup)) 
            ' if you are returning from an item details page, then there should already be groups in the collection. 
            If address = "" Then 
                Return _sampleDataSource.Groups 
            End If 
            _sampleDataSource.Groups.Clear() 
 
            Dim houseGroup = Await _sampleDataSource.GetHouse(address, cityStateZip).ConfigureAwait(False) 
 
            If houseGroup IsNot Nothing Then 
                _sampleDataSource.Groups.Add(houseGroup) 
            End If 
 
            ' If no house is found, then there is no need to look for comparable houses and demographics. 
            If _sampleDataSource.Groups.Count <> 0 Then 
                Dim comparableGroup = Await _sampleDataSource.GetComparableHouses(_sampleDataSource.Groups(0).Items(0).UniqueId).ConfigureAwait(False) 
 
                If comparableGroup IsNot Nothing Then 
                    _sampleDataSource.Groups.Add(comparableGroup) 
                End If 
            End If 
            Return _sampleDataSource.Groups 
            Return Nothing 
        End Function 


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 Sub Button_Click(sender As Object, e As RoutedEventArgs)

    If AddressTextBox.Text = "" Then
        ErrorText.Text = "Please enter an address"
    ElseIf CityStateZipTextBox.Text = "" Then
        ErrorText.Text = "Please enter city and state or a zip code"
    Else
        ' save parameters.
        Dim roamingSettings As Windows.Storage.ApplicationDataContainer = 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

        Dim groups = Await SampleDataSource.GetGroupsAsync(AddressTextBox.Text, CityStateZipTextBox.Text)

        If groups.Count > 0 Then
            Me.DefaultViewModel("houseItems") = groups.ElementAt(0)
            Me.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"

        End If
    End If
End Sub

#End Region


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.



Private Async Sub NavigationHelper_LoadState(sender As Object, e As Common.LoadStateEventArgs)
    Dim address As String = ""
    Dim cityStateZip As String = ""

    ' First time page is loaded. See if we've saved the results of a previous search.
    If e.PageState Is Nothing Then
        Dim roamingSettings As Windows.Storage.ApplicationDataContainer = Windows.Storage.ApplicationData.Current.RoamingSettings

        If roamingSettings.Values.ContainsKey("address") AndAlso roamingSettings.Values.ContainsKey("cityStateZip") Then
            address = roamingSettings.Values("address").ToString()
            cityStateZip = roamingSettings.Values("cityStateZip").ToString()
        End If
        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
    End If
    Dim 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 Then
        Me.DefaultViewModel("houseItems") = groups.ElementAt(0)
        Me.DefaultViewModel("comparableHouseItems") = groups.ElementAt(1)
    Else
        ErrorText.Text = "Please search for a property"
    End If



End Sub


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:
© 2015 Microsoft