jueves, 22 de diciembre de 2011

Google Maps - Windows Form

Esta entrada está dedicada a .NET. Para las entradas de .NET las realizaré con Visual Studio 2010 en C#.  En esta entrada realizaremos una aplicación Windows que incluya lo que hemos realizado hasta ahora de Google Maps. Es decir una aplicación de ventana con un navegador embebido que nos muestre nuestro mapa. Primero mostrare como realizarlo de la manera más sencilla y posteriormente veremos cómo modificar el html desde nuestro código.

Para comenzar en la forma sencilla explicaré los pasos a realizar sin necesidad de pararnos a ver código. Primero crearemos un nuevo proyecto de 'Aplicación de Windows Forms'. Para comenzar en el diseñador del formulario agregaremos un control llamado "WebBrowser". El siguiente paso es agregar el html a nuestra solución. Basta con copiar el fichero a nuestra solución. Lo siguiente que debemos hacer es a la hora de cargar el formulario o si queremos que se cargue al pulsar un boton etc en el evento Click del botón. El control WebBrowser posee un método que es Navigate(string urlString) con este método navegaremos a la url que le pasemos como parámetro. Podemos escribir la dirección de un archivo html de nuestro html y este se cargará en nuestro WebBrowser. Debemos pasarle la dirección de nuestro html con los mapas (recordar que es una ruta relativa pues lo hemos agregado a nuestra solución). Veamos el resultado:

A continuación, realizaré un ejemplo en el que nuestro html tan solo presentará un mapa que cargue una dirección escrita en nuestro formulario. Para ello crearemos un proyecto cómo el anterior. Desanclaremos el WebBrowser para que no ocupe toda la ventana y añadiremos un TextBox y un Button. Veamos:



Lo siguiente que haremos será traer el html con nuestro mapa. En este caso el html será tan solo un mapa que carga una dirección inicial y nos servirá de plantilla. Los pasos que vamos a seguir son: añadir etiquetas de identificación en el html, incrustar nuestro html al compilar el proyecto, obtenerlo en tiempo de ejecución modificar la dirección inicial del mapa del html, guardarlo en el directorio temp de nuestro sistema y cargarlo en el navegador.

Comencemos con los pasos. Inicialmente en nuestro html poseo un string con la dirección inicial. Este string ahora será "[[ADDRESS]]" (incluyendo las comillas). Esto nos servirá como etiqueta para identificarlo cuando debamos modificarlo en tiempo de ejecución. Lo siguiente que debemos hacer es incrustar el html a la hora de la compilación. Con esto conseguiremos que al compilar no creemos el html con el contenido, si no que irá incrustado en nuestro ejecutable. Para ello en el explorador de soluciones haremos click derecho en el html e iremos a propiedades. En la propiedad 'Acción de compilación' seleccionaremos 'Recurso incrustado' y la propiedad 'Espacio de nombres de la herramienta personalizada' debemos escribir el espacio de nombres de nuestra aplicación. 



Con esto ya hemos conseguido incrustar nuestro html. Lo siguiente que debemos hacer es obtener este recurso incrustado. Esto lo podemos realizar con la siguiente función:

 
  public string GetFromResources(string resourceName)
        {
            Assembly assem = this.GetType().Assembly;
            using (Stream stream = assem.GetManifestResourceStream(resourceName))
            {
                try
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        return reader.ReadToEnd();
                    }
                }
                catch (Exception e)
                {
                    throw new Exception("Error de acceso al Recurso: '" + resourceName + "'\r\n" + e.ToString());
                }
            }
        }

Con esta función devolvemos un string con todo el html. Esto lo recogeré en un StringBuilder en el evento Click del botón y en este StringBuilder realizaremos un reemplazo de [[ADDRESS]] por lo que haya escrito en el TextBox. Con esto habremos modificado el html para que muestre nuestra dirección. Lo siguiente y último será guardar nuestro fichero en la carpeta de temporal, guardaremos el archivo con la siguiente función:

 
  public bool CrearFicheroTexto(string Fichero, StringBuilder Contenido)
        {
            // Validaciones
            string Ruta = Path.GetDirectoryName(Fichero);
            if (!Directory.Exists(Ruta))
            {
                Directory.CreateDirectory(Ruta);
            }
            if (File.Exists(Fichero))
            {
                File.Delete(Fichero);
            }

            StreamWriter sw = File.CreateText(Fichero);
            sw.Write(Contenido.ToString());
            sw.Close();
            return true;
        }

