SharePoint: Valores específicos en columnas de tipo “Choice” (Elección) no persisten

noviembre 20, 2009
By

Debido a la filosofía del almacenamiento y vista de datos en listas de SharePoint es muy común el uso de columnas que etiquetan cada ítem en cierto sentido. Un tipo de columna muy utilizado en este sentido es Choice.

Cuando creamos una columna de tipo Choice debemos especificar cuáles son las opciones que el usuario podrá seleccionar al añadir un nuevo ítem. Además está la opción de permitirle especificar su propio valor si no conviene ninguno de los predeterminados, y aquí precisamente es donde se encuentra el problema. Es de esperarse que si un usuario necesitó, en algún momento, especificar su propio valor para algún ítem, este valor aparezca dentro de las opciones posibles en próximas ocasListaiones.

Ilustremos este proceso con el siguiente ejemplo: se quiere tener la información de las impresiones realizadas en una tienda de ofimática. Para ello podemos crear una lista sencilla con los siguientes campos:

  • Título de Impresión
  • Cantidad de Copias
  • Cantidad de Páginas

Con el objetivo de almacenar las dimensiones para cada impresión podemos incluir también una columna “Tamaño de Impresión” que para garantizar cierta uniformidad conviene hacerla de tipo Choice y como no podemos prever todas las posibles, además de incluir las dimensiones comunes de impresión permitiremos al usuario especificar su propio valor. Esto se puede hacer de manera fácil añadiendo una columna a la lista.

CreateCol

ColDef

Las imágenes anteriores describen parte del proceso de creación de la columna “Tamaño de Impresión” de tipo Choice con sus opciones predefinidas y la posibilidad de añadirle valores específicos.

Una vez hecho esto podemos añadir un nuevo elemento y especificar nuestro propio valor para la columna en cuestión:

newItemshowMissing

Si seguidamente queremos añadir otro ítem con el mismo valor especificado anteriormente veremos que no sale dentro de la lista de opciones y que debemos especificarlo nuevamente. Esto en principio no es un gran problema, pero trae consigo el riesgo de no poner el valor con el mismo formato de la vez anterior o con errores ortográficos, lo que podría afectar a cualquier filtro o vista que dependa de esta columna.

¿Cómo resolvemos el problema entonces?

Una buena vía que he encontrado en este sentido es intervenir en el momento en que se añade un nuevo elemento y si este tiene un valor que no esté presente en la lista de valores predeterminados añadirlo a la colección de valores del objeto SPFieldChoice que se corresponde con la columna. Esto se logra implementando un SPItemEventReceiver. Para ello vamos a crear un nuevo proyecto en VS2008 a partir de la plantilla Empty dentro del grupo de plantillas de SharePoint.

  • File > New Project > C# > SharePoint > Empty

creatingNew

Seguidamente haciendo uso nuevamente de las plantillas ds SharePoint vamos a añadir un elemento de tipo EventReceiver:

  • Project > Add New Item > Event Receiver

addingReceiver2 ListTemplate

Nos aseguramos de seleccionar la plantilla de la lista que contiene esta columna o CustomList si no hemos hecho nuestra lista a partir de ninguna plantilla.  Con esto VS se encarga por nosotros de preparar toda la infraestructura de la feature que activará esta funcionalidad en SharePoint.

Ahora tenemos dos clases una que hereda del tipo SPItemEventReceiver y otra que lo hace del tipo SPListEventReceiver, en nuestro caso solo nos interesa la que lo hace de SPItemEventReceiver y en particular el método ItemAdded que, como su nombre indica, es el invocado cada vez que un elemento es añadido. El siguiente código comprueba si el valor especificado para el nuevo ítem no está dentro del conjunto de opciones de la columna y, si es el caso, incluye dicho valor dentro de este conjunto:

    [CLSCompliant(false)]
    [TargetList("00bfea71-de22-43b2-a848-c05709900100")]
    [Guid("df51e097-5c06-49b4-a123-a45b19c109ff")]
    public class ImpresionesReceiverItemEventReceiver : SPItemEventReceiver
    {
        public override void ItemAdded(SPItemEventProperties properties)
        {
            try
            {
                DisableEventFiring();
                SPFieldChoice spf = (SPFieldChoice)properties.
Fields["Tamaño de Impresión"];
                string s;
                if (!spf.Choices.Contains(s = properties.
ListItem["Tamaño de Impresión"].ToString()))
                    spf.Choices.Add(s);
                spf.Update();
            }
            finally
            {
                EnableEventFiring();
            }
        }
    }

