Usando el GroupedItemPicker de SharePoint

diciembre 14, 2009
By

En el SDK de SharePoint existe un control llamado GroupedItemPicker. Este control se usa en las páginas AddFieldFromTemplate.aspx y AddContentTypeToList.aspx.

ColumnasSharePoint

Ayer tuve que crear un WebPart y necesite usar la funcionalidad que brinda este control. Me fue casi imposible configurarlo pues no existe mucha documentación sobre el tema por tanto me  ayudé del código de la  propia página AddFieldFromTemplate.aspx para ver como estaba configurado e hice exactamente lo mismo.

<SharePoint:GroupedItemPicker id="Picker" runat="server"
				GroupControlId="SelectGroup"
				CandidateControlId="SelectCandidate"
				ResultControlId="SelectResult"
				AddButtonId="AddButton"
				RemoveButtonId="RemoveButton"
				DescriptionControlId="DescriptionControl"
				/> 

 

 

 

Como resultado recibí varias excepciones, de las cuales obtuve algunas  experiencias. Lo primero que descubrí es que las propiedades del control (GroupControlId, CandidateControlId, ResultControlId, AddButtonId, RemoveButtonId, DescriptionControlId) tienen que referenciar a los controles indicados. GroupControlId, CandidateControlId y CandidateControlId tiene que ser IDs de controles de tipo SPHtmlSelect. AddButtonId y RemoveButtonId tienen que ser de tipo HtmlButton , la propiedad DescriptionControlId tiene que ser de tipo HtmlGenericControl (en código markup equivalente a un span) y además el control “DescriptionControl” no puede tener su InnerHtml vacío. Una vez que estaban establecidas las propiedades pensé que mis problemas habían terminado, hasta que una nueva excepción me hizo cambiar de opinión (NullReferenceExpection en el método PreRender de GroupedItemPicker ). Esta detonó mi paciencia y es cuando vino la desición de “recrear”  el GroupedItemPicker. Para ello necesité del fichero GroupedItemPicker.js, presente en el directorio …\12\TEMPLATE\LAYOUTS y de algunas “artes oscuras”.  Lo mas interesante es que cuando ya había terminado de crear mi propio control, el cual me resolvió el problema, decidí probar el de SharePoint y para sorpresa mía, no me dió la excepción. Acá les muestro el código que hace uso de GroupedItemPicker .

 public abstract class DefaultLayoutPicker : WebControl
 {
        protected GroupedItemPicker picker;
        protected SPHtmlSelect candidateItem, selectedItems;
        protected HtmlButton btt_add, btt_remove;
        protected HtmlSelect select_groups;
        protected HtmlGenericControl description;
        protected override void CreateChildControls()
        {
//
            candidateItem = new SPHtmlSelect();
            candidateItem.ID = "candidateItems";
            candidateItem.Multiple = true;
            Controls.Add(candidateItem);

            selectedItems = new SPHtmlSelect();
            selectedItems.ID = "selectedItems";
            selectedItems.Multiple = true;
            Controls.Add(selectedItems);

            select_groups = new HtmlSelect();
            select_groups.ID = "selectGroups";
            Controls.Add(select_groups);

            btt_add = new HtmlButton();
            btt_add.ID = "bttAdd";
            btt_add.Attributes["class"] = "ms-buttonheightwidth";
            btt_add.InnerHtml = "Add >";
            Controls.Add(btt_add);

            btt_remove = new HtmlButton();
            btt_remove.ID = "bttRemove";
            btt_remove.InnerHtml = "< Remove";
            btt_remove.Attributes["class"] = "ms-buttonheightwidth";
            Controls.Add(btt_remove);

            description = new HtmlGenericControl();
            description.ID = "description";
            description.InnerText = "Description:";
            Controls.Add(description);

            picker = new GroupedItemPicker();
            picker.AddButtonId = btt_add.ID;
            picker.RemoveButtonId = btt_remove.ID;
            picker.ResultControlId = selectedItems.ID;
            picker.GroupControlId = select_groups.ID;
            picker.CandidateControlId = candidateItem.ID;
            picker.DescriptionControlId = description.ID;

            picker.Clear();
            FillItem();

            Controls.Add(picker);
            base.CreateChildControls();

        }
        protected override void Render(HtmlTextWriter writer)
        {
              string temp = @"<table width= '450px'>
                                <tr>
                                   <td class='ms-authoringcontrols'
					colspan='3'>";
            writer.Write(temp); select_groups.RenderControl(writer);
            temp = @"

                                  </td>
                                 </tr>
                                 <tr>
                                   <td valign='bottom'
				  class='ms-authoringcontrols'
				  style='padding-right: 10px'>
                                   </td>
                                   <td style='padding-right: 10px'>
                                   </td>
                                   <td valign='bottom'
				   class='ms-authoringcontrols'
			            style='padding-right: 10px'>
                                      </br>
                                   </td>
                                  </tr>
                                  <tr>
                                    <td  class='ms-authoringcontrols'
				     style='padding-right: 10px'>";
            writer.Write(temp); candidateItem.RenderControl(writer);
            temp = @"

                                      </td>
                                      <td align='center'
					class='ms-authoringcontrols'
					valign='middle' style='padding-right:
					10px'>";
            writer.Write(temp); btt_add.RenderControl(writer);
            temp = @"
                                         </br>
                                         </br>";
            writer.Write(temp); btt_remove.RenderControl(writer);
            temp = @"
                                        </td>
                                         <td class='ms-authoringcontrols'
				        style='padding-right: 10px'>";
            writer.Write(temp); selectedItems.RenderControl(writer);
            temp = @"
                                        </td>
                                       </tr>
                                       <tr>
                                         <td class='ms-authoringcontrols'
						colspan='3'>";
            writer.Write(temp); description.RenderControl(writer);
            temp = @"
                                         </td>
                                        </tr>
                                       </table>";

            writer.Write(temp);
            picker.RenderControl(writer);
        }
        protected abstract void FillItem();
        public virtual IEnumerable<string> SelectdIds
        {
            get
            {
                 this.EnsureChildControls();
                 return this.picker.SelectedIds.Cast<string>();
            }
        }       

    }

