It’s pretty well documented how to allow the user to edit the properties of a WebPart in SharePoint. What’s less obvious is how to persist data in a similar manner using just code. It turns out it’s not actually all that tricky once you know what’s involved.
First, my scenario. A WebPart is required that builds a list of strings in an ArrayList. The user can add one item at a time using a series of drop-down menus and an Add button. Items can be removed using an ‘X’ icon next to the item name in the list. In Shared View, the same list must appear across all users.
Persisting the array on a shared and personalized basis is the problem here. Here’s how to do it:
- In your WebPart class, add a private variable for the object you wish to use.
private ArrayList listOfItems;
- Add an accessor property for the variable, and give it the Personalizable attribute. Setting the PersonalizationScope to User allows changes to be stored on personal pages, and on shared pages. Personal settings will be stored for that user only, but shared settings will apply to everyone’s shared view.
[Personalizable(PersonalizationScope.User)]
public ArrayList ItemList
{
get { return listOfItems; }
set { listOfItems = value; }
}
- In the constructor, check to see if the variable has been defined or not. If it is null, initialize it here.
if (listOfItems == null) listOfItems = new ArrayList();
- Finally, the most important part, the part that took me a week to figure out – use the WebPart’s SaveProperty property to, well, save. Set it to true if there are things to save, and it will do so after rendering. If this is not present, it seems as thought it just does not commit any changes. So I put this code in the onPreRender() method.
if (listOfItems.Count > 0) SaveProperties = true;
That’s the basics, but it doesn’t end there. You don’t want users changing values willy nilly. Users should only be allowed to change properties on personalized views. Only administrators should be allowed to modify the shared views. There are three things to check:
- Find out if the user has permissions to create and edit pages on the site (like an administrator):
SPContext.Current.Web.DoesUserHavePermissions(SPBasePermissions.AddAndCustomizePages)
- Find out if the user can customize their own pages:
SPContext.Current.Web.DoesUserHavePermissions(SPBasePermissions.AddDelPrivateWebParts)
- Find out if the page is currently in Shared mode or Personalized mode:
this.WebPartManager.Personalization.Scope == PersonalizationScope.Shared
I combined these three states to tell whether or not the user should be allowed to edit an object. If the Web Part Page is in Shared mode AND the user is an administrator, allow editing. If the page is NOT Shared, and the user can personalize, or is an administrator, allow editing. Otherwise, do not allow editing. I put the following code in onPreRender():
bool shared = WebPartManager.Personalization.Scope == PersonalizationScope.Shared;
bool admin =
SPContext.Current.Web.DoesUserHavePermissions(SPBasePermissions.AddAndCustomizePages);
bool personalizable =
SPContext.Current.Web.DoesUserHavePermissions(SPBasePermissions.AddDelPrivateWebParts);
bool editable = (shared && admin) || (!shared && (personalizable || admin));
if(editable)
{
// Assert this value just in case
SaveProperties = false;
// Hide or disable any editing controls here
}
else
{
// Set the property to save
if (listOfItems.Count > 0)
SaveProperties = true;
// Show or enable any editing controls here
}
And that’s it. You might need to add more logic to prevent users from removing items from the list and so on, but now the basics are in place, it should be much more straight-forward.
I must admit, I get the feeling that this process is a little flaky, but it works, and I’ve not found a better solution. If you know better, I’d like to know too!