Windows Phone. Actualizando los mapas a la versión de Windows Phone 8

Después de varios días dándome cabezazos con el nuevo control de mapas, he conseguido amaestrarlo, aunque de la forma en la que me hubiera gustado. Como bien nos cuenta Yerary en su blog, Windows Phone 8 tiene un nuevo control de mapas con mucha más potencia que los anteriores, por muchas funcionalidades entre las que destaco las siguientes:

  • Los mapas son vectoriales y el usuario puede descargar los mapas para tenerlos Offline
  • Incluyen servicios de búsqueda de lugares y cálculos de rutas, con lo que obteniendo la nueva clave de aplicación del centro de desarrollo de Windows Phone nos permite utilizar también estos servicios.

Ahora bien, como ya nos pasó con el control de mapas de Bing de Windows 8, no parecen que estén bien terminados o con las funcionalidades que todos esperamos, y, sin entender el motivo, no existe un control que nos permita representar una colección de puntos, mediante el uso de Binding. Si miramos al control de Windows Phone 7, hacíamos lo siguiente para representar una serie de puntos:

        <my:Map  x:Name=»MyMap»  CredentialsProvider=»{Binding CredentialsProvider}»

                    ZoomLevel=»{Binding Zoom, Mode=TwoWay}»

                    Center=»{Binding Center, Mode=TwoWay}»>

            <my:MapItemsControl x:Name=»PushpinEstaciones»Â

                    ItemsSource=»{Binding EstacionesPushpin}» >

                <my:MapItemsControl.ItemTemplate>

                    <DataTemplate>

                        <my:Pushpin x:Name=»pushpin» Style=»{StaticResource CirclePushpin}» Background=»#FF4499ff»

                                Location=»{Binding Location}» Tap=»EstacionesTap»>

                            <Image Source=»{Binding Rotulo, Converter={StaticResource LogoConverterImage}}» Stretch=»Fill» />

                        </my:Pushpin>

                    </DataTemplate>

                </my:MapItemsControl.ItemTemplate>

            </my:MapItemsControl>

        </my:Map>

 

Como hijo del control de mapas, utilizábamos el control MapItemsControl enlazado a nuestro ViewModel con el ItemsSource. Si migramos a Windows Phone 8, y actualizamos los mapas, nos encontramos con que no tenemos este control, MapItemsControl, y que tendremos que crear nuestros puntos en código.

            foreach (var item in viewModel.EstacionesPushpin)

            {

                var estacionButton = new Button() {Content = item.Rotulo};

                //Creamos una overlay con el botón
						

                MapOverlay MyOverlay = new MapOverlay();

                MyOverlay.Content = estacionButton;

                //Establecemos la posición del elemento
						

                MyOverlay.GeoCoordinate = item.Location;

                //Creamos una capa y le añadimos el overlay
						

                MapLayer MyLayer = new MapLayer();

                MyLayer.Add(MyOverlay);

                MyMap.Layers.Add(MyLayer);

            }

 

Una mejor aproximación, recomendada en la MSDN, la encontramos en unas extensiones para el mapa que han incluido en el Windows Phone Toolkit. Con estas extensiones, podemos utilizar el MapItemsControl y enlazar su ItemsSource en código con la colección de nuestro ViewModel, porque no está implementado el Binding. Veamos cómo quedaría:

        <maps:Map x:Name="MyMap" ZoomLevel="{Binding Zoom, Mode=TwoWay}" Center="{Binding Center, Mode=TwoWay}">
																											

            <maptk:MapExtensions.Children>
										

                <maptk:MapItemsControl Name="PushpinEstaciones">
											

                    <maptk:MapItemsControl.ItemTemplate>
										

                        <DataTemplate>
								

                            <maptk:Pushpin GeoCoordinate="{Binding Location}" Style="{StaticResource CirclePushpin}"
																			

                                           Background="#FF4499ff" Tap="EstacionesTap" >
									

                                <Image Source="{Binding Rotulo, Converter={StaticResource LogoConverterImage}}" Stretch="Fill" />
																			

                            </maptk:Pushpin>
										

                        </DataTemplate>
								

                    </maptk:MapItemsControl.ItemTemplate>
										

                </maptk:MapItemsControl>
										

            </maptk:MapExtensions.Children>
										

        </maps:Map>
										

 

En la carga de la página, enlazamos el MapItemsControl a los datos.

PushpinEstaciones.ItemsSource = viewModel.EstacionesPushpin;

 

