Windows Phone Toolkit y el Control de Mapas

En el post anterior vimos un inicio de como utilizar el control mapas de Nokia para Windows Phone8, en este post añadiremos Windows Phone Toolkit

Para aquellos que no conozcáis Windows Phone Toolkit, este es un conjunto de herramientas y controles extra desarrollados por Microsoft y Open Source alojados en codeplex, concretamente en http://phone.codeplex.com/.

A la hora de utilizarlo en un proyecto nos serviremos de Nuget, haremos click derecho sobre el proyecto o solución > Administrar paquetes Nugget y buscar el Windows Phone Toolkit.

imageimage

Una vez instalado para su utilización deberemos importar su espacio de nombres

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

 

Una vez importado puedes utilizar en la pagina sus controles que son

 

con esto ya se tienen disponibles los todos los controles del toolkit, los cuales son:

  • AutoCompleteBox

  • ContextMenu

  • CustomMessageBox

  • DateTimeConverters

  • DateTimePickers

  • Effects – SlideInEffect, TiltEffect and TurnstileFeatherEffect

  • ExpanderView

  • HubTile

  • ListPicker

  • LongListMultiSelector

  • Map extensions

  • PhoneTextBox

  • RatingControl

  • ToggleSwitch

  • Navigation transitions

  • WrapPanel

  • LongListSelector for 7.x

  • MultiSelect for 7.x

En este caso vamos a ver la extension de mapas, para ello debemos importar su espacio de nombres

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

Como podéis ver en este using estamos importando el espacio de nombres de Mapas del Toolkit y vamos a ver los controles UserLocationMarker y

Pushpin, ambos son un capa de pushpinss personalizados como los que vimos en el anterior post que podíamos hacer con la clase MapOverlay cada uno con su look y destinado a utilizarse para diferentes casos.

 

  • Pushpin: tiene el mismo look & feel que el viejo Bing Maps y se utiliza para señalar puntos de interés en el mapa
  • UserLocationMarker: es usado para identificar la posición del usuario y tiene el mismo look & feel que el usado en la aplicación nativa.

Usarlos es tan sencillo como el siguiente trozo de código

        <Controls:Map x:Name="map"
                      Center="43.2566901,-2.92406159"
                      ZoomLevel="15"
                      Pitch="8"
                      PedestrianFeaturesEnabled="True"
                      LandmarksEnabled="True"
                      Grid.Row="1">
            <toolkit:MapExtensions.Children>
                <toolkit:UserLocationMarker x:Name="UserLocationMarker" />
                <toolkit:Pushpin x:Name="MyPushpin" Content="Posición">
                </toolkit:Pushpin>
            </toolkit:MapExtensions.Children>
        </Controls:Map>
    

Si queremos trabajar con ellos desde el code-behind para enviar un posicionamiento en el mapa y lo marque utilizaremos el siguiente código

        private void CreatePushPins()
        {
            Pushpin pushpin = null;
            UserLocationMarker marker = null;

            ObservableCollection<DependencyObject> children = MapExtensions.GetChildren(map);
            pushpin = children.FirstOrDefault(x => x.GetType() == typeof(Pushpin)) as Pushpin;
            marker = children.FirstOrDefault(x => x.GetType() == typeof(UserLocationMarker)) as UserLocationMarker;
            pushpin.GeoCoordinate = new GeoCoordinate(43.2576901, -2.9250616);
            marker.GeoCoordinate = map.Center;
        }

Como veis a través del método MapExtensions.GetChildren me devuelve todos los objetos creados en el mapa y luego a través de LinQ los recupero por tipo, en este caso, solo el primero de cada tipo porque podemos tener múltiples, a partir de ahí les asigno las coordenadas en las cuales los quiero mostrar, siendo la localización del usuario el centro del mapa y el PushPin una posición al lado como se ve en la imagen

image

 

 

Si lo que queremos es mostrar una serie de lugares a partir de una lista de coordenadas que tengo por ejemplo de restaurantes utilizaremos el siguiente XAML

            <toolkit:MapExtensions.Children>
                <toolkit:MapItemsControl>
                    <toolkit:MapItemsControl.ItemTemplate>
                        <DataTemplate>
                            <toolkit:Pushpin GeoCoordinate="{Binding Coordenada}" Content="{Binding Informacion}" />
                        </DataTemplate>
                    </toolkit:MapItemsControl.ItemTemplate>
                </toolkit:MapItemsControl>
            </toolkit:MapExtensions.Children>

 

Nuestro siguiente paso es crear la clase donde vamos a tener los datos con los que realizamos el binding, como por ejemplo

    public class Lugar
    {
        public GeoCoordinate Coordenada { get; set; }
        public string Informacion { get; set; }      
    }

Rellenaríamos los datos que queremos mostrar

 

private void CrearLugares()
        {
            lugares.Add(new Lugar()
            {
                Coordenada = new GeoCoordinate(43.2566901, -2.92406159),
                Informacion = "Restaurante 1"
            });
            lugares.Add(new Lugar()
            {
                Coordenada = new GeoCoordinate(43.2576901, -2.93406159),
                Informacion = "Restaurante 2"
            });
            lugares.Add(new Lugar()
            {
                Coordenada = new GeoCoordinate(43.2526901, -2.93406159),
                Informacion = "Restaurante 3"
            });
        }

Y ya nos queda el último paso que es asignar la lista de lugares al objeto MapItemsControl, con estas tres líneas de código

 private void CreatePushPins()
        {

            ObservableCollection<DependencyObject> children = MapExtensions.GetChildren(map);
            var obj = children.FirstOrDefault(x => x.GetType() == typeof(MapItemsControl)) as MapItemsControl;

            obj.ItemsSource = lugares;
        }

 

El resultado es

 

image

 

Podéis descargar el ejemplo desde el siguiente enlace

descargar-ejemplo

Control de Mapas en Windows Phone 8

Después de mucho tiempo sin escribir por diversos temas, me he propuesto como arranque del año volver a escribir y como arranque de este año 2014 voy a tratar el tema de Mapas de Windows Phone 8.