En el listado de arriba, se muesta como configurar el control, estableciendo las propiedades correctamente en el método CreateChildControl y luego se da el mismo layout que en la pagina AddContentTypeToList.aspx. Note que  la clase es abstracta, cuyo único método a implementar es el método FillItems. En el siguiente listado se muestra una posible implementación para este método. Todas las referencias que aparecen a clases de CSS estan definidas en …\12\TEMPLATE\LAYOUTS\1033\STYLES\core.css.

public class WebooStudentsPicker : DefaultLayoutPicker
{
    protected override void FillItem()
    {
        using (SPSite site = new SPSite(SPContext.Current.Web.Url))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPList userList = web.SiteUserInfoList;
                foreach (SPListItem item in userList.Items)
                {
                    object grupo = item["Grupo"];
                    if (grupo is string)
                    {
                         string g = grupo as string;
                         if (!string.IsNullOrEmpty(g))
                            picker.AddItem(item.ID.ToString(), item.Name,
					   item.Name, g);
                    }
                }
            }
        }
    }
}

Es este caso se extraen los usuario de la lista “User Information List” (la cual tiene un propiedad adicionada “Grupo”), para proveer los elementos al control GroupedItemPicker . La linea señalada en negritas es la que adiciona los elementos.

AsignPeopleToExamen

Así es como quedó mi WebPart que usó el control DefaultLayoutPicker (dentro del área marcada en rojo)

Resumiendo…

Para trabajar con el control GroupedItemPicker, se deben tener en cuenta tres aspectos:

1- Establecer correctamente las propiedades del control.

2- Implementar un layout para mostralo (opcional).

3- Proveer los elementos mediantes el método GroupedItemPicker.AddItem.

Tags: , ,

