Hace unos días estaba queriendo hacer una aplicación que buscara un lugar y que después me mostrara las opciones resultantes, nada del otro mundo, lo hice en Windows Phone, pero gracias a que es prácticamente lo mismo, podremos hacer un ejemplo utilizando Silverlight.
Esta vez, dado que nuestro interés se fijará en la parte de obtención de datos, dejaré de lado el mapa que acompaña a prácticamente todos mis ejemplos para obtener solo los datos a partir de la información recibida, si te interesa saber como “canalizar” esa información en un mapa escríbelo en los comentarios y te ayudo en esa parte.
Ok, ya que tienes un proyecto abierto de Silverlight 4, lo único adicional que necesitarás es una Bing Maps API Key que te servirá para consultar esta información.
Para comenzar y darte un previo de lo que debes hacer puedes comenzar por visitar este link, donde la idea es que hagas una consulta de un lugar al servicio REST y este te regrese el resultado o resultados de tu solicitud, al hacerlo, obtendrás algo parecido a esta pantalla.
Quizá no lo veas de otro planeta, de hecho no lo es, es un simple XML, aún así continuemos.
¿Ya creaste tu solución? De no ser así, este es el momento, ya que la tengas, ahora si, necesitarás colocar vía XAML los siguientes componentes
<Grid x:Name="LayoutRoot" Background="White"> <Border x:Name="contBuscador" BorderBrush="White" BorderThickness="1" Height="50" Margin="8,8,272,0" VerticalAlignment="Top"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <LinearGradientBrush.RelativeTransform> <CompositeTransform CenterY="0.5" CenterX="0.5" Rotation="99"/> </LinearGradientBrush.RelativeTransform> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="#FF4B4B4B" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid Margin="0"> <TextBox x:Name="txtLugar" Margin="8,8,159,0" TextWrapping="Wrap" Height="25" VerticalAlignment="Top"/> <Button x:Name="btnBuscar" Content="Buscar" HorizontalAlignment="Right" Height="25" Margin="0,8,8,0" VerticalAlignment="Top" Width="147" Click="btnBuscar_Click"/> </Grid> </Border> <Border x:Name="contResultado" BorderBrush="White" BorderThickness="1" Margin="8,62,272,8"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <LinearGradientBrush.RelativeTransform> <CompositeTransform CenterY="0.5" CenterX="0.5" Rotation="99"/> </LinearGradientBrush.RelativeTransform> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="#FF4B4B4B" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid Margin="0"> <StackPanel x:Name="contResultados" Margin="0,8" Width="340" HorizontalAlignment="Center"/> </Grid> </Border> <Border x:Name="contEspecificar" BorderBrush="White" BorderThickness="1" Margin="0,8,8,8" HorizontalAlignment="Right" Width="260"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <LinearGradientBrush.RelativeTransform> <CompositeTransform CenterY="0.5" CenterX="0.5" Rotation="99"/> </LinearGradientBrush.RelativeTransform> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="#FF4B4B4B" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid Margin="0"> <TextBlock Height="22" Margin="8,8,0,0" TextWrapping="Wrap" Text="Ciudad elegida" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Left" Width="91"/> <TextBlock x:Name="txtCiudad" Height="22" Margin="0,31,8,0" TextWrapping="Wrap" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Right"/> <TextBlock Height="22" Margin="8,68,0,0" TextWrapping="Wrap" Text="Latitud" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Left" Width="91" CacheMode="BitmapCache"/> <TextBlock x:Name="txtLatitud" Height="22" Margin="0,91,8,0" TextWrapping="Wrap" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Right"/> <TextBlock Height="22" Margin="8,125,0,0" TextWrapping="Wrap" Text="Longitud" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Left" Width="91"/> <TextBlock x:Name="txtLongitud" Height="22" Margin="0,151,8,0" TextWrapping="Wrap" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Right"/> <TextBlock Height="22" Margin="8,190,0,0" TextWrapping="Wrap" Text="Estado" VerticalAlignment="Top" Foreground="White" HorizontalAlignment="Left" Width="91"/> <TextBlock x:Name="txtEstado" Margin="0,216,8,224" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right"/> <TextBlock Margin="8,0,0,188" TextWrapping="Wrap" Text="Localidad" Foreground="White" HorizontalAlignment="Left" Width="91" Height="22" VerticalAlignment="Bottom"/> <TextBlock x:Name="txtLocalidad" Margin="0,0,8,162" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right" Height="22" VerticalAlignment="Bottom"/> <TextBlock Margin="8,0,0,123" TextWrapping="Wrap" Text="País" Foreground="White" HorizontalAlignment="Left" Width="91" Height="22" VerticalAlignment="Bottom"/> <TextBlock x:Name="txtPais" Margin="0,0,8,97" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right" Height="22" VerticalAlignment="Bottom"/> </Grid> </Border> </Grid> |
De esta forma podrás ver tu página de inicio así.
Ok, ahora crea un nuevo UserControl, en mi caso lo llamé “CiudadEncontrada”, e incluye el siguiente código XAML.
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Leer_XML.CiudadEncontrada" d:DesignWidth="640" d:DesignHeight="480" Width="340" Height="100"> <Grid x:Name="LayoutRoot" Background="Transparent"> <TextBlock x:Name="txtResultado" HorizontalAlignment="Center" Margin="0" TextWrapping="Wrap" Text="Tulancingo de Bravo" VerticalAlignment="Center" FontSize="18.667" Foreground="White"/> </Grid> </UserControl> |
Y lo importante, debe llevar las siguientes propiedades.
public string Nombre { get { return nombre; } set { nombre = value; txtResultado.Text = nombre; } } public string Latitud { get { return latitud; } set { latitud = value; } } public string Longitud { get { return longitud; } set { longitud = value; } } public string Localidad { get { return localidad; } set { localidad = value; } } public string Estado { get { return estado; } set { estado = value; } } public string Pais { get { return pais; } set { pais = value; } } |
Recuerda que cada propiedad incluye una variable de su mismo tipo y local. Ahora, ya con el elemento creado vamos de regreso a la página principal, lo primero que necesitas declarar es un objeto de tipo WebClient y una cadena que nos servirá para el espacio de nombres del XML.
WebClient clienteXML; string nombreEspacio = @http://schemas.microsoft.com/search/local/ws/rest/v1; |
Al momento de iniciar la aplicación crea la instancia del objeto WebClient y un manejador para el evento DownloadStringCompleted
public MainPage() { InitializeComponent(); clienteXML = new WebClient(); clienteXML.DownloadStringCompleted += new DownloadStringCompletedEventHandler(clienteXML_DownloadStringCompleted); } |
Bien con todo esto ya podrás crear el manejador para el evento click del único botón con el que cuentas
private void btnBuscar_Click(object sender, System.Windows.RoutedEventArgs e) { string query = txtLugar.Text; if (!string.IsNullOrEmpty(query)) { CargarXML(txtLugar.Text); } } |
Como puedes ver, en el manejador lo único que haces es verificar que el TextBox de la ciudad que quieres buscar no esté en blanco y mandar llamar a una función llamada “Cargar XML” que recibe como parámetro una cadena, la función es la siguiente.
public void CargarXML(string consulta) { clienteXML.DownloadStringAsync(new Uri("http://dev.virtualearth.net/REST/v1/Locations?query=" + consulta + "&amp;amp;amp;key=Ajtc9UQoW_fIE-ijLj_wmEnUvIhpmqdfeVRdiKlRzjvLlikL3EK0oe9x499&amp;amp;amp;output=xml&amp;amp;amp;c=es-ES", UriKind.Absolute)); } |
Simplemente ejecutas el método asíncrono con el que tu WebClient solicita la información, la url que vez es la que te regresará el XML (en esta dirección es en donde debes incluir tu API Key) del que te hablé al principio del post y la puedes hacer mas compleja viendo el enlace que te mostré ahí mismo. Ya que ejecutaste el método, solo falta la funcionalidad en el manejador que pusiste al iniciar la aplicación, vamos con esa parte.
void clienteXML_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { string resultado = e.Result; XDocument doc = XDocument.Parse(resultado); List<XElement> listaElementos = new List<XElement>(); listaElementos = doc.Descendants(XName.Get("Location", nombreEspacio)).ToList(); contResultados.Children.Clear(); foreach (XElement variable in listaElementos) { CiudadEncontrada ciudadEncontrada = new CiudadEncontrada(); string localidad = variable.Descendants(XName.Get("Locality", nombreEspacio)).First().Value; string estado = variable.Descendants(XName.Get("AdminDistrict", nombreEspacio)).First().Value; string pais = variable.Descendants(XName.Get("CountryRegion", nombreEspacio)).First().Value; ciudadEncontrada.Nombre = localidad + " " + estado + " " + pais; ciudadEncontrada.Estado = variable.Descendants(XName.Get("AdminDistrict", nombreEspacio)).First().Value; ciudadEncontrada.Localidad = variable.Descendants(XName.Get("Locality", nombreEspacio)).First().Value; ciudadEncontrada.Pais = pais; ciudadEncontrada.Latitud = variable.Descendants(XName.Get("Latitude", nombreEspacio)).First().Value; ciudadEncontrada.Longitud = variable.Descendants(XName.Get("Longitude", nombreEspacio)).First().Value; contResultados.Children.Add(ciudadEncontrada); ciudadEncontrada.MouseLeftButtonDown += ciudadEncontrada_MouseLeftButtonDown; } } |
Si tienes experiencia manejando información no verás nada del otro mundo, sino, puedes ver como llenas una lista de tipo “XElement” a partir de casa resultado obtenido y por medio de un ciclo crearás un nuevo objeto de tipo “CiudadEncontrada” (recuerda que fue el UserControl que creaste antes), al cual le pasas las propiedades necesarias, algo importante aquí es que debes tener el XML abierto para poder pasar estas propiedades de lo contrario es prácticamente imposible poder lograrlo.
Como puedes ver, al crear un elemento dinámico en el ciclo, también le estás creando un manejador de eventos, la idea de crearlo es para poder mostrarte que hacer después con esas propiedades, en este caso solo las vas a mostrar en la tercera parte de tu página principal, de la siguiente forma.
void ciudadEncontrada_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { CiudadEncontrada ciudadElegida = sender as CiudadEncontrada; txtCiudad.Text = ciudadElegida.Nombre; txtLatitud.Text = ciudadElegida.Latitud; txtLongitud.Text = ciudadElegida.Longitud; txtEstado.Text = ciudadElegida.Estado; txtLocalidad.Text = ciudadElegida.Localidad; txtPais.Text = ciudadElegida.Pais; } |
Y listo!!! Así puedes obtener y utilizar los resultados obtenidos para poder ubicar ciudades en un mapa.
Descarga aquí el código fuente.
NOTA: Agradezco a Rodrigo Díaz Concha por la ayuda en la obtención de la solución para este problema.