martes, 3 de enero de 2012

Modifying the Pivot Viewer for SharePoint

Pivot Viewer for SharePoint is a great webpart developed by Xavier Vanneste. Among its uses it provides a very friendly visual navigation for SharePoint picture libraries, allowing zooming in and out and filtering by any of the items’ fields.
The source code is available to download. The latest stable version at the time of writing this is 2.5. The solution contains two projects:
-     SLPivotViewer: It’s a Silverlight control based on Microsoft’s PivotViewer control for Silverlight.
-     SPPivotViewer: the webpart that hosts and renders the SLPivotViewer control allowing some cool customizations (via Web Part Editor Panel) like choosing the source that feeds the control and visual appearance. It also contains some other cool stuff like a custom settings page and a couple of features which automatically install and configure everything.


I detected two things that I wanted to change:
1)     SharePoint navigation pop-up menus are hidden by the Silverlight control:

2)  The .xap file corresponding to the Silverlight application is tightly coupled to the webpart, as it’s included into the SPPivotViewer project as an embedded resource:


That’s not a bug at all, but as the source code for the Silverlight control is provided separately, it could be useful to have the ability to modify it and reuse without the need to compile and deploy the whole solution; instead, the .xap file could be uploaded to a document library (and updated as often as needed) in SharePoint and referenced from the main webpart.

Hands on


The first of our issues turns out to be caused by a common issue in Silverlight: The Windowless parameter. Simply by adding this line in the Silverlight object’s html markup does the trick:
<param name=”WindowLess” value=”true” />
I don’t know if it carries any secondary effects, so I decided to include a toolpart property to choose whether to enable this behavior or not.
The second one is fairly simple: the code of the webpart gets a reference to the embedded .xap file’s URL by the following statement in line 252 of the SPPivotViewerWP.cs file.
string strUrlSilverlight = Page.ClientScript.GetWebResourceUrl(
    typeof(SPPivotViewer.SPPivotViewerWP.SPPivotViewerWP),
    "SPPivotViewer.SPPivotViewerWP.SLPivotViewer.xap");

We must change this one so that it references the URL of our .xap file in our document library, which should be configurable via the toolpart.

Adding the logic to the web part


In first place, we are going to create the two web part properties to hold our configuration parameters. Inside the SPPivotViewerWP class (in SPPivotViewerWP.cs file), we add the following properties:
private string _pivotviewerXapUrl;
public string XapUrl
{
    get { return _pivotviewerXapUrl; }
    set { _pivotviewerXapUrl = value; }
}

private bool _windowless;
public bool WindowLess
{
    get { return _windowless; }
    set { _windowless = value; }
}

Then we modify the CreateChildControls() method as follows:
-    For the “WindowLess” issue, we just insert the following line next to the existing ones in the declaration of the strSilverlight variable (for example, after the line corresponding to the parameter named autoUpgrade):
(WindowLess ? "<param name=\"WindowLess\" value=\"true\" />" : "") +

-    For the other one, we just modify the line mentioned in the previous section so that it now holds the XapUrl property:

string strUrlSilverlight = ProcessXapUrl(XapUrl);

The ProcessXapUrl method is created for convenience, so that it allows entering absolute, site relative or site collection relative URLs for the xap file:
private string ProcessXapUrl(string xapUrl)
{
    if (xapUrl.ToLower().StartsWith("http"))
    { //Absolute URL
        return xapUrl;
    }
    else if (xapUrl.StartsWith("/"))
    { //Site collection relative url
        return SPContext.Current.Site.Url + xapUrl;
    }
    else
    { //Site relative url
        return SPContext.Current.Web.Url + "/" + xapUrl;
    }
}
 

Allowing the properties to be changed from the UI


The last thing to do is to write the necessary code to display in the webpart property pane the controls to modify our newly created properties. This will be done in the EditorUIPivotViewer class, inside the EditorUIPivotViewer.cs file.
In first place, we add the fields corresponding to the web controls to edit and display our field values. The Boolean value to choose whether to use the WindowLess feature will be rendered as a checkbox, and the one to enter the URL of the .xap file as a textbox.
CheckBox chkWindowless;
TextBox txtXapUrl;

The next step is to add to the CreateChildControls method the code to render those fields in the pane. For simplicity I didn’t create any separate group for my controls, but I added them directly as rows inside the same table as the existing ones.

tr = new TableRow();
tbl.Rows.Add(tr);
tc = new TableCell();
tr.Cells.Add(tc);
chkWindowless = new CheckBox() { Text = "Windowless" };
tc.Controls.Add(chkWindowless);

tr = new TableRow();
tbl.Rows.Add(tr);
tc = new TableCell();
tr.Cells.Add(tc);
txtXapUrl = new TextBox();
tc.Controls.Add(new LiteralControl("XAP file url: "));
tc.Controls.Add(txtXapUrl);

Last, we need to add code to “link” those controls to their corresponding properties in the webpart object. That’s a bidirectional link, so we need to:
-    Add the following code inside the SyncChanges function (just before the return statement). This will load the property values from the webpart in the database into our controls, for rendering them:

chkWindowless.Checked = pivotWP.WindowLess;
txtXapUrl.Text = pivotWP.XapUrl;

-     Add the following inside the ApplyChanges function (again, just before the return statement). This will fill our webpart properties with the values introduced in the UI, and will be later saved to the content database.
pivotWP.WindowLess = chkWindowless.Checked;
pivotWP.XapUrl = txtXapUrl.Text;

Final result


And that’s it! We could also modify the SPPivotViewer25.webpart file to add some default values to our properties, for instance:
<property name="WindowLess" type="bool">True</property>

Build, package, deploy and, if not done yet, add the webpart to a zone in a page. The new properties pane allows us to modify our properties:
After building the Silverlight project and uploading it to a document library, and changing the XAP file URL property to point to that file, we get our webpart working properly and the popup menus visible as expected.