Ahora solo resta desplegar la solución desarrollada en el sitio que contiene la lista en cuestión. Una manera cómoda sería especificar la url de este sitio en la pestaña Debug dentro de las Propiedades del proyecto y luego sencillamente desplegar la solución a través del menú Build.

Algunas consideraciones generales

Hemos logrado que cada vez que se inserte un elemento se compruebe si el valor especificado para la columna en cuestión está dentro de la colección de valores que aparece por defecto, si no es así, lo añadimos a esta lista. Algo que no he tenido en cuenta por razones de simplificación es el hecho de que esta comprobación se hace cada vez que se añade un elemento a cualquiera de las listas de tipo CustomList del sitio en el que hicimos el despliegue. Para evitar esto simplemente debemos sustituir e valor del atributo TargetList de la clase que implementamos por el Id de la plantilla de la lista que contiene la columna.

Por otro lado es bueno mencionar que esta no es la única solución para este problema. Otra posibilidad hubiese sido crear una segunda lista que contenga las posibles dimensiones y sustituir la columna Tamaño de Impresión por otra de tipo LookUp vinculada a esta “lista de dimensiones”. Esto tiene la desventaja de crear una lista más con solo una columna para el identificador de cada formato y que además todas las listas con esta columna incluirían cada una de las entradas que aparezcan en la lista de dimensiones, lo cual puede que, en algún escenario, no sea deseable; de la manera que lo hemos desarrollado se hacen los cambios de manera local a cada lista. Por otro lado la solución con el LookUp tiene la ventaja de que no necesita programación alguna porque puede lograrse completamente a través de la interfaz web de SharePoint.

Por último quiero mencionar que la generalización de esta idea sería una feature interesante para SharePoint. Esta generalización pudiera lograrse añadiendo un fichero de configuración (quizás un xml dentro del directorio virtual del sitio) que especifique los identificadores de las columnas que quisierámos se comportaran de esta manera, este fichero se consultaría en el método ItemAdded: si el ítem añadido especifica un nuevo valor para alguna columna de tipo Choice y el identificador de esta columna se encuentra especificado dentro del fichero de configuración, entonces se garantiza la persistencia de ese valor.

Tags:

3 Responses to SharePoint: Valores específicos en columnas de tipo “Choice” (Elección) no persisten

  1. José Menéndez on noviembre 23, 2009 at 10:40 am

    Buen post, esto es bastante útil, gracias por compartirlo … a ver si los de Microsoft te escuchan (mejor te leen :-) y lo incluyen en la próxima…

  2. Maximo Lopez on noviembre 24, 2009 at 1:15 pm

    Muy claro y didactico. Me gusta tu enfoque creativo dentro del sharepoint. Gracias.

  3. Raimil on febrero 17, 2010 at 3:02 pm

    Muy Bueno tu artículo Abel. Es bastate útil y ahorra trabajo. En cuanto a la forma de extender este trabajo, aquí propongo una vía.

    public override void ItemAdded(SPItemEventProperties properties)
    {
    try
    {
    DisableEventFiring();
    var choices = properties.ListItem.Fields.OfType();
    foreach (SPFieldChoice choice in choices)
    {
    string s;
    if (!choice.Choices.Contains(s = roperties.ListItem[choice.InternalName].ToString()))
    choice.Choices.Add(s);
    choice.Update();
    }
    }
    finally
    {
    EnableEventFiring();
    }

    }

    De esta forma se pueden actualizar todos las columnas de tipo Choice en una lista, y solo resta especificar que este receiver actua en esas listas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Acerca del autor...

Abel García Celestrín

Abel
Soy estudiante de 5to año de Ciencias de La Computación en La Universidad de La Habana. Tengo dos grandes pasiones la programación y el deporte, una la vivo a diario y en la otra solo un ...Leer completo