Con Windows Phone 8 tenemos dos opciones a la hora de utilizar mapas, los mapas de Bing (los que utilizábamos en Windows Phone 7) o los de Nokia, siendo estos los que se recomienda utilizar por su potencia y fiabilidad, yo voy a hablar de los mapas de Nokia.

A la hora de utilizar los mapas lo primero que tenemos que tener en cuenta es de activar la capacidad ID_CAP_MAP en nuestro proyecto como muestra la siguiente imagen.

 

image

Para utilizar el control de mapas en nuestra aplicación arrastramos de la barra de herramientas a la pantalla donde vamos a utilizarlo como en la siguiente imagen.

image

Al arrástralo observaremos que nos ha introducido un nuevo espacio de nombres en el XAML denominado Controls cuyo espacio de nombres es Microsoft.Phone.Controls.Maps.

image

Ya tenemos el control de mapas en la ventana, la primera propiedad en la que podemos fijarnos es CartographicMode, esta propiedad nos permite indicar el modo de cartografía en el que mostrar el mapa, WP8 nos ofrece 4 tipos que podemos ver en la siguiente imagen.

image

AdemásAdemas de esta propiedad, en el control mapa tenemos

  • Center Indica el centro del mapa que se va a mostrar, es de tipo GeoCoordinate, el cual es ua clase que almacena propiedades de geolocalización como latitud, longitud, altitud….
  • ZoomLevel isNivel del Zoom del mapa, su valor va de 1 (lejos) a 20 (cerca).
  • Heading Rotación del mapa.
  • Pitch Es la elevación del mapa comparado con el Horizonte, veremos como se utiliza.
  • CartographicMode Ya lo hemos visto anteriormente
  • ColoreMode Tipo de color para el map (Dark o Light).
  • LandmarksEnabled Muestra los edificios en una representación 3D, estos edificios son los considerados importantes como monumentos, iglesias.
  • PedestrianFeaturesEnabled Muestra los elementos del peaton, como por ejemplo las estaciones de metro, autobuses….

Un ejemplo sería el siguiente código

 

image

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Controls:Map x:Name="map"
                      Center="43.2566901,-2.92406159"
                      ZoomLevel="17"
                      Heading="45"
                      Pitch="25"
                      CartographicMode="Road"
                      ColorMode="Dark"
                      PedestrianFeaturesEnabled="True"
                      LandmarksEnabled="True"/>
    </Grid>

Lo siguiente que vamos a ver es el método SetView, este método permite cambiar la vista del control (ir a otras coordenadas) usando una animación, es muy sencillo de usar solo tenemos que ver el siguiente código

                map.SetView(new System.Device.Location.GeoCoordinate()
                {
                    Latitude = 43.3065222257616,
                    Longitude = -2.9944420673
                }, 15, Microsoft.Phone.Maps.Controls.MapAnimationKind.Parabolic);

Como tipos de animación tenemos Parabolic  o  Linear.

Una de las características mas chulas del control de mapas es la facilidad con la que se pueden añadir cualquier tipo de capas al control para señalar posiciones, elementos…. Esto se realiza a través de la clase MapOverlay , esta clase representa una capa dentro del mapa y puede contener cualquier objeto de tipo UIElement. Por ejemplo si queremos señalar un punto geográfico con una ellipse de color rojo, es tan sencillo como el siguiente trozo de código.

            var overlay = new MapOverlay();
image            overlay.GeoCoordinate = new System.Device.Location.GeoCoordinate()
            {
                Latitude = 43.3065222257616,
                Longitude = -2.9944420673
            };
            overlay.Content = new Ellipse()
            {
                Height = 30,
                Width = 30,
                Stroke = new SolidColorBrush(Colors.Red)
            };
            var layer = new MapLayer();
            layer.Add(overlay);
            map.Layers.Add(layer);

Como podéis observar es un característica muy potente ya que podemos generar cualquier contenido y a ese contenido darle comportamientos, lo que nos permite generar PushPins al mapa muy potentes y personalizados. Los pasos que tenemos que realizar son:

 

  1. Crear el objeto MapOverlay
  2. En el MapOverlay establecer el contenido con un UIElement
  3. En el MapOverley establecer la ubicación geográfica
  4. Crear el objeto MapLayer
  5. Agregar el MapOverlay a la colección de Layers del control

En el siguiente post utilizaremos el Windows Phone Toolkit, donde veremos los controles UserLocationMarker y Pushpin.

 

 Aquí os dejo un ejemplo de lo visto anteriormente

Windows Server AppFabric Monitoring Limpiando los datos de monitorización