Para obtener la dirección de los archivos temporales usaremos Environment.GetEnvironmentVariable("TEMP");  a esta dirección le añadiremos el nombre que queramos dar a nuestro html, por ejemplo "\google.htm". Una vez guardado el fichero debemos cargarlo con el evento Navigate del WebBrowser. Veamos cómo quedaría el evento Click del botón:

 
private void botCargar_Click(object sender, System.EventArgs e)
        {
            StringBuilder textoHtml = new StringBuilder();
            // Entorno
            textoHtml.AppendLine(GetFromResources("BlogGMap.mapa.html"));
            string TempFolder = Environment.GetEnvironmentVariable("TEMP");

            textoHtml.Replace("[[ADDRESS]]", tbDireccion.Text);

            string ficheroTemporalHTML = TempFolder + @"\" + "google.htm";
            bool existeFichero = false;
            try
            {
                existeFichero = CrearFicheroTexto(ficheroTemporalHTML, textoHtml);

            }
            catch (Exception ex)
            {
                MessageBox.Show(this.Text, ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            if (existeFichero)
            {
                this.wbGMap.Navigate(ficheroTemporalHTML);
            }
        }

Y el resultado final:




Podemos descargar la solución de aquí: Descargar

Nota: Se recomienda que la propiedad ScriptErrorsSuppressed del WebBrowser este a true.

Google Maps - Windows Form - Parte 2
Google Maps - Windows Form - Parte 3

39 comentarios:

  1. muy interesante el blog, con muy buen contenido. Espero que no te moleste que te agregue a mi blogroll y si te interesa poder realizar un intercambio de enlaces..

    saludos y sigue así...

    ResponderEliminar
  2. Gracias, me alegra que te resulte interesante el contenido. No me importa que me agregues a tu blogroll. En mi perfil puedes ver mi correo si quieres intercambiar enlaces o algo.

    Saludos.

    ResponderEliminar
  3. solo me gustaría aparecer en tu blogroll, ya que, creo que estamos orientados al mismo tema: "Aportar conocimientos de programación.."

    saludos

    ResponderEliminar
  4. Gracias por tu enlace.. estamos leyendonos...

    saludos y felices fiestas...

    ResponderEliminar
  5. Muy bueno el aporte... Lo he insertado en mi aplicación y va genial, pero tengo una pregunta... yo introduzco la dirección (calle+municipio), a partir de esta y con los resultados de Geocoder cómo es posible mostrar en textbox's la longitud y la latitud? GraciaS!

    ResponderEliminar
  6. Hola Marisol. Como ya ves centramos el mapa con la localización que nos ha dado el geocoder. Esta localización tiene dos métodos: .lat(), .lng() estos métodos nos devuelven la latitud y longitud. Si deseamos obtener esta latitud y longitud desde windows form podemos crear inputs ocultos en nuestro html. En estos inputs almacenaremos los valores de latitud y longitud. Posteriormente en nuestra aplicación windows podemos poner un boton que se llame "obtener coordenadas" y en su evento click acceder a estos input ocultos mediante: webBrowserHTML.Document.GetElementById("OcultoLat").GetAttribute("value")
    es decir con esto podemos acceder a controles html desde nuestro código. Espero haber aclarado tu duda. Si no es asi, en mi perfil esta mi correo electronico para más dudas.

    Gracias.

    ResponderEliminar
  7. muchas gracias por la respuesta, pero no consigo saber como crear el input oculto en el archivo html

    ResponderEliminar
  8. realmente, el input si lo he insertado en el html, el problema es que al intentar asignarle el valor de la latitud o longitud da un error en ejecución, avisando de que el objeto no contiene el método indicado (lng y lat)

    ResponderEliminar
  9. en la función "verDireccion" tenemos el 'results[0].geometry.location' en el cual obtenemos la dirección. Se puede conseguir almacenar la latitud en un oculto mediante: document.getElemetById("ocultoLat").value = results[0].geometry.location.lat().toString();
    Con eso debería funcionar (al menos yo lo empleo y me funciona). Si sigue sin funcionar nos ponemos en contacto para verlo más detenidamente, aunque estoy de examenes y no me puedo conectar mucho. Saludos

    ResponderEliminar
  10. gracias pero nada, ahora me dice que el objeto no acepta el método getElemetById. me sabe mal hacerte perder más tiempo

    ResponderEliminar
    Respuestas
    1. Ahora que he sacado tiempo he subido una entrada con un ejemplo obteniendo coordenadas, espero que te sirva de ayuda.

      Eliminar
  11. Podrias pasar el Codigo? Gracias!! Es una aplicacion Form?

    ResponderEliminar
    Respuestas
    1. Si, se caduco el enlace pronto lo subo.

      Sí, es una aplicacion de Windows Form.

      Eliminar
    2. ya lo he subido, tienes el enlace puesto

      Eliminar
  12. Oye y como puedo buscar por latidud y longitud en el form, asi como lo haces por nombre

    ResponderEliminar
    Respuestas
    1. si escribes la latitud y longitud, en el mismo lugar que por el nombre de la calle, la API de Google Maps nos sitúa en la dirección asociada a esa latitud y longitud. Si deseas algo más que eso con las coordenadas, puedo hacer un ejemplo y realizar una nueva entrada =)

      Eliminar
  13. grasias viejo buena aplicacion me sirvio de mucho

    ResponderEliminar
  14. es de gran utilidad la aplicaion es algo que andaba buscando pero aora necesito implementar en el mapa el trazo de las rutas y no tengo idea de como hacerlo si eres tan amable de ayudarme u orientarme un poco te lo agradeceria

    ResponderEliminar
  15. Lo podrias publicar para VB.net

    ResponderEliminar
  16. En la documentación de Google Maps tenemos rutas: http://bit.ly/QRz4Bs

    En cuanto a lo de VB.net, intentaré colgar el ejemplo en cuanto disponga de un poco de tiempo =).

    Gracias por vuestros comentarios.

    ResponderEliminar
  17. Esta interesante el ejemplo pero podrias checar el link de descarga del codigo al parecer ya caduco, gracias

    ResponderEliminar
  18. Hola, he cambiado el enlace para descargarlo desde mi SkyDrive. Por si hay alguna duda es BlogGMap.rar

    ResponderEliminar
  19. Perfecto, muy buen ejemplo justo lo que endaba buscando le dare una revisada para adaptarlo a lo que necesito, muchas gracias por el ejemplo

    ResponderEliminar
  20. Muy bueno, tengo una duda, como marcar varias direcciones de una misma zona y que se muestren en el mismo mapa.

    ResponderEliminar
    Respuestas
    1. Hola, esto se realizaría con el API de Google Maps en JavaScript. Ahora mismo estoy de exámenes, en cuanto tenga tiempo realizaré un ejemplo de lo que me pides.

      Para ver cómo sería puedes ir viendo en los distintos ejemplos de Google: https://developers.google.com/maps/documentation/javascript/examples/?hl=es

      Aspectos Básicos: https://developers.google.com/maps/documentation/javascript/basics?hl=es

      Gracias por tu comentario

      Eliminar
    2. Hola, lo he estado viendo y para agregar lo que pides en Windows Forms es diferente. Deberas pensar en que el marcador en e archivol HTML [[Address]] ahora contendrá una lista de direcciones. Deberás almacenar las direcciones que vayas buscando, guardalas en el Form. A continuación, cada vez que se regenere el HTML sustituiras la etiqueta [[Address]] por el formato correspondiente a una lista JS, puede ser un array. Por último deberás tratar esta lista en el JS para que se pinte un marker por dirección.

      No sé si me he explicado correctamente o si se ve claro lo que quiero decir, si sigues teniendo alguna duda daré prioridad a escribir una entrada resolviendo el problema. =)

      Eliminar
    3. Hola como estas? pudiste solucionar lo de los marker para winforms? por que estoy con eso y no e podido solucionarlo desde ya muchas gracias

      Eliminar
    4. Buenas, la idea es similar a la que se realiza para un marker. En este caso podrías tener en lugar de una etiqueta [[ADDRESS]] una zona marcada con otra etiqueta llamemosla [[MARKERS]]. En el código HTML puedes ver cómo se crea un marker. Imagina que la creación del marker la encapsulas en una función crearMarker(address). Bien pues en esta etqiueta [[MARKERS]] que hemos puesto deberemos reemplazarla por las X llamadas a la función del marker en función de las direcciones que tengamos. En el fondo es componer en un string un trozo de codigo JS y sustituirlo en nuestro HTMl.

      No sé si me he explicado muy bien =/.

      Eliminar
    5. Hola gracias como entender lo entiendo es que no pude hacerlo cuando tengas tiempo agradesco tu ayuda esto es todo bastante nuevo para mi

      Eliminar
    6. Disculpa la molestia denuevo pero podrias pasarme cuando tengas tiempo como crearlo y pasarlo de c# al html? muchas gracias

      Eliminar
  21. Fernando, buen día, tendras algun codigo para cargar un KML en windows forms .NET

    ResponderEliminar
  22. si podemos visualizar el KML desde Google earth pero en nuestra aplicacion no:
    este es un estracto de nuestro codigo.

    var Lon = "[[Lon]]";
    var Lat = "[[Lat]]";

    var myLatlng = new google.maps.LatLng(Lat,Lon);

    var myOptions = {
    zoom: 15,
    center: myLatlng,
    mapTypeId: google.maps.MapTypeId.SATELLITE
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

    var ctaLayer = new google.maps.KmlLayer('http://www.nnnnnn/Layers/nnnn.kml');

    ctaLayer.setMap(map);

    Espero puedas apoyarnos...
    Muchas gracias

    ResponderEliminar
    Respuestas
    1. Buenos días.

      Lamentablemente ahora mismo no puedo ayudarte =( Este semestre en la universidad nos estan dando mucho trabajo y acabamos de empezar.

      Espero poder sacar tiempo para poder ayudarte a ti y a todas las personas que me pedís ayuda.

      Gracias por vuestros comentarios.

      Eliminar
  23. Fernando,muchas gracias por tu intencion, ya se resolvio el problema, el kml era el que estaba mal... lo rehicimos y funciona correctamente,
    un abrazo y suerte en tu semestre! :D

    ResponderEliminar
  24. Como puedo insertar es de html,,,sorry soy nueva en esto

    ResponderEliminar
  25. Hola, muy buen aporte, tengo una pregunta, como puedo obtener los datos de longitud y latitud y a la vez crear un marcador con solo hacer click en el mapa? Te agradezco la ayuda

    ResponderEliminar
  26. hace horas estoy buscando como hacerlo
    MUCHISIMAS GRACIAS POR COMPARTIR
    GENIAL TU TRABAJO

    ResponderEliminar