Wednesday, March 16, 2011

Adding Properties to Visual Web Parts

Visual Studio 2010 introduces a new feature called “Visual Web Parts”, which allows a developer to create a web part by using a user control as a base. SharePoint 2007 developers will find this very familiar, as they’ll see that Visual Studio 2010 simply does what we had done in the past, which is to create a web part to host the user control. So a Visual Web Part is a user control inside a web part.

VisualWebPartStructure

Let’s walk through creating a Visual Web Part and allow user customization of it. We’ll start by adding a Visual Web Part to a SharePoint project. After you add the Visual Web Part to your SharePoint project, you’ll notice Visual Studio adds many items to support the new web part.

VisualWebPartParts

There are three main items in here of interest:

  • HelloVisualWebPart.cs -This is the actual web part. The class contained in this code file inherits from WebPart and overrides CreateChildControls.
  • HelloVisualWebPartUserControl.ascx - This is the user control that will make up the interface for the web part.
  • HelloVisualWebPartUserControl.ascx.cs - This is the code behind for the user control. This is where any event handlers and other code to add functionality to the web part will be placed.

If you view the code in the HelloVisualWebPart.cs file, you’ll notice it simply loads the user control and places it inside the web part. Again – a Visual Web Part is simply a user control hosted in a web part.

// Code from HelloVisualWebPart.cs
private const string
_ascxPath = @"<<really long string omitted>>";

protected override void CreateChildControls()
{
    Control control = Page.LoadControl(_ascxPath);
    Controls.Add(control);
}

When creating a web part, one of the most common requirements is to allow the end user to customize it. Typically this is done by adding properties to the web part and using those properties to customize the display. This is where things change for a Visual Web Part.

Remember there are two moving parts making the magic happen here – the web part class, which SharePoint will see, and the user control, which houses the UI. If we add the property to the web part class, the user control won’t be able to access it. If we add the property to the user control, SharePoint won’t see it.

The solution is to add the property to the web part, and to add an instance of the web part to the user control. By adding the property to the web part, SharePoint can then prompt the user for a value. By passing the web part into the user control, you can then access these properties.

The first step, adding the property to the web part, is done as normal for a web part property.

// Added to HelloVisualWebPart.cs
[WebBrowsable(true)]
[WebDisplayName("Message")]
[WebDescription("Message to display to users")]
[Personalizable(PersonalizationScope.User)]
[Category("Message Configuration")]
public string Message
{
    get; set;
}

The second step, passing the web part into the user control takes just a little more work. First, we need somewhere to store the web part. We’ll accomplish this by adding a property to the user control of the web part type.

// Added to HelloVisualWebPartUserControl.ascx.cs
public HelloVisualWebPart
ParentWebPart
{
    get; set;
}

Then we need to change the code in the web part that’s adding the user control. The problem is it’s adding a normal user control, and not our specific user control. We need our specific user control as that’s the one with the property. We also then need to pass the web part into the user control.

// Modified in HelloVisualWebPart.cs
protected override void
CreateChildControls()
{
    HelloVisualWebPartUserControl control =
         (HelloVisualWebPartUserControl) Page.LoadControl(_ascxPath);

    control.ParentWebPart = this;
    Controls.Add(control);
}

Finally, we can now access the properties from the web part in the user control. In my little example, I’m just going to add that in as a label.

<%—Added to HelloVisualWebPartUserControl—%>
<asp:Label runat=”server” ID=”lblMessage” />

//Added to HelloVisualWebPartUserControl.ascx.cs
protected void Page_Load(object sender, EventArgs
e)
{
    lblMessage.Text = ParentWebPart.Message;
}

After deploying the web part and adding it to a page, we then get the normal interface in SharePoint.

VisualWebPartFinal

So when we create a Visual Web Part we actually get two moving parts – the web part and a user control. If we want to add properties to the Visual Web Part, we need to add the property to the web part, and then pass an instance of the web part into the user control so the user control can access the values.

16 comments:

  1. Awesome! The best of the lot :)
    Thank you so much :)

    ReplyDelete
  2. Simple and clear. Thanks.

    ReplyDelete
  3. Little late, but all these decorations can be chained into the same []:

    [WebBrowsable(true),WebDisplayName("Message"),WebDescription("Message to display to users"),Personalizable(PersonalizationScope.User),Category("Message Configuration")]

    ReplyDelete
    Replies
    1. You are absolutely right. However, I stack them one on top of the other as I feel it reads better than chaining them. Personal preference.

      Thanks!

      Delete
  4. Doesn't this method clear the values on an IISreset, though? How can we save these values in the content database to preserve them from an IISreset?

    ReplyDelete
    Replies
    1. As long as the web part property is flagged as "Personalizable" it will persist to the content database.

      Delete
    2. I followed your steps here and the Message field is always cleared out after I hit OK. Any suggestions on what went wrong? Thanks!

      Delete
    3. To any one that experiences the values being cleared out as soon as you click OK, here is the solution:
      You are probably calling a dispose of the SPContext class. I had this in my code using(SPSite site = SPContext.Current.Site) which was disposing the site before it could save the values.
      All is working now! And great blog post Chirstopher! This is the method I am using to create custom properties.

      Delete
    4. Ahh, yes. That would do it. And unfortunately when and where to call Dispose gets tricky. In a nutshell, if you avoid calling Dispose when using SPContext you're just fine.

      You may also want to check out SPDisposeCheck, which will examine your MSIL to see if you're using Dispose correctly. It also plugs into Visual Studio.

      Thanks again and I'm glad it's working for you now.

      Delete
  5. Thank you Christopher, very helpful.

    ReplyDelete