Cuando en desarrollo estas con un servidor de App Fabric o sobre todo en pruebas de rendimiento, es frecuente que tengas que limpiar y reinicializar las bases de datos de monitorización que tiene AppFabric. Para ello es tan sencillo como lanzar comandos en PowerShell para inicializar las bases de datos.

   1:  import-module applicationserver
   2:   
   3:  $ConfirmPreference = "None"
   4:   
   5:  Clear-ASMonitoringSqlDatabase -Database "AppFabricMonitoring" -Server "ServidorDeSqlServer"
   6:   
   7:  (Cambiar el nombre de ServidorSqlServer por el la nombre de servidor del Sql Server

 

También suele pasar que después de lanzar este comando las queries del dashboard de AppFabric se vuelven lentas, para ello solo hay que lanzar el comando T-SQL UPDATE STATISTICS ASEventSourcesTable.

Aquí tenéis la entrada en el MSDN

.

Windows Phone 7 – Tutorial XXXVII – Localización Tutorial IV

En este articulo veremos como utilizar BingMaps, en nuestro Windows Phone, para ello lo primero que tenemos que hacer es crear una cuenta de BingMAps siguiendo los siguientes pasos

1.- Abrir el navegador con la url http://www.bingmapsportal.com.

2.- Pinchar en el botón Create utilizando tu cuenta de Windows Live Id

3.- En la siguiente página rellenamos los datos

 

4.-Una vez que te has registrado , pincha en el enlace “Create or view keys” del menú de la izquierda.

 

5.- En la siguiente página rellenamos los datos que nos solicita

6.- Una vez que nos ha dado la key, debemos de guardarla ya que será necesaria mas adelante

image

Ya tenemos la key ahora iniciamos un nuevo proyecto en nuestro Visual Studio y añadimos la referencia a la dll Microsoft.Phone.Controls.Maps

image

Una vez añadido abrimos la pantalla Main.xaml y arrastramos desde la ToolBox el objeto map a nuestra pagina y si abrimos el xaml obtendremos un código como este

 

1 <Border x:Name="MapView" 2 Background="Black" 3 Height="768" Width="480"> 4 <my:Map Name="map1" Height=”50” Width=”50” /> 5 </Border>

Eliminamos la altura y anchura por defecto y conseguimos la siguiente pagina

 

Nuestro siguiente paso es abrir el fichero App.xaml.cs y crear una constante que haga referencia a la key que hemos generado antes

1 internal const string Id = "Tu Key";

 

El siguiente paso es enlazar la key con nuestro mapa, para ello debemos de utilizar la clase Microsoft.Phone.Controls.Maps.CredentialsProvider, crearemos una instancia de esta clase en el fichero Main.cs

 

1 private readonly CredentialsProvider _credentialsProvider = new ApplicationIdCredentialsProvider(App.Id); 2 public CredentialsProvider CredentialsProvider 3 { 4 get { return _credentialsProvider; } 5 }

Ahora solo tenemos que enlazar esta propiedad con la propiedad CredentialsProvider de nuestro objeto map a través del databinding

1 <my:Map Name="Map" 2 CredentialsProvider="{Binding CredentialsProvider}" />

Ahora ya podemos utilizarlo en nuestra aplicación, lo primero que vamos ha hacer es que muestre por defecto una localización, para ello debemos de utilizar la propiedad Center de tipo GeoCoordinate , un ejemplo lo tenemos en el siguiente código, en el fichero Main.cs

En el fichero Main.xaml

1 <my:Map Name="Map" 2 CredentialsProvider="{Binding CredentialsProvider}" 3 ZoomLevel="{Binding Zoom, Mode=TwoWay}" 4 Center="{Binding Center, Mode=TwoWay}"> 5 ... 6 </my:Map>

También podemos cambiar el zoom a través de la propiedad Zoom de tipo double por ejemplo

 

1 public double Zoom 2 { 3 get { return _zoom; } 4 set 5 { 6 var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value)); 7 if (_zoom != coercedZoom) 8 { 9 _zoom = value; 10 NotifyPropertyChanged("Zoom"); 11 } 12 } 13 }

1 <my:Map Name="Map" 2 LogoVisibility="Collapsed" 3 ZoomLevel="{Binding Zoom, Mode=TwoWay}"> 4 <my:Map.Mode> 5 <my:AerialMode ShouldDisplayLabels="True" /> 6 </my:Map.Mode> 7 </my:Map>

y así muchas propiedades que nos proporciona, pero vamos a fijarnos en como podemos poner marcadores o pushpin para señalar direcciones dentro del mapa, para ello utilizaremos la clase Pushpin.  Generalmente añadiremos pushpin mediante código como por ejemplo

1 map1.Center = new GeoCoordinate(47.676289396624654, -122.12096571922302); 2 map1.ZoomLevel = 22; 3 4 //Creamos el pushpin 5 Pushpin pin = new Pushpin(); 6 7 //Envio la localización para el pushpin 8 pin.Location = new GeoCoordinate(47.676289396624654, -122.12096571922302); 9 10 //Añado el pushpin al mapa 11 map1.Children.Add(pin);

 

Quedándonos una imagen del tipo

 

Una de las grandes ventajas del Pushpines que podemos cambiar su apariencia totalmente, por ejemplo aprovechando la propiedad Content.

 

1 ImageBrush image = new ImageBrush() 2 { 3 ImageSource = new System.Windows.Media.Imaging.BitmapImage 4 (new Uri("http://www.clker.com/cliparts/e/d/9/9/1206572112160208723johnny_automatic_NPS_map_pictographs_part_67.svg.med.png")) 5 }; 6 7 //El contenido es una ellipse rellena con la imagen 8 pin.Content = new Ellipse() 9 { 10 Fill = image, 11 StrokeThickness=10, 12 Height = 100, 13 Width = 100 14 }; 15 16 17 map1.Children.Add(pin);

Nos quedaría

 

 

También podemos cambiar el template a través del Blend, por ejemplo

 

1 <ControlTemplate x:Key=”PushpinControlTemplate1? TargetType=”m:Pushpin”> 2 <Grid x:Name=”ContentGrid” Width=”34? Height=”34? > 3 <StackPanel Orientation=”Vertical” > 4 <Grid MinHeight=”31? MinWidth=”29? Margin=”0?> 5 <Ellipse Fill=”#FFFF7F00? 6 Margin=”1? 7 HorizontalAlignment=”Center” 8 VerticalAlignment=”Center” 9 Width=”30? 10 Height=”30? 11 Stroke=”White” 12 StrokeThickness=”3?/> 13 <ContentPresenter HorizontalAlignment=”Center” 14 Content=”{TemplateBinding Content}” 15 ContentTemplate=”{TemplateBinding ContentTemplate}” 16 Margin=”4?/> 17 </Grid> 18 </StackPanel> 19 </Grid> 20 </ControlTemplate>

Si aplicamos este template

 

image

 

Como veis un gran control totalmente personalizable para nuestras aplicaciones que queramos mostrar información en un mapa

Windows Phone 7 – Tutorial XXXVI – Localización Tutorial III

En este articulo veremos como utilizar el emulador de GPS que viene con Mango, para nuestros desarrollos en el emulador. Cuando creamos nuestra aplicación de Windows Phone, Visual Studio nos propone en que framework queremos desarrollar nuestra aplicación, mostrándonos la siguiente ventana.

 

image

 

Una vez creado nuestro proyecto creamos un XAMl sencillo tal que este

