Saturday, May 11, 2013

Windows Store Split App Template an Echtdaten anbinden

Eines der Templates um eine Windows Store App zu erstellen ist das Split App (XAML) Template.

Dieses ist sofort lauffähig und liefert euch sofort Daten. Diese sind in der Applikation allerdings “harcoded”, das ist für die meisten Zwecke nicht wirklich brauchbar. Wir wollen nun gemeinsam etwas “Dynamik” in das Template bringen und Echtdaten, die frei zur Verfügung stehen anbinden.

Dazu erstelle ich zuerst einmal eine neue Windows Store Splitt App (XAML) und nenne diese SplitAppRealData, und zur Sicherheit lasse ich diese gleich einmal laufen, um die Demodaten "zu begutachten.

SNAGHTML904531b0image

Es gibt einige JSON Quellen, die Daten frei zur Verfügung stellen, eine davon ist die Flickr API. Diese werden wir in diesem Beispiel verwenden.

http://api.flickr.com/services/feeds/photos_public.gne?tags=surf,pipeline&tagmode=all&format=json&jsoncallback=?

Der erste Schritt ist dass wir C# Klassen zu dem JSON-Resultat benötigen ,diese lassen wir uns mit Hilfe der Webseite http://json2csharp.com/ erzeugen.

Dazu postet Ihr einfach das Resultat aus dem Browser auf die Webseite. Das Resultat sind dann folgende Klassen (die ich etwas angepasst habe, damit diese den allgmeinen C#-Coding Standards entsprechen):

    [DataContract()]
public class Media
{
[DataMember(Name = "m")]
public string PreviewUrl { get; set; }
}

[DataContract()]
public class Item
{
[DataMember(Name = "title")]
public String Title { get; set; }

[DataMember(Name = "link", IsRequired = true)]
public String Link { get; set; }

[DataMember(Name = "media")]
public Media Media { get; set; }

[DataMember(Name = "date_taken")]
public string Datetaken { get; set; }

[DataMember(Name = "description")]
public string Description { get; set; }

[DataMember(Name = "published")]
public string Published { get; set; }

[DataMember(Name = "author")]
public string Author { get; set; }

[DataMember(Name = "author_id")]
public string AuthorId { get; set; }

[DataMember(Name = "tags")]
public string Tags { get; set; }
}

[DataContract()]
public class RootObject
{
[DataMember(Name = "title", IsRequired = true)]
public String Title { get; set; }

[DataMember(Name = "link", IsRequired = true)]
public String Link { get; set; }

[DataMember(Name = "items", IsRequired = false)]
public Item[] Items { get; set; }
}

Jetzt ist es an der Zeit die Daten von Flickr zu holen und in dem Template anuzeigen. Dazu muß man die LoadState Methode der ItemsPage.xaml.cs Datei anpassen. Ich habe den “Default-Call” zu SampleDataSource.GetGroups auskommentiert. Stattdessen rufen wir eine Methode LoadItems auf. Diese wiederum ruft eine neue Methode SampleDataSource.GetJsonGroups, die danach implementiert wird.

        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
//var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter);

LoadItems();
}

private async Task LoadItems()
{
string url =
"http://api.flickr.com/services/feeds/photos_public.gne?tags=surf,pipeline&tagmode=all&format=json&jsoncallback=?";
var sampleDataGroups = await SampleDataSource.GetJsonGroups(url);

this.DefaultViewModel["Items"] = sampleDataGroups;
}
 

Die Methode  GetJsonGroups erledigt die eigentliche Arbeit:



  • Den WebRequest usführen
  • Das Resultat in einen MemoryStream schreiben
  • Deserialisieren des JSON-Strings in die C# Klassen
  • Zurückgeben der Enumeration
        public static async  Task<IEnumerable<Item>> GetJsonGroups(string url)
{
try
{
var client = new HttpClient();
var result = await client.GetStringAsync(new Uri(url, UriKind.Absolute));

MemoryStream stream = new MemoryStream();
//Usually 0 and result.length, BUT
//Flickr adds a ( at the beginning and a ) at the end
stream.Write(Encoding.UTF8.GetBytes(result), 1, result.Length - 2);
stream.Position = 0;
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(RootObject));

var rootObject = (RootObject)ser.ReadObject(stream);

return rootObject.Items.ToList();
}
catch (Exception ex)
{
Debug.WriteLine("!EXCEPTION in GetJsonGroups!");
throw;
}
}

Und das war es dann auch schon, wenn man die App laufen lässt, erhält man schon ein durchaus erfreuliches Resultat:


imageimage


Um das Resultat zu verbessern, muss noch das Standard250x250ItemTemplate in StandardStyles.xaml minimal angepasst werden.

    <DataTemplate x:Key="Standard250x250ItemTemplate">
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding Media.PreviewUrl}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding Author}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>

Wie man sieht ist es relativ einfach das Standard-Template so aufzubohren, dass es sehr schnell Resultate liefert.

No comments:

CSharpCodeFormatter