Empezando con Windows Phone 7.1 (y XXI)–La importancia de IoC en el diseño de pantallas

¿Y qué tendrá que ver una cosa con la otra? Podrías preguntarte.

Pues lo cierto es que, por la forma en que funcionan las principales herramientas de diseño (Visual Studio y Blend) para Windows Phone, la importancia es mucha.

¿Cómo funciona?

Tanto Visual Studio como Blend compilan el código de tu solución antes de tratar de mostrarte en pantalla el diseño de la página (pantalla).

image

image

Lo que pasa es que ambas son extremadamente cuidadosas en el control de errores, así que, cuando salta una excepción tratan de mostrarte todo lo posible. Y lo que no, lo dejan sin mostrar.

En una aplicación más o menos típica se consumirán servicios web o proveedores de datos antes de mostrar la información en pantalla. Puede ocurrir que algunas de estas fuentes de datos no se encuentren disponibles en tiempo de diseño. Aquí entra IoC.

¿Cuál es la relación entre IoC y la presentación en tiempo de Diseño?

Si estamos utilizando MVVM Light, disponemos de la clase ViewModelLocator.cs que es el proveedor de datos de toda nuestra aplicación (en otros frameworks las soluciones serán más o menos similares).

Si le echas un vistazo al esqueleto que se presenta un poco más abajo verás alguna cosa interesante.

   1: public class ViewModelLocator

   2: {

   3:     static ViewModelLocator()

   4:     {

   5:         ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

   6:  

   7:         if (ViewModelBase.IsInDesignModeStatic)

   8:         {

   9:             SimpleIoc.Default.Register<IConfiguracionDataService, Design.ConfiguracionDataService>();

  10:             SimpleIoc.Default.Register<IContextoGeneralDeDatos, Design.ContextoGeneralDeDatos>();

  11:             SimpleIoc.Default.Register<IFourSquareContexto, Design.FourSquareContexto>();

  12:  

  13:             SimpleIoc.Default.Register<ILocationService, Design.LocationService>();

  14:         }

  15:         else

  16:         {

  17:             // Proveedores de datos

  18:             SimpleIoc.Default.Register<IConfiguracionDataService, ConfiguracionDataService>();

  19:             SimpleIoc.Default.Register<IContextoGeneralDeDatos, ContextoGeneralDeDatos>();

  20:             SimpleIoc.Default.Register<IFourSquareContexto, FourSquare.FourSquareContexto>();

  21:  

  22:             // Para localización

  23:             SimpleIoc.Default.Register<ILocationService, LocationService>();

  24:         }

  25:  

  26:         // Para los recursos

  27:         SimpleIoc.Default.Register<ITraductorAppBar, TraductorAppBar>();

  28:  

  29:         // Registramos VistasModelo

  30:         SimpleIoc.Default.Register<ConfiguracionViewModel>();

  31:         SimpleIoc.Default.Register<FourSquareLoginViewModel>();

  32:         SimpleIoc.Default.Register<CheckInViewModel>();

  33:         SimpleIoc.Default.Register<UsuarioViewModel>();

  34:         SimpleIoc.Default.Register<MainViewModel>();

  35:     }

  36: }

Sin entrar en mucho detalle, se puede ver como hay tres secciones importantes.

  1. La primera aplica sólo cuando estamos en modo de diseño (es decir, mostrando las páginas en el diseñador de Visual Studio o de Blend)
  2. La segunda aplica sólo cuando no estamos en modo de diseño.
  3. La tercera aplica en todos los casos.

Ya ves, utilizando IoC podemos proporcionar alternativas en tiempo de diseño y en tiempo de ejecución a servicios que, de otra manera nos darían problemas cuando no estamos ejecutando la aplicación.

El mismo esquema se utiliza para proporcionar conjuntos de pruebas.

Anuncios

Empezando con Windows Phone 7.1 (y XIII) – Creando una nueva vista. Navegación entre páginas.

¡El horror, oh el horror!

En el anterior post nos quedamos con una forma de crear un nuevo lugar un tanto deleznable.

image

Así pues, creo que lo mejor es hacer que la nueva interfaz aproveche la barra de aplicación de Windows Phone.

Aplicando algunos cambios.

Para ello, he realizado algunos cambios en la aplicación. He creado una carpeta en la solución donde podré organizar más fácilmente las páginas y he movido la página principal a dicha carpeta.

image

Esto me ha obligado a realizar algunos cambios menores en el código.

En el manifiesto de la aplilcación

image

En el cual se indica la página de inicio para la aplicación, he cambiado la ruta.

 1: <Tasks>

 2:     <DefaultTask

 3:         Name="_default"

 4:         NavigationPage="/Pages/MainPage.xaml" />

 5: </Tasks>

Y, en la propia página, he cambiado la url relativa a las imágenes.

 1: <controls:Panorama.Background>

 2:     <ImageBrush

 3:         ImageSource="../Resources/images/Panorama%20Green.png"/>

 4: </controls:Panorama.Background>