1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 2 <Grid.RowDefinitions> 3 <RowDefinition /> 4 <RowDefinition /> 5 <RowDefinition /> 6 <RowDefinition /> 7 <RowDefinition /> 8 </Grid.RowDefinitions> 9 <Grid.ColumnDefinitions> 10 <ColumnDefinition /> 11 <ColumnDefinition /> 12 </Grid.ColumnDefinitions> 13 <TextBlock Height="30" HorizontalAlignment="Right" Name="textBlock1" Text="Longitud:" VerticalAlignment="Center" TextAlignment="Right" /> 14 <TextBlock Height="30" HorizontalAlignment="Right" Name="textBlock2" Text="Latitud:" TextAlignment="Right" VerticalAlignment="Center" Grid.Row="1" /> 15 <TextBox Grid.Column="1" HorizontalAlignment="Left" Name="txtLongitud" Text="" VerticalAlignment="Center" Width="222" /> 16 <TextBox HorizontalAlignment="Left" Name="txtLatitud" Text="" VerticalAlignment="Center" Width="222" Grid.Column="1" Grid.Row="1" /> 17 <Button Content="Obtener Loca." Grid.ColumnSpan="2" Grid.Row="2" HorizontalAlignment="Center" Name="btnLocalizacion" VerticalAlignment="Center" /> 18 </Grid> 19

Como resultado la pantalla siguiente, un botón para recoger la localización y mostrarla en la cajas de texto.

 

image

El code-behind seria

 

1 public MainPage() 2 { 3 InitializeComponent(); 4 btnLocalizacion.Click += new RoutedEventHandler(btnLocalizacion_Click); 5 } 6 7 void btnLocalizacion_Click(object sender, RoutedEventArgs e) 8 { 9 GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(); 10 watcher.Start(); 11 txtLatitud.Text = watcher.Position.Location.Latitude.ToString(); 12 txtLongitud.Text = watcher.Position.Location.Longitude.ToString(); 13 watcher.Stop(); 14 }

Vamos a utilizar las nuevas herramientas del emulador que vienen con Mango para poder probar nuestra aplicación. Si lanzamos la aplicación en el emulador tendremos la pantalla anterior si pulsamos el botón de obtener Localización , sse nos mostrara en cada caja de texto los valores NaN, es decir, no ha podido recuperar la localización. Ahora con Mango en la barra de herramientas del emulador nos aparece un nuevo botón

image

 

Pulsando sobre el nos aparece una nueva ventana para simular el acelerómetro y el GPS, en nuestro caso pulsando sobre la pestaña de Location se nos presenta la siguiente pantalla

 

image

Si queremos poner una localización en concreto, en la caja se Search ponemos una dirección damos a la lupa y se nos mostrara el mapa con esa dirección, por ejemplo si ponemos Bilbao

 

image

El siguiente paso es pinchar con el ratón en la posición del mapa y se irán poniendo psuhpin según vayamos pinchando, podemos poner tantos como queramos como por ejemplo simular una ruta

image

 

Como podéis ver en la imagen anterior tenemos Current Location con un valor el del PushPin con el número 1 y luego una lista con los siguientes puntos. Si pinchase ahora en el botón obtendría una localización correcta.

 

image

Con esta herramienta podemos simular que el teléfono sigue una ruta determinada por unos puntos, aquí tenéis un video para que veáis el partido que se le puede sacar

 

Demo Emulador GPS Mango

 

Una gran herramienta para nuestros desarrollos en Windows Phone

Windows Phone 7 – Tutorial XXXV – Localización Tutorial II

En el anterior articulo vimos como detectar los cambios de estado del GPS de nuestro teléfono, en este nos vamos a centrar en como recoger nuestra posición en todo momento. Como todos sabéis la localización GPS se mide a partir de tres valores Latitud, Longitud y Altitud, estos tres valores se encuentran en la propiedad Position del objeto GeoCoordinateWatcher, estos valores solo aparecerán si el estado es Ready, sino es así y se tomo la posición en otro momento aparecerán los datos de Latitud, Longitud y Altitud  aunque también se nos indicará junto a la propiedad TimeStamp que hora se tomo la posición.

Lo que nos interesa muchas veces es ir recogiendo la posición cada vez que cambie, por ejemplo, para un programa de rutas de bici…. Para ello debemos utilizar el evento PositionChanged que se lanzara cada vez que el usuario cambie de posición. Es importante recordar que si queremos cambiar elementos visuales de la UI tendremos que utilizar el objeto Dispatcher.

Como siempre es mejor verlo en líneas de código os la dejo aquí.

 

1 GeoCoordinateWatcher geowatcher; 2 private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) 3 { 4 geowatcher = new GeoCoordinateWatcher(); 5 geowatcher.PositionChanged += geowatcher_PositionChanged; 6 } 7 private void geowatcher_PositionChanged(object sender, 8 GeoPositionChangedEventArgs<GeoCoordinate> e){ 9 var locationText = PositionString(e.Position.Location); 10 this.Dispatcher.BeginInvoke(() = > this.GeoLocationText.Text = locationText); 11 } 12 private string PositionString(GeoCoordinate position) 13 { 14 return "Latitude: " + position.Latitude.ToString() + Environment.NewLine + 15 "Longitude: " + position.Longitude.ToString() + Environment.NewLine + 16 "Altitude: " + position.Altitude.ToString(); 17 } 18

Generalmente queremos coger la posición del GPS cada cierto tiempo y no siempre, por ejemplo, coger la posición cada 100 metros, para ello tendremos que utilizar la propiedad MovementThreshold donde le indicaremos cada cuantos metros como mínimo debe de ejecutarse el evento PositionChanged.

 

Ahora viene la pregunta del millo, como probamos en nuestro emulador?. La repuesta en estos momentos no es tan sencilla ya que tendremos que elegir entre la versión 7.0 o Mango, en este articulo vamos a ver las dos empezando por la primera versión 7.0

Como en nuestro emulador no disponemos de los sensores debemos de utilizar Mock para simular el GPS, para ello Microsoft nos provee de la interfaz IGeoPositionWatcher < GeoCoordinate > para que creemos nuestro Mock, en este articulo no vamos a ver como crear nuestro Mock sino utilizar uno ya hecho. Si hay que decir que esto es valido para cuando desarrollemos para la versión 7.0, ya que Mango nos va a proporcionar las herramientas de simulación integradas con el emulador que veremos en el siguiente articulo.

