App-Entwicklung für Windows Phone 8–Part 3

Von Maximilian Sachs (Gastblogger) Autor Feed 6. February 2013 07:00

Dies ist der 3. Teil unserer Serie, in der wir das GeoFotoalbum App entwickeln. Dieser Artikel steht ganz im Zeichen des Map-Control. Das heißt, im Fokus stehen diesmal folgende Punkte:

 

Inhalt des Artikels

  • Hinzufügen eines Map-Control zu unserem Projekt
  • Anzeigen der aktuellen Position
  • Anzeigen der Bildpositionen
  • Berechnen von Routen von der aktuellen Position zu einer gewählten Bildposition

image

 

Hinzufügen der Karte

Nachdem wir im Hintergrund bereits alle Informationen (Längengrad und Breitengrad) besitzen, die wir für das Zeichnen der Bildpositionen benötigen, werden wir nun als erstes ein Kartenelement auf der MainPage platzieren, mit dem wir dem User zeigen können, wo die Bilder geschossen wurden. Wie schon zuvor, ist die einfachste Methode auch hier das Öffnen der Toolbox und das Ziehen des Controls an die geeignete Stelle. Diese „Drag and Drop“-Operation kann im Übrigen auch in das XAML-Codefenster erfolgen und dieses ist auch unser Ziel.

In den vorherigen Blogeinträgen haben wir uns hier noch eine kleine Baustelle hinterlassen, die wir damals mit <!--TODO: Implementiere Karte im Teil 3--> markiert hatten. Genau dieses Kommentar löschen wir nun und ziehen an den entstehenden Freiraum unser „Map“-Control.

Damit die Karte auch den gesamten Freiraum ausfüllt, werden wir hier, wie auch schon zuvor bei der Liste, wieder die Attribute HorizontalAlignment und VerticalAlignment jeweils auf „Stretch“ setzen. Zudem geben wir dem Control den Namen „Map“. Wenn nun alles funktioniert hat, dann sollte die entstandene Zeile in etwa so aussehen:

<Controls:Map HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="Map" />

image Tipp: Das Hinzufügen der Karte über die Toolbox hat zudem den entscheidenden Vorteil, dass wir uns nicht um die Einbindung der Namespaces für die Karte kümmern müssen. Sollte die Karte manuell hinzugefügt worden sein, so muss in der Definition der PhoneApplicationPage am Beginn der Datei die Namespace-Liste noch um folgenden Eintrag erweitert werden:

xmlns:Controls="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"

Wenn wir schon einmal hier sind, geben wir auch direkt dem PivotItem der Karte und dem PivotControl selbst einen Namen (der Grund dafür wird etwas später im Artikel enthüllt werden Winking smile ). Die beiden Definitionen sollten dann in etwa so aussehen:

<phone:Pivot Title="Fotos" HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" Name="PivotControl">

<phone:PivotItem CacheMode="{x:Null}" Header="Karte" Name="MapItem">

Soweit, so gut. Wir könnten nun die App ausführen und einmal testen, was sich so mit der Karte machen lässt. Dafür fehlt uns aber leider noch – wer hätte es geahnt – das Setzen einer Capability, damit es der App auch erlaubt ist, das Kartencontrol zu verwenden. Um diese zu setzen, öffnen wir ein weiteres Mal die WMAppManifest-Datei, wechseln in den Capabilities-Reiter und aktivieren dort die Capability ID_CAP_MAP.

Jetzt steht einem kurzen Testlauf nichts mehr im Wege. Bei einer Ausführung der App, sollten wir nun im zweiten Reiter (Karte) unsere neue Karte bewundern können. Zugegeben, viel damit machen lässt sich noch nicht, aber darum kümmern wir uns nun direkt im Anschluss! Smile

 

Anzeigen der aktuellen Position

Um die aktuelle Position in unserer Karte anzeigen zu können, müssen wir zu allererst einige weitere Membervariablen zu unserer MainPage-Klasse hinzufügen, welche sich im Code-Behind-File der MainPage befindet.

Wir erweitern also die Liste der privaten Membervariablen um folgende Einträge:

MapLayer positionLayer = new MapLayer();
GeoCoordinate currentPosition = new GeoCoordinate();

Als nächstes registrieren wir den Positionlayer bei der Karte und setzen im selben Atemzug auch gleich noch ein halbwegs schönes Zoom-Level, damit wir nicht erst aus dem Orbit herunterzoomen müssen, um etwas zu erkennen. Winking smile

Dies tun wir im Konstruktor der Klasse (MainPage). An dessen Ende fügen wir folgende beiden Zeilen, um unser Ziel zu erreichen:

