This is the 3rd part in a small series on Silverlight development for SharePoint. In part 1 I have introduced the Silverlight News web part and showed you how to prepare your server(s) for Silverlight. The 2nd part shows how to create and install the WCF service that will search for the news items. In this part we will create the web part that will host the Silverlight solution. The main task is to host and parameterize the Silverlight control in the page. It also allows users to select a scope and it makes the web part act as a filter consumer. This web part gathers all the information required for the Silverlight application to work properly.
Part 1 - Introduction and preparation
Part 2 - Create the WCF News service
Part 3 - Create the Silverlight web part
Part 4 - Create the Silverlight application
Step 1 – Create a new web part
I added a new class library to my solution and added a new webpart class to the new project. This project needs 2 new references; a reference to Microsoft.SharePoint.dll and a reference to System.Web.Silverlight.dll. The web part has 1 public property, for the scope of the news, and a number of private variables that are needed to host the Silverlight control:
public class NewsWebPart : WebPart, IWebEditable
{
private ScriptManager _scriptHandler;
private System.Web.UI.SilverlightControls.Silverlight _silverlightControl = null;
[Browsable(false),
Personalizable(PersonalizationScope.Shared)]
public NewsScope Scope
{
get;
set;
}
public NewsWebPart()
{
}
}
The NewScope enumeration is defined as:
[DataContract(Namespace = "http://schemas.blackbelts.com/2008/11/news")]
public enum NewsScope : int
{
[EnumMember()]
CurrentWeb = 0,
[EnumMember()]
CurrentWebAndBelow = 1,
[EnumMember()]
SiteCollection = 2
}
Because the enum will be passed between the Silverlight client and the WCF service, the enum is also decorated with the DataContract attribute.
Step 2 – Create an editor part
Second thing to do is to create an editor part that will let our users select the scope for their news search.
public class NewsWebPartEditor: EditorPart
{
private const string EMPTYITEM = "EMPTY";
private RadioButtonList _selectScope;
public NewsWebPartEditor(string webPartID)
{
this.ID = string.Format("SelectWebPropertyEditor{0}", webPartID);
this.Title = "Silverlight News Options";
}
protected override void CreateChildControls()
{
Label label = new Label();
label.Text = "Select a scope:";
Controls.Add(label);
_selectScope = new RadioButtonList();
_selectScope.Items.Add(new ListItem("Current web", NewsScope.CurrentWeb.ToString()));
_selectScope.Items.Add(new ListItem("Current web and below", NewsScope.CurrentWebAndBelow.ToString()));
_selectScope.Items.Add(new ListItem("Site Collection", NewsScope.SiteCollection.ToString()));
Controls.Add(_selectScope);
base.CreateChildControls();
}
public override bool ApplyChanges()
{
NewsWebPart webpart = WebPartToEdit as NewsWebPart;
webpart.Scope = (NewsScope)Enum.Parse(typeof(NewsScope), _selectScope.SelectedValue);
return true;
}
public override void SyncChanges()
{
EnsureChildControls();
NewsWebPart webpart = WebPartToEdit as NewsWebPart;
_selectScope.SelectedValue = webpart.Scope.ToString();
}
}
If you want to read more about creating an editor part, read this post I have written about this. Besides creating the editor part, we will need to register it in the NewsWebPart by implementing IWebEditable and implementing CreateEditorParts:
EditorPartCollection IWebEditable.CreateEditorParts()
{
List<EditorPart> newEditors = new List<EditorPart>();
EditorPartCollection editors = base.CreateEditorParts();
foreach (EditorPart part in editors)
newEditors.Add(part);
newEditors.Add(new NewsWebPartEditor(this.ID));
return new EditorPartCollection(newEditors);
}
Step 3 – Initialize and create the controls
In the OnInit, our Silverlight host web part registers a new script manager.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_scriptHandler = ScriptManager.GetCurrent(this.Page);
if (_scriptHandler == null)
{
_scriptHandler = new ScriptManager();
_scriptHandler.ID = string.Format("TST.BlackBelt.Silverlight.News.script_{0}", this.ID);
this.Controls.Add(_scriptHandler);
}
}
This scriptmanager is required on the page for the Silverlight control to work properly. In CreateChildControls our web part will create and initialize the Silverlight control. The Source of the Silverlight control points to the xap file that we will create in the next post. Please note that the xap file is deployed to the LAYOUTS folder, which is a folder relative to our current context. The InitParameters property of the silverlight control can be used to initialize the silverlight control. I use the InitParameters to send the title of the web part and the selected scope to the silverlight control. This is important to understand, because once you are in your silverlight control, you are in a totally different request, that knows nothing about SharePoint, web parts or web part properties. Therefore I send all parameter I need in my silverlight control by setting the InitParameters property.
protected override void CreateChildControls()
{
base.CreateChildControls();
_silverlightControl = new System.Web.UI.SilverlightControls.Silverlight();
_silverlightControl.ID = string.Format("TST.BlackBelt.Silverlight.News.xap_{0}", ID);
_silverlightControl.Source = string.Format("{0}/{1}", SPContext.Current.Web.Url, "_layouts/sbb/TST.BlackBelt.Silverlight.News.xap");
if (this.Width.Value > 0)
_silverlightControl.Width = this.Width;
else
_silverlightControl.Width = Unit.Pixel(600);
if (this.Height.Value > 0)
_silverlightControl.Height = this.Height;
else
_silverlightControl.Height = Unit.Pixel(400);
_silverlightControl.InitParameters = string.Format("WebPartTitle={0}, Scope={1}", this.Title, this.Scope.ToString());
_silverlightControl.Attributes["Style"] = "z-index:0";
_silverlightControl.Windowless = true;
this.Controls.Add(_silverlightControl);
LiteralControl contentDiv = new LiteralControl("<div id=\"contentDiv\" style=\"position:absolute;z-index:1;border:1px solid black;background-color:white\"></div>");
this.Controls.Add(contentDiv);
}
The last control that is created by our web part and added to the controls collection is a DIV, called the
contentDiv. This DIV will be used to render the contents of the news annoucement after the user has selected an item in the interface. See the screenshots in the
first article.
Step 4 – Make our web part a filter consumer
Last thing to implement in our web part is the filter consumer. Our web part will accept incoming filter values from filter providers like the out of the box filter web parts, or my List Item Filter or Web Context Filter web parts. To do this, we create a new method and add the ConnectionConsumer attribute. In the SetFilter method, we create a new ConsumerParameter. These parameters can be selected by the user upon connection the web part to a filter provider. In this example web part, we currently only support the Title field. So the webpart can currently only be filtered on the Title field. In the SetFilter web also handle the incoming filter. In this case the filter field and value are added to the InitParameters property of the Silverlight control. Make sure this control is properly initialized by using EnsureChildControls in the SetFilter method. The incoming filter value is added to the initialization parameters for the silverlight control. This controls passes the filter value to the WCF service that we created in the second post. This WCF service processes the filter.
[ConnectionConsumer("filter", "IFilterValues", AllowsMultipleConnections = true)]
public void SetFilter(Microsoft.SharePoint.WebPartPages.IFilterValues filterValues)
{
if (filterValues != null)
{
EnsureChildControls();
List<Microsoft.SharePoint.WebPartPages.ConsumerParameter> parameters = new List<Microsoft.SharePoint.WebPartPages.ConsumerParameter>();
parameters.Add(new Microsoft.SharePoint.WebPartPages.ConsumerParameter(
"Title",
Microsoft.SharePoint.WebPartPages.ConsumerParameterCapabilities.SupportsSingleValue |
Microsoft.SharePoint.WebPartPages.ConsumerParameterCapabilities.SupportsAllValue |
Microsoft.SharePoint.WebPartPages.ConsumerParameterCapabilities.SupportsEmptyValue));
filterValues.SetConsumerParameters(
new System.Collections.ObjectModel.ReadOnlyCollection<Microsoft.SharePoint.WebPartPages.ConsumerParameter>(parameters));
if (filterValues.ParameterValues != null && filterValues.ParameterValues.Count > 0)
{
HandleFilter(filterValues.ParameterName, filterValues.ParameterValues[0]);
}
}
}
private void HandleFilter(string fieldname, string filter)
{
_silverlightControl.InitParameters = string.Format("WebPartTitle={0}, Scope={1}, FilterField={2}, FilterValue={3}", this.Title, this.Scope.ToString(), fieldname, filter);
}
If you want to learn more about creating your own filter providers and consumers, you can start by reading this blog post.