Yo utilizo Windows Phone GPS Emulator una pequeña aplicación hecha en WPF que nos va a permitir probar nuestra aplicación en el emulador aunque no tengamos GPS. Con esta herramienta podemos enviar tanto un punto simulando nuestra localización, como una ruta con puntos intermedios.

La herramienta incluye

  • Una aplicación windows que emula el GPS
  • el assembly Windows Phone GPS Emulator
  • Una simple aplicación de test
  • Una aplicación completa utilizando BingMaps

Para usarlo en nuestra aplicación debemos de seguir unos sencillos pasos. El paquete de descarga nos ofrece la dll GPSEmulatorClient, esta dll contiene la clase GeoCoordinateWatcher que cumple la interfaz IGeoPositionWatcher < GeoCoordinate > de la clase System.Device.Location.GeoCoordinateWatcher, de manera que programaticamente nos va a dar igual utilizar una que otra ya que solo se diferencian en el namespace.

Debemos de crear una variable de compilación en debug y la llamamos GPS_EMULATOR , de esta manera distinguiremos las llamadas a los métodos de la dll “real” con la de “mock”, por ejemplo.

1 #if GPS_EMULATOR 2 _Watcher = new GpsEmulatorClient.GeoCoordinateWatcher(); 3 #else 4 _Watcher = new System.Device.Location.GeoCoordinateWatcher(); 5 #endif

De esta manera podemos probar todo nuestro código que afecte a la localización en el emulador perfectamente, además las llamadas a métodos de localización de la dll de mock se comunican con la aplicación WPF a través de WCF, mostrándonos información en el plano y pudiendo enviar información de la aplicación al GPS, por ejemplo si solicitamos una posición en la aplicación del teléfono cogerá la posición que tenga la aplicación WPF, de manera que la aplicación WPF hace las veces de GPS

Debemos de recordar que para ejecutar la aplicación en WPF tiene que tener permisos de administrador, sino no será capaz de crear los canales de WCF, es una herramienta muy útil cuando desarrollamos contra el GPS, pero nunca debemos olvidarnos de probar contra un dispositivo físico

Windows Phone 7 – Tutorial XXXIV – Localización Tutorial I

En esta serie de artículos trataremos de aprender como utilizar el GPS de nuestro Windows Phone además de aprovecharnos del control Bing Maps. En este primer articulo trataremos el objeto GeoCoordinateWatcher, este objeto es el que nos proporcionará el acceso al GPS del teléfono.Esta clase se encuentra en la dll System.Device.dll que tendremos que hacer referencia en nuestros proyectos.

Lo primero que tenemos que saber es que este objeto nos proporciona el estado del GPS del teléfono a través de la enumeración GeoPositionStatus, para detectar los cambios de estado de nuestro GPS y actuar en consecuencia en nuestra aplicación utilizaremos el evento StatusChanged.

Cuando instanciamos el objeto su estado siempre será NoData, hasta que no arranquemos el servicio con Start no cambiara de estado comprobando si el GPS esta disponible o no indicándolo en el estado. En este sencillo código podemos probar la aplicación.

 

1 GeoCoordinateWatcher geowatcher; 2 private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e){ 3 geowatcher = new GeoCoordinateWatcher(); 4 geowatcher.StatusChanged += geowatcher_StatusChanged; 5 } 6 private void StartButton_Click(object sender, RoutedEventArgs e){ 7 geowatcher.Start(); 8 } 9 private void StopButton_Click(object sender, RoutedEventArgs e){ 10 geowatcher.Stop(); 11 } 12 private void geowatcher_StatusChanged(object sender, 13 GeoPositionStatusChangedEventArgs e){ 14 this.Dispatcher.BeginInvoke(() = > { 15 this.StatusText.Text = e.Status.ToString(); 16 }); 17 } 18

Si se nos muestra el estado Disabled debemos de chequear la propiedad Permission de la instancia de nuestro objeto GeoCoordinateWatcher, esta propiedad devolverá Granted, Denied, o Unknown, valores de la enumeración GeoPositionPermission , dependiendo de estos valores deberemos de solicitar al usuario permiso para que nuestra aplicación acceda a al GPS y recoger la posición.

Al código anterior en el evento Status_Changed podemos actuar antes los diferentes estados

1 if (geowatcher.Status == GeoPositionStatus.Disabled) 2 { 3 if (geowatcher.Permission == GeoPositionPermission.Denied) 4 { 5 MessageBox.Show("El servicio de localización esta deshabilitado."); 6 } 7 else 8 { 9 MessageBox.Show("El servicio de localización no esta funcionando."); 10 } 11 geowatcher.StatusChanged -= new EventHandler<GeoPositionStatusChangedEventArgs>(geowatcher_StatusChanged); 12 geowatcher.Stop(); 13 } 14 else if (geowatcher.Status == GeoPositionStatus.Initializing) 15 { 16 userMessage.Text = "Inicializando localización"; 17 } 18 else if (geowatcher.Status == GeoPositionStatus.NoData) 19 { 20 MessageBox.Show("Los datos de localización no esta disponible"); 21 } 22 else if (geowatcher.Status == GeoPositionStatus.Ready) 23 { 24 25 }

A la hora de utilizar el GPS tendremos que tener en cuenta si queremos que recoja la posición del GPS, de la Wifi o de la red de móvil, dependiendo de la aplicación y sus necesidades será necesario una alta precisión o no. Esto es importante para que gestionemos bien el gasto de batería. Este valor lo podemos indicar a partir de la propiedad DesiredAccuracy  y se lo indicaremos con la enumeración GeoPositionAccuracy que contiene los valores High y Low, por defecto es Low con lo que utilizará la red de móvil o wifi para coger la posición, si queremos que tire del GPS le tendremos que indicar el valor High.

En el siguiente articulo veremos como coger la posición del GPS una vez que lo tenemos en estado Ready.

Windows Phone 7 – Tutorial XXXIII – Utilizar TweetSharp para autenticarse

Después de unos correos que me han llegado a raíz de mi ultimo articulo, la gente me ha estado preguntando como usar autenticarse usando la librería Tweetsharp que recomendaba en ese articulo.