Map.Layers.Add(positionLayer);
Map.ZoomLevel = 12;

Soweit, so gut. Damit wir nun jedoch auch unseren eigenen Standpunkt auf der Karte sehen können, müssen wir die PositionChanged-Methode des Watchers ein wenig erweitern. Mit dem folgenden Code löschen wir zum einen alle alten Markierungen auf der Karte, aktualisieren unseren neu hinzugefügten Klassenmember (currentPosition), zentrieren die Position auf der Karte und zeichnen einen kleinen blauen Kreis an die Stelle, an der wir uns befinden:

// Alte Einträge entfernen
positionLayer.Clear();

// Unsere Position aktualisieren
currentPosition.Latitude = e.Position.Location.Latitude;
currentPosition.Longitude = e.Position.Location.Longitude;
Map.Center = currentPosition;

// Positionsmarker für unsere eigene Position erstellen
Ellipse circle = new Ellipse();
circle.Fill = new SolidColorBrush(Colors.Blue);
circle.Height = 20;
circle.Width = 20;
circle.Opacity = 50;

// Overlay erzeugen und dem Layer der Karte hinzufügen
MapOverlay overlay = new MapOverlay();
overlay.Content = circle;
overlay.GeoCoordinate = currentPosition;
overlay.PositionOrigin = new Point(0.5, 0.5);
positionLayer.Add(overlay);

In dem erzeugten Overlay befindet sich hierbei unser Kreis, welcher durch eben diesen Container dem positionLayer der Karte hinzugefügt wird.

Nach diesem Stückchen Code sollte uns unsere Karte nun die Position des Geräts wunderschön zentriert mit einem kleinen blauen Kreis anzeigen können. Einmal kurz testen, sehr schön! Winking smile

image

 

Anzeigen der Bildpositionen

Ganz analog zu der gerade implementierten Positionsanzeigen implementieren wir nun auch Indikatoren für die Aufnahmeposition unserer Bilder. Da wir dies jedoch pro Bild tun müssen, bietet es sich an, das Erstellen des Markers direkt in der Foto-Klasse zu erledigen. Wir wechseln also in Foto.cs und erstellen dort eine neue Methode „AddToLayer“ mit folgendem Inhalt:

public void AddToLayer(MapLayer layer)
{
  // Positionsmarker für die Position des Bildes erstellen
  Ellipse circle = new Ellipse();
  circle.Fill = new SolidColorBrush(Colors.Red);
  circle.Height = 20;
  circle.Width = 20;
  circle.Opacity = 50;

  // Overlay erzeugen und dem Layer der Karte hinzufügen
  MapOverlay overlay = new MapOverlay();
  overlay.Content = circle;
  overlay.GeoCoordinate = new GeoCoordinate(breitengrad, laengengrad);
  overlay.PositionOrigin = new Point(0.5, 0.5);
  layer.Add(overlay);
}

Wie man hier sehr schön sehen kann, machen wir im Grunde nichts anderes als vorhin. Die einzigen beiden Unterschiede finden sich in der Farbe des Kreises (dieser ist diesmal Rot) und in dem Setzen der Koordinaten (denn hier verwenden wir nun die, die wir zuvor aus dem Bild extrahiert haben).

Wir wechseln nun schnell noch einmal zurück in die Update-Methode des Watchers und fügen der foreach-Schleife eine zweite Zeile hinzu, sodass diese nun folgendermaßen aussieht:

foreach (Foto foto in fotos)
{
  foto.updatePosition(e.Position.Location);
  foto.AddToLayer(positionLayer);
}

Nun aktualisieren und zeichnen wir auch die Position eines jeden Bildes auf der Karte!

image

 

Routenberechnung

Als kleines Bonusfeature implementieren wir nun noch eine Routenberechnung, damit man auch die Möglichkeit hat, sich zu den aufgenommenen Bildern navigieren zu lassen. Sobald also ein Bild berührt wird, generieren wir uns eine Route vom momentanen Standpunkt zum Aufnahmeort des Bildes und zeichnen diese auf der Karte ein.

Um dies zu erreichen, müssen wir uns zuerst eine Methode überlegen, mittels derer wir feststellen können, wann ein Bild berührt wurde. Dank XAML brauchen wir dafür nicht allzu viel tun, ein Anlegen eines Tap-Events im Image-Element genügt vollkommen und Visual Studio erstellt uns direkt im Code-Behind-File die passende Methode. Die Definition des Image-Elementes sollte nun in etwa so aussehen:

<Image Grid.Column="0" Source="{Binding Vorschaubild}" 
    HorizontalAlignment="Center" VerticalAlignment="Center" Tap="Image_Tap" />

