Acceso a Contactos y Calendarios en Windows Phone Mango

Hola a todos!

Hoy vamos a ver una de las novedades que nos traerá Windows Phone Mango a los desarrolladores: el API de contactos y calendarios.

En Windows Phone 7.5 se ha incluido la capacidad de acceder a la información de contactos y de calendarios que el usuario posee en el dispositivo. Este acceso es de solo lectura, pero nos permitirá trabajar con los datos de usuario de una manera más potente que los selectores de los que disponíamos hasta ahora.

Agregado de datos

Windows phone nos ofrece una vista agregada con todas las fuentes de datos que el usuario tenga configuradas en el sistema, esto es, las diferentes cuentas que tenga. No todas las cuentas ofrecen todos los datos que usan de forma pública en el API de contactos y calendarios. Podemos usar el enumerador StorageKind para conocer las posibles fuentes de datos.

En la siguiente tabla tenemos un resumen de los diferentes proveedores y que tipos de datos podemos obtener de cada uno:

Proveedor de datos

Datos disponibles

Dispositivo

Datos de contacto y calendario

Windows Live Social

Datos de contacto y calendario

Windows Live Rolodex

Datos de contacto y calendario

Exchange

Datos de contacto y calendario

Lista de contactos del operador

Datos de contacto

Facebook

Nombre y foto de contacto

Otras cuentas (Twitter, LinkedIn)

Ninguno

Existen ciertas “Buenas prácticas” que debemos seguir al acceder a los agregados de datos:

  • El usuario debe dar permiso explicito para acceder a los datos y debemos mostrar una póliza de privacidad que acepte. (Requerimiento 2.11 de las políticas de privacidad de Windows Phone)
  • En el manifiesto de nuestra aplicación (WMAppManifest.xml) debemos indicar la capacidad ID_CAP_CONTACTS para que el usuario sepa que accederemos a sus contactos.
  • Los datos de contactos se ofrecen como una vista de solo lectura, si necesitamos refrescar los datos debemos volver a realizar la consulta.
  • Podemos encontrar listas de datos de contactos muy grandes, debemos estar preparados, mostrando una indicación visual al usuario de que estamos cargando datos.
  • Es mejor usar los campos de búsqueda predefinidos en vez de usar LINQ siempre que sea posible, están indexados y son mucho más rápidos.

Contactos

Acceder y mostrar la información de contactos en Windows Phone es realmente sencillo, como veremos en el siguiente ejemplo.

En primer lugar, vamos a realizar un ejemplo que simplemente acceda a los contactos sin filtrar y nos muestre el total de contactos existentes.

Asumimos que tenemos una aplicación de Windows Phone con un botón llamado “btnCountContacts”, debemos incluir un using del namespace Microsoft.Phone.UserData en nuestra clase:

private void btnCountContacts_Click(object sender, RoutedEventArgs e)
{
    Contacts contactos = new Contacts();

    contactos.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contactos_SearchCompleted);
    contactos.SearchAsync(string.Empty, FilterKind.None, "Prueba de contactos");
}

La búsqueda de contactos se realiza de manera asíncrona, mediante el método SearchAsync, recibiendo la respuesta el manejador de eventos que indiquemos para el evento SearchCompleted:

void contactos_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
    MessageBox.Show(e.Results.Count().ToString());
}

 

En este caso simplemente mostramos el número total de contactos recuperados.

También del objeto Contacts podemos obtener las diferentes cuentas de las cuales se pueden obtener datos, mediante la propiedad Accounts:

Contacts contactos = new Contacts();
StringBuilder sb = new StringBuilder();
foreach (Account cuenta in contactos.Accounts)
{ 
    string c = string.Format(@"{0}{1}", cuenta.Kind,
                                            cuenta.Name);
    sb.AppendLine(c);
}
MessageBox.Show(sb.ToString());

 

De esta forma, obtendremos el tipo y nombre de cada cuenta que nos devuelva datos.

El siguiente ejemplo que podemos realizar nos permitirá mostrar los datos obtenidos al usuario, usando enlace a datos de Silverlight.