La verdad es que es muy sencilla de utilizar y me voy a saltar los pasos de como recoger los APIKey, ConsumerKey y ConsumerSecret que lo explicaba en el anterior articulo. Como siempre lo voy a realizar con un ejemplo, en este caso de consola.

El primer paso lógicamente es bajarnos la librería de Codeplex que se encuentra en la siguiente direción:TweetSharp Library.

El segundo paso es tambien facil, añadimos las referencias Hammock , Newtonsoft.Json , TweetSharp , TweetSharp.Twitter a nuestro proyecto

 

 

El siguiente paso ya es codificar la llamada, como veries el código es muy simple

 

1 using System; 2 using System.Configuration; 3 using System.Diagnostics; 4 using TweetSharp; 5 using TweetSharp.Model; 6 using TweetSharp.Twitter.Service; 7 8 namespace ConsoleApplication1 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 15 TwitterClientInfo twitterClientInfo = new TwitterClientInfo(); 16 twitterClientInfo.ConsumerKey = ConsumerKey; 17 twitterClientInfo.ConsumerSecret = ConsumerSecret; 18 //Creamos el servicio de Twitter 19 TwitterService twitterService = new TwitterService(twitterClientInfo); 20 21 if (string.IsNullOrEmpty(AccessToken) || string.IsNullOrEmpty(AccessTokenSecret)) 22 { 23 //recogemos el TokenSecret y AuthorisationUrl 24 25 OAuthToken requestToken = twitterService.GetRequestToken(); 26 string authUrl = twitterService.GetAuthorizationUrl(requestToken); 27 28 29 Console.WriteLine("Permite a esta APP enviar Tweets"); 30 Process.Start(authUrl); //Lanzamos el navegador con AuthUrl. 31 32 //Permitir la APP 33 Console.WriteLine("Introduce el PIN:"); 34 string pin = Console.ReadLine(); 35 36 OAuthToken accessToken = twitterService.GetAccessToken(requestToken, pin); 37 38 string token = accessToken.Token; 39 string tokenSecret = accessToken.TokenSecret; 40 41 Console.WriteLine("AccessToken: " + token); 42 Console.WriteLine("AccessTokenSecret: " + tokenSecret); 43 } 44 45 twitterService.AuthenticateWith(AccessToken, AccessTokenSecret); 46 twitterService.SendTweet("Mi primer Tweet desde Tweetsharp"); 47 Console.WriteLine("Introduce un Tweet"); 48 string tweetMessage; 49 50 while (true) 51 { 52 tweetMessage = Console.ReadLine(); 53 if(tweetMessage.ToLower() == "salir") 54 { 55 break; 56 } 57 twitterService.SendTweet(tweetMessage); 58 } 59 } 60 61 62 63 #region ConsumerKey & ConsumerSecret 64 private static string ConsumerSecret 65 { 66 get { return ConfigurationManager.AppSettings["ConsumerSecret"]; } 67 } 68 69 private static string ConsumerKey 70 { 71 get { return ConfigurationManager.AppSettings["ConsumerKey"]; } 72 } 73 74 private static string AccessToken 75 { 76 get { return ConfigurationManager.AppSettings["AccessToken"]; } 77 } 78 private static string AccessTokenSecret 79 { 80 get { return ConfigurationManager.AppSettings["AccessTokenSecret"]; } 81 } 82 #endregion 83 } 84 }

 

Bien esto funciona para este tipo de aplicaciones pero para nuestro querido Windows Phone deberemos de optar por otro método mas sencillo y es utilizar xAuth en nuestra aplicación, TweetSharp nos facilita este tipo de autenticación en Twitter y es tan sencillo como

 

1 TwitterService service = new TwitterService("consumerKey", "consumerSecret"); 2 OAuthAccessToken access = service.GetAccessTokenWithXAuth("username", "password");

Como veis mucho mas sencillo si es posible, tenéis información de como se trabaja con este tipo de autenticación en http://apiwiki.twitter.com/Twitter-REST-API-Method:-oauth-access_token-for-xAuth

 

Espero que no hagáis muchas aplicaciones de Twitter

Windows Phone 7 – Tutorial XXXII–Seguridad VI–Autenticación OAuth

En la actualidad redes sociales como Twitter o Facebook están implementando la autenticación OAuth (Open Authorization) para las aplicaciones externas, de manera que si desarrollamos un cliente Twitter nuestra aplicación deberá autenticarse mediante este método. En este artículo vamos a ver como realizar esta autenticación contra Twitter que utiliza autenticación Oauth1.0.

La manera de autenticarse con OAuth es a través de una pagina web que nos proporciona en este caso Twitter donde el usuario se autenticará con su cuenta de Twitter, una vez autenticado esta página web nos mostrará un PIN que será el token que deberemos coger y utilizar para todas las llamadas que utilicemos para esa cuenta de Twitter, como podréis suponer esto lo tendremos que realizar a través de un control webbrowser, pero bueno esto lo veremos mas adelante.

Lo primero que tendremos que hacer es crear una cuenta de desarrollador en Twitter, para ello iremos al sitio http://dev.twitter.com

 

image

image

 

Debemos elegir en tipo de aplicación Client, esto es importante porque cuando el usuario se autentique en la web que le presentará twitter debemos de recoger el PIN que le asigne.

image

En esta ultima ventana tenemos ConsumerKey y ConsumerSecret que tendremos que utilizar en nuestra aplicación y luego nos enseñan las url necesarias para autenticarnos

image

Cuando el usuario utilice nuestra aplicación en Windows Phone 7 deberá seguir estos pasos para autenticarse

 

twiiter_HomeScreentwitter_startScreenimagetwitter_signIn_2tiwtter_authorize

Bueno empezamos a desarrollar nuestra conexión a Twitter, para ello crearemos nuestra aplicación a la que llamaremos AutenticacionOAuthTwitter. En nuestra pagina Main insertaremos un botón y un navegador, dentro del botón nos subscribiremos al evento Click para empezar la autenticación. No lo vamos a realizar con MVVM para que sea mas sencillo entenderlo.