Ahora vamos a realizar algunos cambios en la página principal. De momento eliminaremos el PanoramaItem que estaba destinado a contener los controles para crear un nuevo lugar y añadiremos la posibilidad de crear un nuevo lugar desde cualquier punto de la página principal. Para ello, vamos a crear una ApplicationBar en la página principal.

 1: <phone:PhoneApplicationPage.ApplicationBar>

 2:     <shell:ApplicationBar

 3:             Mode="Minimized"

 4:             IsMenuEnabled="False"

 5:             Opacity="0.7">

 6:

 7:         <shell:ApplicationBarIconButton

 8:             x:Name="NuevoLugarButton"

 9:             IconUri="/Resources/icons/Add%20New%20Place.png"

 10:             Text="Nuevo Lugar" />

 11:     </shell:ApplicationBar>

 12: </phone:PhoneApplicationPage.ApplicationBar>

Esto nos permite disponer de una barra de aplicaciones que no siempre estará visible, de esta forma aprovecharemos al máximo el espacio vertical.

Asignando Acciones a los botones de la ApplicationBar

Maldición. El primer problema que me he encontrado es. ¿Cómo puedo utilizar Comandos con los botones de la Application Bar para aprovecharme del patrón visto antes en MVVM? El control dispone de una propiedad Click que te permite asignar código en el “Code Behind” de la Vista, pero no de la VistaModelo como vimos en el anterior post (mediante Binding).

El otro problema es. ¿Cómo puedo asignar al texto del botón una entrada de mi fichero de recursos? Ni con Visual Studio ni con Blend me permite hacer uso de mi clase para manejar los recursos de la aplicación.

Proporcionando soporte multi-idioma y comandos en un ApplicationBarIconButton

¿Queréis la respuesta rápida?

No es posible sin cierta cantidad de esfuerzo ya que la barra de aplicación no es un componente Silverlight. Se trata de un objeto controlado por el Shell de Windows Phone, con lo que no aplican las mismas reglas que a cualquier otro control que incluyas en tu aplicación.

Confused smile

Resumiento la situación actual

En fin, algo que parecía bastante trivial se está convirtiendo en un pequeño problema:

  1. La barra de aplicación no es un control Silverlight, con lo que trabajar con la misma haciendo uso del patrón MVVM resulta complicado (recordad que la idea es evitar, en la medida de lo posible) tocar el Code Behind de la página.
  2. La navegación se realiza mediante la clase NavigationService que está accesible desde la propia págia como una propiedad.
  3. Desde la VistaModelo deberíamos de evitar instanciar nuevas clases que nos introduzcan dependencias (si tienes la palabra clave “new” en tu código lo mejor que puedes hacer es revisar el código). Un patrón como IoC viene aquí que ni al pelo.
  4. Crear una nueva vista y asociar correctamente su VistaModelo de forma flexible.

Siguientes Pasos

Si bien es perfectamente posible realizar todas las tareas descritas en el punto anterior (con mayor o menor esfuerzo). Este es un buen momento para hacer un alto en el camino y revisar algunas opciones que nos ayudarán con el Modelo Vista Vista Modelo y proseguir con el desarrollo apoyándonos en alguno de los siguientes Frameworks.

Empezando con Windows Phone 7.1 (y X) – Creando un Contexto de Datos de Prueba con Blend

Cuando comienzas con el diseño de la aplicación es importante tener presente el aspecto que tendrá la misma. Para ello Blend resulta de mucha ayuda.

Mis Sitios Favoritos en Blend

Mis Sitios Favoritos en Blend

Como podéis ver, se muestra una página (en este caso con un control Panorama) y tres PanoramaItem. Dentro de cada uno de ellos existe un ListBox que, actualmente está vacío. Vamos a ver cómo es posible con Blend, crear una fuente de datos de prueba para poder ver el aspecto que tendrá el control en tiempo de diseño.

Para ello abriemos la pestaña Data y, para el proyecto, escogeremos la creación de una nueve fuente de datos a partir de un Objeto (Object Data Source).

Create Object Data Source

Create Object Data Source

La idea es decirle a Blend, que genere un fichero de datos de ejemplo partiendo del ViewModel que tenemos asociado a nuestra página. En mi caso, después de una pantalla de error debida a que estoy utilizando SQL CE en Windows Phone “No se puede cargar el archivo o ensamblado ‘Microsoft.Phone.Data.Internal'” (el ensamblado no está localizado en mi máquina, está dentro del propio teléfono o del emulador. Hablé de ello en este post).

Error Load Microsoft.Phone.Data.Internal

Error Load Microsoft.Phone.Data.Internal

Como decía, después de este bonito error, que podemos ignorar, seleccionamos la clase que implementa el ViewModel para el cual queremos generar el conjunto de datos de ejemplo.

Seleccionar la Clase que implementa el ViewModel

Seleccionar la Clase que implementa el ViewModel

A partir de aquí, es posible editar el fichero XAML que se crea para nutrirlo con datos de ejemplo.

Xaml con datos de ejemplo

Xaml con datos de ejemplo

En Visual Studio, será necesario marcar la propiedad BuildAction del fichero a “DesignData”

BuildAction a "Design Data"

BuildAction a "Design Data"

Y, posteriormente, crear una fuente de datos de diseño que apunte al fichero (yo lo he hecho a nivel de página, pero es posible hacerlo a nivel de control)

Contexto de Datos de Diseño de Página

Contexto de Datos de Diseño de Página

Con este pequeño esfuerzo ya tenemos elementos que pueden mostrarse en pantalla.

Algunos datos en modo diseño

Algunos datos en modo diseño

Ahora queda adaptar un poco el aspecto que tendrá cada elemento, pero esto lo dejaremos para otro post más adelante.