TdZ
TdZ

Reputation: 5

Get data out of a JSON string and bind it to XAML

New to coding and new to JSON, I have this JSON string: https://feeds.citibikenyc.com/stations/stations.json

Now i'm able to get the timestamp out, but not the data like stationnames.

here is my Proxy

public class BPNewYorkCityProxy
{
    public async static Task<RootObject> GetNewYorkCity()
    {
        var http = new HttpClient();
        var response = await http.GetAsync("https://feeds.citibikenyc.com/stations/stations.json");
        var result = await response.Content.ReadAsStringAsync();
        var serializer = new DataContractJsonSerializer(typeof(RootObject));

        var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
        var data = (RootObject)serializer.ReadObject(ms);

        return data;

    }
}

[DataContract]
public class StationBeanList
{
    [DataMember]
    public int id { get; set; }
    [DataMember]
    public string stationName { get; set; }
    [DataMember]
    public int availableDocks { get; set; }
    [DataMember]
    public int totalDocks { get; set; }
    [DataMember]
    public double latitude { get; set; }
    [DataMember]
    public double longitude { get; set; }
    [DataMember]
    public string statusValue { get; set; }
    [DataMember]
    public int statusKey { get; set; }
    [DataMember]
    public int availableBikes { get; set; }
    [DataMember]
    public string stAddress1 { get; set; }
    [DataMember]
    public string stAddress2 { get; set; }
    [DataMember]
    public string city { get; set; }
    [DataMember]
    public string postalCode { get; set; }
    [DataMember]
    public string location { get; set; }
    [DataMember]
    public string altitude { get; set; }
    [DataMember]
    public bool testStation { get; set; }
    [DataMember]
    public string lastCommunicationTime { get; set; }
    [DataMember]
    public string landMark { get; set; }
}

[DataContract]
public class RootObject
{
    [DataMember]
    public string executionTime { get; set; }
    [DataMember]
    public List<StationBeanList> stationBeanList { get; set; }
}

And here is my code on my XAML, as said the timestamp get's but now i want more, like station name's and available spots.

private async void GetData_Click(object sender, RoutedEventArgs e)
    {
        RootObject nycParking = await BPNewYorkCityProxy.GetNewYorkCity();

        // how to get a stationname .. my proxy creates a list, does it?... 
        //myStationName.Text = 

        // Well this works
        myTimeStamp.Text = nycParking.executionTime.ToString();

    }

How to do this? thanks in advance

Upvotes: 0

Views: 2311

Answers (2)

AlexDrenea
AlexDrenea

Reputation: 8039

You are correct that the proxy returns a list

public List<StationBeanList> stationBeanList { get; set; }

Since you have more than one list, you cannot show that in a single Text field. So you need a list

<ListBox x:Name="stations"/>

Next, you need to configure what each element in the list will look like. In XAML that is called a DataTemplate. So let's configure one for our list:

<ListBox x:Name="stations">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding stationName}" Margin="5"/>
                <TextBlock Text="{Binding availableDocks}" Margin="5"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Finally, to populate the list with the results, in your code-behind file you need to assign the ItemsSource property of the list to the data you get from the server:

private async void GetData_Click(object sender, RoutedEventArgs e)
{
    RootObject nycParking = await BPNewYorkCityProxy.GetNewYorkCity();

    // how to get a stationname .. my proxy creates a list, does it?... 
    stations.ItemsSource = nycParking.stationBeanList;
    // Well this works
    myTimeStamp.Text = nycParking.executionTime.ToString();
}

This is all, and it should work for your simple example. However, you'll probably have to work on the XAML template and make it look nicer. There are a lot of concepts that you need to work on and improve the code with:

  • Creating a view model out of your Data model
  • Use Data Binding to link the ListBox itemssource to the result set (MVVVM)
  • Use {x:Bind} instead of the old {Binding} - optional, for performance

Upvotes: 0

Swagata Prateek
Swagata Prateek

Reputation: 1086

The RootObject wraps the list stationBeanList and I presume that's what you want.

private async void GetData_Click(object sender, RoutedEventArgs e)
{
    RootObject nycParking = await BPNewYorkCityProxy.GetNewYorkCity();

    foreach (var station in nycParking.stationBeanList)
    {
        // Access all of them here may be?
        Console.WriteLine(station.stationName);
    } 

    // Well this works
    myTimeStamp.Text = nycParking.executionTime.ToString();

}

But if you want a simpler workflow, I'd like to suggest using Json.net if it's not a problem for you

public class BPNewYorkCityProxy
{
    public static async Task<RootObject> GetNewYorkCity()
    {
        var http = new HttpClient();
        var response = await http.GetAsync("https://feeds.citibikenyc.com/stations/stations.json");
        var result = await response.Content.ReadAsStringAsync();
        var data = JsonConvert.DeserializeObject<RootObject>(result);
        return data;
    }
}  
public class StationBeanList
{
    public int id { get; set; }
    public string stationName { get; set; }
    public int totalDocks { get; set; }
    public double latitude { get; set; }
    public double longitude { get; set; }
    public string statusValue { get; set; }
    public int statusKey { get; set; }
    public int availableBikes { get; set; }
    public string stAddress1 { get; set; }
    public string stAddress2 { get; set; }
    public string city { get; set; }
    public string postalCode { get; set; }
    public string location { get; set; }
    public string altitude { get; set; }
    public bool testStation { get; set; }
    public string lastCommunicationTime { get; set; }
    public string landMark { get; set; }
}

public class RootObject
{
    public string executionTime { get; set; }
    public List<StationBeanList> stationBeanList { get; set; }
}

Upvotes: 1

Related Questions