Para entender los siguientes pasos yo recomiendo leer la pagina de Twitter en la que explica como se realiza la autenticación paso a paso, podeis acceder desde esta dirección http://dev.twitter.com/pages/auth

Lo primero que vamos a hacer es crear la clase OAuthAuthenticate que se encargara de toda la autenticación, esta clase tendrá las propiedades

1 public class OAuthAuthenticate 2 { 3 public string RequestUri { get; set; } 4 public string AuthorizeUri { get; set; } 5 public string AccessUri { get; set; } 6 7 public string Method { get; set; } 8 9 public string NormalizedUri { get; set; } 10 public string NormalizedParameters { get; set; } 11 12 public string VerifierPin { get; set; } 13 14 public string ConsumerKey { get; set; } 15 public string ConsumerSecret { get; set; } 16 public string Token { get; set; } 17 public string TokenSecret { get; set; } 18 19 public IDictionary<string, string> Parameters { get; private set; } 20 }

En estas propiedades guardaremos las uri de acceso a la autenticación, autorización.. que nos ha proporcionado Twiiter, el método de paso de parámetros si es POST o GET , nuestros ConsumerKey y ConsumerSecret…., además de un diccionario donde guardaremos los parámetros que nos devuelva Twitter cuando pedimos el Token.

 

En nuestro caso las inicializaremos con 

 

1 RequestUri = "https://api.twitter.com/oauth/request_token", 2 AuthorizeUri = "https://api.twitter.com/oauth/authorize", 3 AccessUri="https://api.twitter.com/oauth/access_token", 4 Method = "POST", 5 ConsumerKey = "Tu ConsumerKey", 6 ConsumerSecret = "Tu ConsumerSecret"

Ahora crearemos nuestro método de autenticación al que le pasaremos dos parámetros el objeto browser donde el usuario va a realizar la autenticación y un objeto callback para que una vez producida la autenticación por ejemplo hagamos invisible el navegador. La firma sería la siguiente.

public void Authenticate(WebBrowser browser, Action<IDictionary<string, string>> callback)

 

Lo primero que  debemos hacer es recoger el token de petición que Twitter nos proporciona, para ello utilizamos la uri de la propiedad RequestUri a través de una petición HttpWebRequest, esta petición tal como nos indica la documentación de Twitter debe de ir con una serie de parámetros en el que se indica la versión de OAuth que utilizamos, el TimeStamp, si utilizamos HMACSHA1… esto lo realizaremos en el método

 

1 public static string GenerateSignature(this OAuthRequest request, string uri) 2 { 3 if (!string.IsNullOrEmpty(request.Token)) 4 { 5 request.Parameters[OAuthTokenKey] = request.Token; 6 } 7 8 if (!string.IsNullOrEmpty(request.VerifierPin)) 9 { 10 request.Parameters[OAuthVerifierKey] = request.VerifierPin; 11 } 12 13 request.Parameters[OAuthConsumerKeyKey] = request.ConsumerKey; 14 request.Parameters[OAuthVersionKey]=OAuthVersion; 15 request.Parameters[OAuthNonceKey]=GenerateNonce(); 16 request.Parameters[OAuthTimestampKey]=GenerateTimeStamp(); 17 request.Parameters[OAuthSignatureMethodKey]=HMACSHA1SignatureType; 18 request.Parameters[OAuthConsumerKeyKey]=request.ConsumerKey; 19 20 string signatureBase = GenerateSignatureBase(request, uri); 21 22 HMACSHA1 hmacsha1 = new HMACSHA1(); 23 hmacsha1.Key = Encoding.UTF8.GetBytes(string.Format("{0}&{1}", UrlEncode(request.ConsumerSecret), string.IsNullOrEmpty(request.TokenSecret) ? "" : UrlEncode(request.TokenSecret))); 24 25 var signature = ComputeHash(signatureBase, hmacsha1); 26 request.Parameters[OAuthSignatureKey] = UrlEncode(signature); 27 return signature; 28 } 29

 

1 public void RetrieveRequestToken(Action Callback) 2 { 3 this.GenerateSignature(this.RequestUri); 4 5 var request = HttpWebRequest.Create(this.NormalizedUri); 6 request.Method = this.Method; 7 request.Headers[HttpRequestHeader.Authorization] = this.GenerateAuthorizationHeader(); 8 9 request.BeginGetResponse((result) => 10 { 11 var req = result.AsyncState as HttpWebRequest; 12 var resp = request.EndGetResponse(result) as HttpWebResponse; 13 14 using (var strm = resp.GetResponseStream()) 15 using (var reader = new StreamReader(strm)) 16 { 17 var responseText = reader.ReadToEnd(); 18 this.ParseKeyValuePairs(responseText); 19 } 20 21 Callback(); 22 23 }, request); 24 25 } 26

 

 

