PeopleEditor control and the multiview

I spend quite some hours on this one. Here is my configuration:

– a web part with a multiview control with several views in it

– a few linkbuttons to navigate between views

– one of these views contains SharePoint’s PeopleEditor control

– the web part runs in a SharePoint site

Now, the problem was that the PeopleEditor does not retain its values after more than 2 postbacks. As the multiview triggers postbacks, this cannot be accepted. I searched a lot on the internet, but not much information here.

So, i needed a workaround, which i found by subclassing the PeopleEditor control, and override the "RaisePostDataChangedEvent" and the "OnPreRender" event. In short; i store the selected values in a Session var, and use this same session var to load it in the OnPreRender event. I have chosen Sesson vars instead of ViewState because now, I can access it from anywhere in my application, but ViewState works as well.

Here is the code for the PeopleEditor subclass:

================================================================================

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using System.Web.SessionState;

namespace wpPeopleEditor
{
    public class myPPE: PeopleEditor
    {
            public override void RaisePostDataChangedEvent()
            {
               Context.Session.Remove("sessionvalues");
               Context.Session.Add("sessionvalues", this.CommaSeparatedAccounts);
            }
            protected override void OnPreRender(EventArgs e)
            {
                this.CommaSeparatedAccounts=(String)Context.Session["sessionvalues"];
                base.OnPreRender(e);
            }
    }
}

================================================================================

And, for the fun of it, the code of the web part itself:

================================================================================

using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls;
using System.Collections;

namespace wpPeopleEditor
{
    [Guid("e377c0db-7e7b-430b-9935-aa482eb25cd3")]
    public class wpPeopleEditor : System.Web.UI.WebControls.WebParts.WebPart
    {
        public MultiView mv;
        public View vw1;
        public View vw2;
        public View vw3;
        public myPPE PeopleEditor1;
        public wpPeopleEditor()
        {
            this.ExportMode = WebPartExportMode.All;
        }

        protected override void Render(HtmlTextWriter writer)
        {
            this.EnsureChildControls();
            RenderChildren(writer);
        }
        protected override void CreateChildControls()
        {
            mv = new MultiView();
            vw1 = new View();
                Label lbl1 = new Label();
                lbl1.Text = "View1";
                vw1.Controls.Add(lbl1);
                mv.Views.Add(vw1);
            vw2 = new View();
                    PeopleEditor1 = new myPPE();
                    PeopleEditor1.AutoPostBack = true;
                    PeopleEditor1.PlaceButtonsUnderEntityEditor = true;
                    PeopleEditor1.ID = "pplEditor";
                    PeopleEditor1.AllowEmpty = false;
                    PeopleEditor1.SelectionSet = "User,DL,SecGroup,SPGroup";
                    PeopleEditor1.MultiSelect = true;
                    PeopleEditor1.EnableViewState = true;
                vw2.Controls.Add(PeopleEditor1);
                mv.Views.Add(vw2);
            vw3 = new View();
                Label lbl3 = new Label();
                lbl3.Text = "View3";
                vw3.Controls.Add(lbl3);
                mv.Views.Add(vw3);
            this.Controls.Add(mv);
            this.Controls.Add(new LiteralControl("<br>"));
            LinkButton btn1 = new LinkButton();
            btn1.Text = "view 1";
                btn1.CausesValidation = true;
                btn1.Click += new EventHandler(btn1_Click);
                this.Controls.Add(btn1);
            LinkButton btn2 = new LinkButton();
                btn2.Text = "view 2" + PeopleEditor1.CommaSeparatedAccounts;
                btn2.CausesValidation = true;
                btn2.Click += new EventHandler(btn2_Click);
                this.Controls.Add(btn2);
            LinkButton btn3 = new LinkButton();
                btn3.Text = "view 3: " + PeopleEditor1.CommaSeparatedAccounts;
                btn3.CausesValidation = true;
                btn3.Click += new EventHandler(btn3_Click);
                this.Controls.Add(btn3);
            base.CreateChildControls();
        }
        void btn1_Click(object sender, EventArgs e)
        {
            mv.SetActiveView(vw1);
        }
        void btn2_Click(object sender, EventArgs e)
        {
            mv.SetActiveView(vw2);
        }
        void btn3_Click(object sender, EventArgs e)
        {
            mv.SetActiveView(vw3);
        }

    }
}

================================================================================

As you can see, everything is neat and clean in the MyPeopleEditor class itself; no need to get/set stuff in the parent control.

Have fun with it!

Using the People Picker in Visual Studio

In Visual Studio, you can use the People Picker if you are developing for the SharePoint platform. It was actually quite easy:

– go to your tool pane and right click "Choose Items…"

– scroll to the "PeopleEditor" and add this to your tool pane

– switch you view to design and drag this control on your page. Don’t worry the error message, if you build your solution, it will succeed

– now, you can set properties design time on this control, or do this via code. The textbox with the images will show up automatically, usage is as normal in a standard site

– by iterating through the resolved entities you can roll up each user in the people picker. Easy!

I also want to apply filtering (for example: only Groups and users which start with ABC). You can do this on site collection level with STSAdm: "Stsadm.exe -o setproperty –url http://sharepoint –pn peoplepicker-onlysearchwithinsitecollection –pv yes" .However, I would like to do this in code, so I do not interfere with other team members’ work. So, I will have to do some coding…

Here is the code from a user control which will show the people picker. This user control is rendered in the SmartPart web part (must have!). Note here that you cannot test this in your development environment; you will have to copy the user control to your Smart Part directory and fire up your SharePoint site.

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

//added:
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
public partial class usrPeoplePicker : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Alternative: set controls on object itself
        PeopleEditor1.AutoPostBack = true;
        PeopleEditor1.PlaceButtonsUnderEntityEditor = true;
        PeopleEditor1.ID = "pplEditor";
        PeopleEditor1.AllowEmpty = false;
        PeopleEditor1.SelectionSet = "User,DL,SecGroup,SPGroup";
        PeopleEditor1.MultiSelect = true;
    }
    private string GetAccountName()
    {
        //read contents of people picker control
        string _ret = "";
        foreach (PickerEntity ent in PeopleEditor1.ResolvedEntities)
        {
            _ret += ";" + ent.Key;
        }
        return _ret;
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        lblAccount.Text = GetAccountName();
    }
}

Need SharePoint web parts with a lot of controls? Use smartpart!

For a client, I was creating a create new user form with quite some complex code in it and a lot of input controls. Since we use the agile approach, the layout is likely to change drastically along the project. So, a regular web part is too much hassle with coding the controls and placing them. A user control offers a design surface which gives you far more freedom to move stuff around. But, it can be quite some work to render web user controls in your web part. No worries, here is the solution: Jan Tielens Smart Part!

I was amazed by the easy install- and configuration involved. Just install the web part (it includes a setup.exe which will install the web part as feature and activates it on site collection of your choice..), create a folder in your virtual directory called "usercontrols", and drag and drop your usercontrol files in it. Then, drag your smart part on a page, and configure it to use your user control. Easy!

You can download it here: http://www.codeplex.com/smartpart/Release/ProjectReleases.aspx?ReleaseId=10697