Además, tenemos que asegurarnos que antes de que enlacemos los datos se ejecuta un método que configura los controles de las extensiones:

        /// <summary>
								

        /// Setup the map extensions objects.
							

        /// All named objects inside the map extensions will have its references properly set
							

        /// </summary>
								

        /// <param name="map">The map that uses the map extensions</param>
										

        private void MapExtensionsSetup(Microsoft.Phone.Maps.Controls.Map map)

        {

            ObservableCollection<DependencyObject> children = MapExtensions.GetChildren(map);

            var runtimeFields = this.GetType().GetRuntimeFields();

 

            foreach (DependencyObject i in children)

            {

                var info = i.GetType().GetProperty("Name");

 

                if (info != null)

                {

                    string name = (string)info.GetValue(i);

 

                    if (name != null)

                    {

                        foreach (FieldInfo j in runtimeFields)

                        {

                            if (j.Name == name)

                            {

                                j.SetValue(this, i);

                                break;

                            }

                        }

                    }

                }

            }

        }

 

Dos opciones a elegir y, particularmente, ninguna me convence del todo. La primera porque metemos lógica de presentación en el código de la vista y la segunda porque no me convence el método que configura la extensión, porque estamos trabajando con un Toolkit que siempre ha tenido pequeños bugs y porque no tiene el Binding implementado.

¿Cuál elegirías tú?

 

Saludos a todos…

SharePoint 2013. Etiquetas de navegación administradas

Una de las grandes novedades de los sitios de publicación en SharePoint 2013 es la Navegación Administradas por Metadatos, que nos permite configurar nuestros sitios para que utilicen la jerarquía de términos para definir la navegación de nuestro sitio, incluyendo una Frienly Url para estas. Vean este artículo de mi blog.

Estos términos pueden ser usados como etiquetas y, por ejemplo, crearnos un campo de metadatos en el tipo de contenido de Página de Artículo para etiquetarla. Si tenemos unas páginas de autores de artículos, nos interesaría poder etiquetar estos artículos, con el autor que lo ha creado para que, desde la misma página de artículos, podamos poner un enlace que nos lleva a la información del autor. Quedaría tal como sigue:

www.misitio.com/articulos/article1

www.misitio.com/articulos/article2

www.misitio.com/autores/alberto-diaz-martin

www.misitio.com/autores/santiago-porras

Por defecto, para los campos de tipo Taxonomía tenemos un control que permite visualizar o editar esta información desde una página de publicación, y lo que estamos buscando es que, en el modo de visualización, no solo nos renderice el nombre del autor (valor de la etiqueta), si no que nos añade el enlace a la Friendly Url que le corresponde.

 

Para esto, nos vamos a crear un control de campo (FieldControl) que reciba el campo que queremos mostrar y localice en el almacenamiento de términos, la Friendly Url que le corresponde.

Nuestro control va a heredar el Microsoft.SharePoint.WebControls.BaseFieldControl y sobreescribir el método RenderFieldForDisplay que es el que se encarga de renderizar el valor del campo en modo no edición.

protected override void RenderFieldForDisplay(HtmlTextWriter output)

{

    //Obtenemos el campo y su valor de tipo TaxonomyField

    TaxonomyField field = this.Field as TaxonomyField;

    var tagValue = ListItem[field.Title] as TaxonomyFieldValue;

 

    if (tagValue != null)

    {

        //Obtenemos el Término de la taxonomía que corresponda con el valor del campo

        var taxSession = new TaxonomySession(SPContext.Current.Site);

        var taxTermStore = taxSession.DefaultSiteCollectionTermStore;

        var termSet = taxTermStore.GetTermSet(field.TermSetId);

        var term = termSet.GetTerm(new Guid(tagValue.TermGuid));

 

        //Obtenemos el Término de Navegación

        var navTerm = NavigationTerm.GetAsResolvedByWeb(term,

            SPContext.Current.Web,

            StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider);

 

        //Obtenemos el valor de la FriendlyUrl

        var url = «#»;

        if (navTerm != null)

        {

            url = navTerm.GetWebRelativeFriendlyUrl();

        }

         output.Write(«<a href='» + url + «‘>»);

        output.Write(tagValue.Label);

        output.Write(«</a>»);

    }

    else

    {

        base.RenderFieldForDisplay(output);

    }

}

 

Lo que tenemos que hacer es obtener el Term del valor de nuestro campo de Taxonomía para utilizar la nueva clase NavigationTerm que nos permite obtener la información de navegación de un término, del que obtenemos la url que estamos buscando.

Así, con este control y para cualquier término de navegación, nos devolvería su correspondiente Friendly Url, utilizándolo en nuestro Page Layout.

<%@ Register Tagprefix=»GSCControls» Namespace=»GSC.Publishing.Controls» Assembly=»GSC.Publishing.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXXXXX» %>

<GSCControls:TaxonomyNavigationControl FieldName=»ef3be664-8ac8-49de-b164-253fe97ad209″ runat=»server» />

 

Saludos a todos…