Partimos del mismo ejemplo anterior, recuperando todos los contactos existentes, recuerda añadir un using de Microsoft.Phone.UserData a tu clase.

En este caso, al recibir la información de contactos en el manejador del evento SearchCompleted la vamos a guardar en una propiedad pública ListaContactos que usaremos para enlazar en XAML.

public partial class MainPage : PhoneApplicationPage
{
    public List<Contact> ListaContactos { get; set; }

    // Constructor
    public MainPage()
    {
        InitializeComponent();
    }

    private void btnVerContacts_Click(object sender, RoutedEventArgs e)
    {
        Contacts contactos = new Contacts();

        contactos.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contactos_SearchCompleted);
        contactos.SearchAsync(string.Empty, FilterKind.None, "Prueba de contactos");
    }

    void contactos_SearchCompleted(object sender, ContactsSearchEventArgs e)
    {
        ListaContactos = new List<Contact>(e.Results);
        this.DataContext = ListaContactos;
    }
}

 

Por último podemos usar LINQ TO OBJECTS para filtrar los datos devueltos como si se tratasen de cualquier colección de objetos, por ejemplo para buscar un contacto con un email en concreto:

List<Contact> contactos = (from Contact con in e.Results
                            from ContactEmailAddress mail in con.EmailAddresses
                            where mail.EmailAddress.Contains("example")
                            select con).ToList();
this.DataContext = contactos;

 

Calendarios

El proceso de trabajo con calendarios es muy parecido al de contactos. Debemos recordar que, al igual que los contactos, los datos del calendario son de solo lectura. Lo primero que necesitamos realizar es añadir un using a Microsoft.Phone.UserData en nuestra clase.

El primer ejemplo que vamos a ver, simplemente obtendrá el acceso a los datos del calendario, y nos mostrará cuantos apuntes existen en los mismos, usando el objeto Appointments.

private void btnCountAppointments_Click(object sender, RoutedEventArgs e)
{
    Appointments apuntes = new Appointments();

    apuntes.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>(apuntes_SearchCompleted);
    apuntes.SearchAsync(DateTime.Now.AddMonths(-1), DateTime.Now, "Busqueda de apuntes");
}

La única diferencia con contactos es que, en este caso, realizamos la busqueda entre fechas, lo cual nos devolverá los apuntes de los calendarios comprendidos entre la fecha de inicio y de final indicadas, ambas incluidas. Recibimos la respuesta en el manejador del evento SearchCompleted al igual que en los contactos:

void apuntes_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
{
    MessageBox.Show(e.Results.Count().ToString());
}

 

También del objeto Appointments podemos usar la propiedad Accounts, que contiene todas las cuentas registradas en el teléfono que nos están devolviendo datos:

Appointments apuntes = new Appointments();
StringBuilder sb = new StringBuilder();
foreach (Account cuenta in apuntes.Accounts)
{
    string c = string.Format(@"{0}{1}", cuenta.Kind,
                                            cuenta.Name);
    sb.AppendLine(c);
}
MessageBox.Show(sb.ToString());

 

Con este código, obtendremos un cuadro de mensaje que contendrá todas las cuentas que nos sirven datos, con su tipo y nombre.

También podemos usar el resultado de la búsqueda en el objeto Appointments para mostrar datos en una lista.

Lo primero que necesitamos realizar es obtener todos los datos entre dos fechas y en el manejador del evento SearchCompleted rellenar nuestra ListaApuntes que se encuentra enlazada a la lista en XAML.

public partial class MainPage : PhoneApplicationPage
{

    public List<Appointment> ListaApuntes { get; set; }
    // Constructor
    public MainPage()
    {
        InitializeComponent();
    }

    private void btnVerApuntes_Click(object sender, RoutedEventArgs e)
    {
        Appointments apuntes = new Appointments();

        apuntes.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>(apuntes_SearchCompleted);
        apuntes.SearchAsync(DateTime.Now.AddMonths(-6), DateTime.Now.AddMonths(3), "Busqueda de apuntes");
    }

