C# WPF, HTML Datei in webBroser laden

Mathias09876

Ensign
Registriert
Nov. 2010
Beiträge
235
Hallo zusammen,

ich habe hier eine WPF Anwendung, die Kartenausschnitte von GoogleMaps anzeigen soll. Bisher hatte ich das über statische Karten gelöst, wollte nun aber auch die Möglichkeit implementieren die Karten dynamisch verschieben zu können. Dazu habe ich mir mal die API von Google angeschaut und eine kleine HTML Datei gebastelt, die ein kurzs JavaScript enthält, welches die Karte anzeigt (eine Adresse sucht und dann einen Marker auf diese Adresse setzt).

Die HTML Datei lade ich dann über
Code:
webBrowser.Navigate(new URI(@"H:\Test.html"))

und bekomme so die Karte angezeigt.

Das funktioniert soweit auch, nur müsste ich jetzt die Adresse abhängig von Eingaben im Programm bestimmen. Die einzige Lösung, die mir jetzt einfällt ist die bestehende HTML Datei öffnen und die betreffende Zeile, in der die Adresse steht mit einer neuen zu ersetzen, die Datei speichern und wieder im webBrowser zu öffnen.

Gibt es hierfür eine elegantere Lösung? Irgendwie erscheint mir das schon ziemlich schief ^^ Falls jemand noch eine Methode kennt dynamische Google Maps Karten in einer WPF Anwendung zu laden bin ich für Ideen dankbar :)

Grüße
Mathias
 
Ich weiß nicht wie weit inzwischen die Fähigkeiten des WPF Browser-Controls sind... aber mit dem von WindowsForms (ist auch in WPF einbindbar) hast du vollen Zugriff aufs DOM und JavaScript und kannst vom Programm aus selber das HTML ändern, JS-Funktionen starten usw.
 
Hmm nur irgendwie erschien mir das bisher auch ziemlich unsauber in einer WPF Anwendung WinForms zu verwenden oder bilde ich mir das jetzt nur ein? ^^
 
holy schrieb:
Meiner Meinung nach ist dein Lösungweg nicht grade optimal.

Ne das ist er allerdings nicht :D aber er funktioniert ;)

Das Problem ist, dass ich mit den API's in C# nix anfangen kann bzw. GMaps.net (der zweite link) bisher nur statische Karten unterstützt aber keine dynamischen.

Soweit ich das verstanden habe brauche ich fürs dynamische JS um eben die Google API zu nutzen. Damit ich mit dem JS in meinem C# Programm was anfangen kann dachte ich an den webBrowser. Oder hab ich da jetzt was falsch verstanden?
 
Um ehrlich zu sein, war das mehr so ein Schlaumeier-Post :)
Hab mit den APIs noch nicht gearbeitet, aber du hast Glück. Da ich eben das Achievement-Addon für Visual-Studio gefunden habe und jetzt coden muss, bastel ich mal :)

PS.
Würde mich nicht drauf verlassen, dass ich dir in den nächsten 5min. fertigen Code liefere :)
 
Das Prinzip ist richtig. Aber wenn sich seit der Zeit wo ich das mal in Händen hatte (ca 1-2 Jahre her) nichts großartiges geändert hat ist das WPF Browser Control für die Tonne... wir haben damals dann auf das aus WinForms gesetzt. Hat gut zusammen harmoniert, gab eigentlich keine Probleme. Und die Schnittstelle gibt dir dann vollen Zugriff auf alles was in dem Browser läuft. (Cookies lesen/schreiben, DOM verändern, JavaScript aufrufen oder C#-Methoden auf EventHandler z.B. von <button>s hängen...)
 
holy schrieb:
Würde mich nicht drauf verlassen, dass ich dir in den nächsten 5min. fertigen Code liefere :)

Bin eh erst in ca 4h daheim ;)

Falls du aber auf etwas hilfreichs stößt, bin ich froh, wenn du mich teilhaben lässt :)

Grüße
 
Warum verwendest keinen QueryString?

Also anstatt: webBrowser.Navigate(new URI(@"H:\Test.html"))
verwendest so etwas ähnliches:
webBrowser.Navigate(new URI(@"H:\Test.html?Plz=22200&Adress=Musterstraße 24")) oder wie auch immer du es zusammenbauen willst. Und dann per JavaScript oder was auch immer den QueryString auslesen und damit die Google API füttern.
 
Also,

ich glaube, ich muss ein wenig zurückrudern bzgl. DOM ;)
Allerdings hab ich es ein wenig anders gelöst und baue das komplette Dokument selbst. Das hat den Vorteil, dass du nicht erst groß suchen musst. Der Code unten zeigt dir nur beispielhaft, wie es geht, du kannst das ganze nach belieben erweitern.

Falls du das ganze lieber mit Flash machen möchtest, hier findest du ein Howto von Google dazu.

So, nun der Code.
Wie gesagt, ich baue das Dokument selber zusammen und nutze die Javascript API. Für die Suche verwende ich den Web-Service von Google.

Mein Button-Click:
Code:
private void OnBtnClick( object sender, RoutedEventArgs e )
{
    Location aachen = Location.SearchGoogleMaps( "aachen" );
    MapStream maps = new MapStream( "Your-API-Key-Here" ) { MapType = MapTypes.Hybrid };
    string dom = maps.GetDOMForLocation( aachen );
    browser.NavigateToString( dom );
}