Im Code-Behind-File sollte sich nun eine Methode Namens „Image_Tap“ befinden, welche wir folgendermaßen füllen:

// Foto aus dem DataContext extrahieren
Foto foto = (sender as Image).DataContext as Foto;
      
// Start- und Endpunkt festsetzen
List<GeoCoordinate> coordinates = new List<GeoCoordinate>();
coordinates.Add(currentPosition);
coordinates.Add(new GeoCoordinate(foto.Breitengrad, foto.Laengengrad));

// RouteQuery basteln, die uns die genaue Route berechnet
routeQuery = new RouteQuery();
routeQuery.Waypoints = coordinates;
routeQuery.QueryCompleted += routeQuery_QueryCompleted;
routeQuery.QueryAsync();

Der springende Punkt ist hierbei das Erstellen der Route-Query, welcher wir eine Koordinatenliste (gefüllt mit unseren eigenen Standpunktkoordinaten und denen des Bildes) und eine Callback-Methode übergeben. Damit diese nun auch noch bei Beendigung der Routenberechnung ausgeführt wird, müssen wir sie zuerst einmal erstellen.

Bevor wir dies jedoch tun, fehlen uns noch die beiden Membervariablen von oben in der Klasse. Wir fügen der MainPage also folgende Felder hinzu:

RouteQuery routeQuery = null;
MapRoute route = null;

Jetzt legen wir eine neue Methode namens „routeQuery_QueryCompleted“ an und fügen ihr folgenden Code hinzu, um die Route auf unsere Karte zu überführen:

void routeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
  if (e.Error == null)
  {
    // Etwaige alte Routen entfernen
    if (route != null)
    {
      Map.RemoveRoute(route);
    }

    // Zur Karte hinzufügen und Query freigeben
    route = new MapRoute(e.Result);
    Map.AddRoute(route);
    routeQuery.Dispose();

    // Zur Karte navigieren, damit der User die Route sieht
    Map.Center = currentPosition;
    PivotControl.SelectedItem = MapItem;
  }
}

Die Route bekommen wir dabei praktischerweise verpackt als Result in dem e-Parameter. Mittels AddRoute können wir diese dem Map-Control ganz einfach hinzufügen.

Damit der User nun merkt, dass sich etwas getan hat, möchten wir noch gerne die Page des Pivotcontrols auf die Kartenseite ändern und zentrieren erneut auf den momentanen Standpunkt, damit wir nicht irgendwo ins Nirgendwo zeigen (dies war übrigens der Grund für die Namensgebung der beiden Controls vorhin – ohne Namen hätten wir diese nicht aus dem Code heraus adressieren können). Winking smile

Vorausgesetzt es hat nun alles funktioniert, sollten wir die Route zum angetippten Bild gut sichtbar aus der Karte entnehmen können. Wir starten unsere App noch ein letztes Mal und siehe da, wir haben nun eine Routenberechnung! Smile

image

 

Blogeinträge und Ressourcen

Am Ende dieses Blogeintrags verweisen wir noch einmal auf eine Liste der bisher veröffentlichten Blogeinträge:

und auf den Link zum Download der aktuellen Projektversion (beinhaltet den kompletten Stand der App bis zum Ende dieses Eintrags):

Zu guter Letzt

Erneut bedanken wir uns für Eure Aufmerksamkeit und das Durchhalten bis zum Schluss. Hoffentlich dürfen wir euch auch beim nächsten Teil wieder begrüßen! In diesem Sinne: Danke noch einmal und bis zum nächsten Mal! Smile

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

Datenschutzhinweis: Sie stimmen durch "Kommentar speichern" der Speicherung Ihrer Angaben durch Microsoft Österreich für die Beantwortung der Anfrage zu. Sie erhalten dadurch keine unerwünschten Werbezusendungen. Ihre Emailadresse wird auf Ihren Wunsch dazu verwendet Sie über neue Kommentare zu informieren.

Microsoft respektiert den Datenschutz. Datenschutz & Cookies

Entwickler Wettbewerbe:

Wettbewerbe

Entwickler Events:

Developer Events

App für Windows 8, Windows Phone oder/und Azure? Diese Events zeigen Dir, wie es geht:

Mehr Information

Aktuelle Downloads

Visual Studio Downloads
 
Windows Azure Free Trial
Instagram
CodeFest.at on Facebook

Datenschutz & Cookies · Nutzungsbedingungen · Impressum · Markenzeichen
© 2013 Microsoft. Alle Rechte vorbehalten · BlogEngine.NET 2.7.0.0 · Diese Website wird für Microsoft von atwork gehostet.
powered by atwork