    void apuntes_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
    {
        ListaApuntes = new List<Appointment>(e.Results);
        this.DataContext = ListaApuntes;
    }
}

 

Por último también podemos usar LINQ TO OBJECTS para filtrar los resultados obtenidos en el manejador de eventos SearchCompleted, por ejemplo, para mostrar solo los eventos que tengan duración de día completo:

List<Appointment> apuntes = (from Appointment ap in e.Results
                                where ap.IsAllDayEvent == true
                                select ap).ToList();
this.DataContext = apuntes;

 

Tenemos que tener en cuenta, que para probar estos ejemplos necesitaremos hacerlo en un dispositivo de desarrollo, puesto que el emulador no contiene datos de ejemplo para el calendario, aunque sí para los contactos.

A continuación tenéis el código fuente de los dos ejemplos usados aquí, espero que os sea de utilidad y Happy Coding!

[WP7] Evento: Windows Phone: A new hope

wpmango

Hola a todos!

Este martes 26 de Julio estaré en el CIIN de Santander junto a Rafa Serna dando una charla sobre Windows Phone Mango, la nueva versión del sistema operativo para móviles de Microsoft.

Por mi parte veremos el pasado, presente y futuro de este sistema operativo, como desarrollar de forma productiva usando Expression Blend 4 y Visual Studio 2010, el patrón MVVM y recomendaciones para que nuestra aplicación sea certificada sin problemas además de algunas cosas más.

Rafa nos hablará de las posibilidades de Windows Phone para el desarrollo de aplicaciones de línea de negocio y algunas de las novedades que Mango incorporará a este efecto.

Aquí os dejo un enlace al registro del evento e información más extensa:
http://www.ciin.es/web/servicios/eventos/Paginas/20110726_EventoWP7.aspx?Fecha=26-07-2011

Espero veros!

Un saludo y happy coding!

SQL Server CE en Windows Phone Mango

Hola a todos!

Con Windows Phone 7.1 Microsoft ha introducido la posibilidad de usar bases de datos locales en nuestras aplicaciones mediante SQL Server CE (Compact Edition).

SQL Server CE usa archivos sdf para almacenar nuestra base de datos, en Windows Phone 7.1, estos archivos se guardan en nuestro almacenamiento aislado. Como vimos anteriormente una aplicación puede acceder solo al almacenamiento aislado que le corresponde por lo que no podremos compartir una misma base de datos para varias aplicaciones.

El modelo preferido para crear nuestra base de datos y trabajar con ella en esta versión de Windows Phone es el code first, código primero, por el cual deberemos crear nuestras clases e indicar el mapeo a tablas y columnas de cada clase y propiedad y a partir de estas clases crearemos la base de datos en tiempo de ejecución en el terminal, aunque existen herramientas, que veremos más adelante que nos permitirán crear nuestras clases a partir de una base de datos sdf que tengamos en tiempo de desarrollo.

Otra particularidad es que no usaremos Entity Framework para acceder a nuestros datos, en esta versión se ha decidido implementar LINQ TO SQL como ORM.

Por ahora, Windows Phone 7.1, soporta la mayoría de LINQ TO SQL, pero tenemos que prestar atención a ciertas limitaciones:

  • No podremos usar ExecuteCommand, ejecución de T-SQL no está soportada.
  • Objetos de ADO.NET, como DataReaders, no están soportados, todos los resultados se obtendrán como colecciones de objetos especificados por el contexto de datos.
  • Skip() y Take() requieren una lista ordenada para devolver los resultados.

Para empezar a trabajar con SQL Server CE lo primero que necesitamos será añadir una referencia al ensamblado System.Data.Linq en nuestra aplicación y un using del namespace System.Data.Linq.Mapping en nuestra clase. Vamos a crear una clase Customer, en la que podamos almacenar la información de un cliente y decorarla con los atributos necesarios para poder mapearla a una tabla Customers de nuestra futura base de datos