1 public void Authenticate(WebBrowser browser, Action<IDictionary<string, string>> callback) 2 { 3 var baseAuthorizeUri = this.AuthorizeUri; 4 browser.Navigated += (s, e) => 5 { 6 if (e.Uri.AbsoluteUri.ToLower().StartsWith(baseAuthorizeUri)) 7 { 8 if (!e.Uri.Query.Contains("oauth_token")) 9 { 10 var htmlString = browser.SaveToString(); 11 12 var authPinName = "oauth_pin>"; 13 var startDiv = htmlString.IndexOf(authPinName) + authPinName.Length; // eg <DIV id=oauth_pin>4697728</DIV></DIV> 14 var endDiv = htmlString.IndexOf("<", startDiv); 15 var pin = htmlString.Substring(startDiv, endDiv - startDiv); 16 17 this.VerifierPin = pin; 18 this.RetrieveAccessToken(callback); 19 } 20 } 21 }; 22 23 // Obtener el token 24 RetrieveRequestToken(() => 25 { 26 browser.Dispatcher.BeginInvoke(() => 27 { 28 browser.Navigate(new Uri(this.AuthorizeUri)); 29 }); 30 }); 31 } 32


Ya solo nos queda un paso y es recoger el token de acceso a tarves de la uri de acceso que nos indica Twitter, si os fijáis en el evento OnNavigated la ultima instrucción es RetrieveAccessToken que recogera el token de acceso, que es muy parecido al método RetriveRequestToken de antes.

1 public void RetrieveAccessToken(Action<IDictionary<string, string>> Callback) 2 { 3 4 5 this.GenerateSignature(this.AccessUri); 6 7 var request = HttpWebRequest.Create(this.NormalizedUri); 8 request.Method = this.Method; 9 request.Headers[HttpRequestHeader.Authorization] = this.GenerateAuthorizationHeader(); 10 request.BeginGetResponse((result) => 11 { 12 var req = result.AsyncState as HttpWebRequest; 13 var resp = request.EndGetResponse(result) as HttpWebResponse; 14 15 Dictionary<string, string> responseElements; 16 17 using (var strm = resp.GetResponseStream()) 18 using (var reader = new StreamReader(strm)) 19 { 20 var responseText = reader.ReadToEnd(); 21 responseElements = this.ParseKeyValuePairs(responseText); 22 } 23 24 Callback(responseElements); 25 26 }, request); 27 28 } 29 } 30 }

Una vez seguidos estos pasos ya tenemos nuestra autenticación en Twitter, deberemos grabar estos valores en el IsolatedStoraged para que el usuario no tenga que volverse a identificar cada vez que arranque la aplicación.

Si queréis hacer una aplicación para Twitter os recomiendo utilizar TweetSharp que os va a abstraer de la comunicación con la api de Twitter, este articulo ha sido para que entendais la forma de comunicarnos con un sistema con autorización OAuth.

Windows Phone 7 – Tutorial XXXI–Seguridad V–Autenticación Basica

Cuando nos conectamos a través de servicios WCF, si estos servicios están desarrollados por nosotros es recomendable que utilicemos autenticación en los mismos intentando que al menos las llamadas a nuestros servicios web tengan autenticación.

En este caso vamos a ver la autenticación básica  de nuestros servicios WCF, lo primero que tenemos que hacer es habilitar la autenticación básica en nuestros sitio Web que aloja los servicios web que consumimos, esto lo configuramos en el Internet Information Services (IIS) Manager console (Start ➪ Control Panel ➪ Administrative Tools IIS Manager) seleccionamos nuestros sitio y habilitamos Basic Authentication como en la imagen pulsando en Enable

image

Si deshabilitamos Anonymous Authentication y habilitamos Basic Authentication si nos vamos al Internet Explorer veremos que nos pedirá un usuario y password que serán las credenciales de Windows.

Para llamar al servicio WCF desde tu aplicación de Windows Phone 7 deberemos de enviar las credenciales en en la propiedad Credentials del objeto HttpWebRequest, tan sencillo como este código

1 private void BasicCallServiceButton_Click(object sender, RoutedEventArgs e){ 2 var client = new BasicAuthSample.BasicAuthServiceClient(); 3 client.ClientCredentials.UserName.UserName =<username>”; 4 client.ClientCredentials.UserName.Password =<password>”; 5 client.DoWorkCompleted += BasicService_DoWorkCompleted; 6 client.DoWorkAsync(); 7 } 8 void BasicService_DoWorkCompleted(object sender, AsyncCompletedEventArgs e){...}

1 private void BasicAuthButton_Click(object sender, RoutedEventArgs e) 2 { 3 var request = HttpWebRequest.Create(“http://localhost/AuthSample/BasicAuth/BasicAuthText.txt”); 4 request.Credentials = new NetworkCredential(“ < username > ”, “ < password > ”); 5 request.BeginGetResponse(FileComplete, request); 6 }

Aparte de incluir en las credenciales el usuario y password deberemos de configurar nuestro servicio WCF indicándole que espere Basic Authentication, estolo configuramos en el elemento basicHttpBinding poniendo el modo a TransportCredentialOnly y asignando clientCredentialType a true.

1 <system.serviceModel> 2 <services> 3 <service behaviorConfiguration="BasicAuthBehavior" name="AuthSample.BasicAuth.BasicAuthService"> 4 <endpoint binding="basicHttpBinding" 5 bindingConfiguration="basicAuth" 6 contract="AuthSample.BasicAuth.IBasicAuthService" /> 7 <!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />--> 8 </service> 9 10 </services> 11 <bindings> 12 <basicHttpBinding> 13 <binding name="basicAuth"> 14 <security mode="TransportCredentialOnly"> 15 <transport clientCredentialType="Basic" /> 16 </security> 17 </binding> 18 19 </basicHttpBinding> 20 </bindings> 21 22

Cuando añadimos la referencia a nuestra aplicación de WCF automáticamente se creara el fichero Client.Config y veremos que el elemento 

security mode="TransportCredentialOnly"

 

1 <system.serviceModel > 2 <bindings > 3 <basicHttpBinding > 4 <binding name="BasicHttpBinding_IBasicAuthService" 5 maxBufferSize=”2147483647” 6 maxReceivedMessageSize=”2147483647” > 7 <security mode="TransportCredentialOnly" /> 8 </binding> 9 </basicHttpBinding> 10 </bindings> 11 <client> 12 <endpoint address="http://localhost/AuthSample/BasicAuth/BasicAuthService.svc" 13 binding=”basicHttpBinding” 14 bindingConfiguration=”BasicHttpBinding_IBasicAuthService” 15 contract=”BasicAuthSample.IBasicAuthService” 16 name=”BasicHttpBinding_IBasicAuthService” /> 17 </client> 18 </system.serviceModel>

A la hora de desarrollar debemos de tener en cuenta que si deshabilitamos Anonymous Authentication en el IIS, debemos de eleiminar el endpoint mex vereis que en el código anterior esta comentado, sino el servicio al llamarlo os dará un error, pero al quitar el endpoint mex no podremos añadirlo a nuestra aplicación de Windows Phone, por lo que tenemos que jugar con esta configuración para ejecutar y para añadir la referencia a nuestro servicio WCF.

Debemos de tener en cuenta que el usuario y password se envían en texto plano, con lo que utilizarlo sin SSL como vimos anteriormente en mi opinión no sirve de nada.