3 Responses to Usando el GroupedItemPicker de SharePoint

  1. Robert on abril 15, 2010 at 4:42 am

    Ola Raimil,
    Quiero saber como salvar los elementos del groupeditempicker en el SPListitem?

    puedes darme el codigo para salvar los elementos??

  2. Raimil Cruz
    Raimil Cruz on abril 15, 2010 at 10:55 am

    Hola Robert:
    En el ejemplo , lo que hago es asignar un grupo de estudiantes a un ejercicio. El WebPart que se ve en la imagen es el siguiente:

    [csharp]
    public class AsignPeopleToOrientation : System.Web.UI.WebControls.WebParts.WebPart
    {
    WebooStudentsPicker studentPicker;
    DropDownList dd_orientations;
    Button btt_asignar;

    [WebBrowsable(true)]
    [Personalizable(true)]
    [WebDisplayName("Nombre de la lista")]
    public string OrientationList { get; set; }

    State State { get; set; }
    string message;

    public AsignPeopleToOrientation()
    {
    State = State.Normal;
    }

    protected override void CreateChildControls()
    {
    base.CreateChildControls();

    dd_orientations = new DropDownList();
    FillOrientations(dd_orientations);
    Controls.Add(dd_orientations);

    studentPicker = new WebooStudentsPicker();
    Controls.Add(studentPicker);

    btt_asignar = new Button();
    btt_asignar.Text = "Asignar";
    btt_asignar.Click += new EventHandler(btt_asignar_Click);
    Controls.Add(btt_asignar);
    }

    private void FillOrientations(DropDownList dd_orientations)
    {
    try
    {
    using (SPSite site = new SPSite(SPContext.Current.Web.Url))
    {
    using (SPWeb web = site.OpenWeb())
    {
    SPList list = web.Lists[OrientationList ?? "Orientaciones"];
    foreach (SPListItem item in list.Items)
    {

    dd_orientations.Items.Add(new ListItem() { Text = item.Name, Value = (item.ID).ToString() });
    }
    }
    }
    }
    catch (Exception exp)
    {
    State = State.ErrorConfig;
    message = exp.Message + "<–>" + exp.StackTrace;
    }
    }
    protected override void Render(HtmlTextWriter writer)
    {
    if (State == State.ErrorConfig)
    {
    writer.Write("Configure correctament el WebPart");
    writer.Write(message);
    return;
    }

    writer.Write("Seleccione una Orientación");
    dd_orientations.RenderControl(writer);
    writer.Write("</br>");
    studentPicker.RenderControl(writer);
    writer.Write("</br>");
    btt_asignar.RenderControl(writer);
    if (State == State.Asigned)
    writer.Write("Estudiantes Asignados Correctamente");

    }
    void btt_asignar_Click(object sender, EventArgs e)
    {
    using (SPSite site = new SPSite(SPContext.Current.Web.Url))
    {
    using (SPWeb web = site.OpenWeb())
    {
    web.AllowUnsafeUpdates = true;

    SPList list = web.Lists[OrientationList ?? "Orientaciones"];
    SPList userInfoList = web.SiteUserInfoList;
    SPListItem item = list.GetItemById(int.Parse(dd_orientations.SelectedValue));

    object p = item["Participantes"];
    SPFieldUserValueCollection participantes;
    if (p == null)
    participantes = new SPFieldUserValueCollection();
    else
    participantes = p as SPFieldUserValueCollection;

    foreach (string studentId in studentPicker.SelectdIds)
    {
    int id = int.Parse(studentId);
    participantes.Add(new SPFieldUserValue(web, id, userInfoList.GetItemById(id)["ImnName"].ToString()));
    }
    item["Participantes"] = participantes;
    item.Update();
    list.Update();
    web.Update();

    web.AllowUnsafeUpdates = false;
    }
    }
    State = State.Asigned;
    }
    }
    enum State
    {
    Normal,Asigned,ErrorConfig
    }
    }
    [/csharp]

    Es el código del método “btt_asignar_Click” el que debe de interesarte.

    Espero que te sea util.

  3. Alfredo on septiembre 2, 2013 at 6:39 am

    Hola,
    A que puede ser debido que esté cargando los elementos en el control candidateItems pero al visualizar el control en pantalla no aparecen.
    Si añado otro SPHtmlSelect desenlazado al GroupedItemPicker si aparecen.

    Gracias

Deja un comentario

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

*

Acerca del autor...

Raimil Cruz

Raimil Cruz
Graduado en Ciencia de la Computación en la Universidad de la Habana. Imparte docencia en la asignatura de Programación en la Facultad de Matemática y Computación. Miembro del Grupo Weboo (Web ...Leer completo