[Table(Name="Customers")]
public class Customer
{
    [Column(IsPrimaryKey=true, IsDbGenerated=true)]
    public int CustomerId { get; set; }
    [Column(CanBeNull=false)]
    public String FirstName { get; set; }
    [Column(CanBeNull=true)]
    public String LastName { get; set; }
}

Como podemos ver, es una clase normal y corriente la cual hemos decorado con atributos de System.Data.Linq.Mapping, Table para la clase, identificándola como una tabla, con el parámetro Name que nos permite especificar el nombre de la tabla relacionada en la base de datos (Customers) y Column para las propiedades, indicando si se trata de una clave primaria, si es autogenerada por la base de datos, si puede contener valores nulos y más parámetros que tenemos a nuestra disposición.

Una vez que tenemos creada nuestra clase de datos Customer, vamos a crear el contexto de datos de nuestra aplicación. Este contexto heredará de la clase DataContext del ensamblado System.Data.Linq, y expondrá toda la funcionalidad necesaria para poder trabajar con nuestra base de datos. Por ahora necesitamos la funcionalidad standard y que además nos permita trabajar con nuestra clase Customer:

public class AppDbContext : DataContext
{
    public AppDbContext(string connectionString) 
                            :base(connectionString)
    {

    }

    public Table<Customer> Customers
    {
        get
        {
            return this.GetTable<Customer>();
        }
    }
}

Es una clase muy sencilla, al heredar de DataContext ya tenemos toda la funcionalidad requerida implementada en nuestra clase base, simplemente añadimos una propiedad de tipo Table de Customer para exponer nuestra tabla Customers.

El constructor de nuestra clase AppDbContext requiere un parámetro que contenga la cadena de conexión hacia la base de datos que deseamos usar. En Windows Phone 7.1 el formato de cadena de conexión es especial y distinto del que estamos acostumbrados normalmente. Como nuestra base de datos se encuentra en el almacenamiento aislado la cadena de conexión se compone de “Data Source=’isostore:/” y la ruta en el almacenamiento aislado donde está nuestro sdf:

Data Source='isostore:/CustomersDb.sdf'

Lo único que debemos hacer para comenzar a trabajar con nuestra base de datos es, usando nuestra clase AppDbContext, consultar si nuestra base de datos existe y si no, crearla:

using (AppDbContext context = new AppDbContext("Data Source='isostore:/CustomersDb.sdf'"))
{
    if (!context.DatabaseExists())
        context.CreateDatabase();
}

Una vez que hemos realizado esto, podemos crear datos por defecto de una forma realmente sencilla, primero creamos una lista de customer con los datos que deseamos crear:

List<Customer> customers = new List<Customer>()
{
    new Customer() 
    { 
        FirstName = "Yeray", LastName = "Julián" 
    },
    new Customer()
    {
        FirstName = "Pedro", LastName = "Picapiedra"                        
    }
};

A continuación, los añadimos a la propiedad Customers de nuestra clase AppDbContext usando el método InsertAllOnSubmit, este método añade a la propiedad Customers los registros que hemos creado con un estado de pendiente de inserción:

context.Customers.InsertAllOnSubmit(customers);

Y por último solo nos queda indicar a nuestra clase AppDbContext que envíe los cambios a la base de datos usando el método SubmitChanges:

context.SubmitChanges();

Recuperar datos de nuestra base de datos también es muy sencillo, usando LINQ TO SQL, podemos consultar la propiedad Customers de nuestro contexto:

using (AppDbContext context = new AppDbContext("Data Source='isostore:/CustomersDb.sdf'"))
{
    Customers = context.Customers.ToList();
}

Como podemos ver, trabajar con SQL Server CE usando LINQ TO SQL en Windows Phone es muy sencillo y nos da muchísimas posibilidades para almacenar datos de forma sencilla y rápida en nuestras aplicaciones.

A continuación os dejo el ejemplo para que podáis descargarlo y jugar con el (Recordad que necesitareis las herramientas de desarrollo de mango para poder usarlo):

Espero que os sea de ayuda, en el próximo artículo veremos como con algunos simples trucos podemos optimizar muchísimo nuestra base de datos. Un saludo y Happy Coding