Die Klasse Location:
Code:
namespace MapsTesting
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Xml.Linq;

    public sealed class Location
    {
        #region Constructors and Destructors

        private Location()
        {
        }

        #endregion

        #region Public Properties

        public string FormattedAddress { get; private set; }

        public double Latitude { get; private set; }

        public double Longitude { get; private set; }

        #endregion

        #region Public Methods

        public static Location SearchGoogleMaps( string location )
        {
            if ( string.IsNullOrEmpty( location ) )
            {
                throw new ArgumentNullException( "location" );
            }

            string uri = string.Format(
                "http://maps.googleapis.com/maps/api/geocode/xml?address={0}&sensor=false", location );
            WebRequest request = WebRequest.Create( uri );
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream stream = response.GetResponseStream();

            StreamReader reader = new StreamReader( stream, Encoding.UTF8 );
            string data = reader.ReadToEnd();

            stream.Close();
            stream.Dispose();
            response.Close();

            XDocument doc = XDocument.Parse( data );
            if ( !doc.Descendants( "status" ).First().Value.Equals( "OK" ) )
            {
                throw new Exception();
            }

            XElement locElem = doc.Descendants( "location" ).First();
            string latVal = locElem.Descendants( "lat" ).First().Value;
            string lngVal = locElem.Descendants( "lng" ).First().Value;
            string address = doc.Descendants( "formatted_address" ).First().Value;

            NumberFormatInfo numberFormat = new NumberFormatInfo { NumberDecimalSeparator = "." };
            Location loc = new Location
                {
                    Latitude = double.Parse( latVal, numberFormat ), 
                    Longitude = double.Parse( lngVal, numberFormat ), 
                    FormattedAddress = address
                };

            return loc;
        }

        #endregion
    }
}

Und letztlich der "MapStream":
Code:
namespace MapsTesting
{
    using System;
    using System.Globalization;
    using System.Text;

    public enum MapTypes
    {
        Roadmap, 
        Satellite, 
        Hybrid, 
        Terrain
    }

    public sealed class MapStream
    {
        #region Constants and Fields
        
        private readonly string _apiKey;

        #endregion

        #region Constructors and Destructors
        
        public MapStream( string apiKey )
        {
            if ( string.IsNullOrEmpty( apiKey ) )
            {
                throw new ArgumentNullException( "apiKey" );
            }

            _apiKey = apiKey;
        }

        #endregion

        #region Public Properties

        public MapTypes MapType { get; set; }

        public bool UseSensor { get; set; }

        public bool UserScalable { get; set; }

        #endregion

        #region Public Methods

        public string GetDOMForLocation( Location location )
        {
            StringBuilder bld = new StringBuilder();
            NumberFormatInfo numberFormat = new NumberFormatInfo { NumberDecimalSeparator = "." };

            bld.Append( "<!DOCTYPE html>" );
            bld.Append( "<html><head>" );
            bld.Append(
                string.Format(
                    "<meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable={0}\" />", 
                    UserScalable ? "yes" : "no" ) );
            bld.Append( "<style type=\"text/css\">" );
            bld.Append( "html { height: 100% }" );
            bld.Append( "body { height: 100%; margin: 0; padding: 0 }" );
            bld.Append( "#map_canvas { height: 100% }" );
            bld.Append( "</style>" );
            bld.Append( "<script type=\"text/javascript\"" );
            bld.Append(
                string.Format(
                    "src=\"http://maps.googleapis.com/maps/api/js?{0}&sensor={1}\">", 
                    _apiKey, 
                    UseSensor ? "true" : "false" ) );
            bld.Append( "</script>" );
            bld.Append( "<script type=\"text/javascript\">" );
            bld.Append( "function initialize() {" );
            bld.Append( "var myOptions = {" );
            bld.Append(
                string.Format( numberFormat, "center: new google.maps.LatLng({0}, {1}),", location.Latitude, location.Longitude ) );
            bld.Append( "zoom: 8," );
            bld.Append( string.Format( "mapTypeId: google.maps.MapTypeId.{0}", MapType.ToString().ToUpper() ) );
            bld.Append( "};" );
            bld.Append( "var map = new google.maps.Map(document.getElementById(\"map_canvas\")," );
            bld.Append( "myOptions);" );
            bld.Append( "}" );
            bld.Append( "</script></head>" );
            bld.Append( "<body onload=\"initialize()\">" );
            bld.Append( "<div id=\"map_canvas\" style=\"width:100%; height:100%\"></div>" );
            bld.Append( "</body></html>" );

            return bld.ToString();
        }

        #endregion
    }
}

Edit.
Noch ein paar Anmerkungen.
Ich habe größtenteils auf Error-Handling verzichtet. Ebenfalls verarbeite ich alles synchron, also nicht wundern, wenn die UI einen Moment einfriert :)
 
Zuletzt bearbeitet:
Wow, cool :) Danke!

Nur eine Frage hab ich noch, wie hast du das mit dem API Key gemacht? Irgendwie dachte ich ich habe mal gelesen, dass man keine mehr braucht und bisher hab ich auch noch keinen benutzt. Wenn ich aber anfordern will, will er eine Webseite von mir haben, wie hast du das gemacht?

Grüße
Mathias

EDIT: Habs geschafft verwende einfach folgende URL: http://maps.google.com/maps/api/js?sensor=false

In den Google FAQ steht folgender Satz "Hinweis: Die Google Maps-API-Schlüssel sind nur bei Verwendung des Google Maps JavaScript-APIs Version 2 sowie des Google Maps-APIs für Flash erforderlich." bei Version 3 geht es also auch ohne :)
 
Zuletzt bearbeitet:
Zurück
Oben