Contents tagged with .NET

  • Web Parts Connections - Introduction

    Tags: .NET, SharePoint, Web Parts

    This is the first post in a series on Web Parts Connections. This spring I had a series on Web Part Properties that I think was very successful, they got some good comments and feedback and they get a lot of hits from search engines. Please help me out and evolve this new series of posts with some feedback and questions.

    What is Web Parts Connections?

    imageWeb Parts Connections allows you to connect the Web Part server controls so that they can exchange information. Web Parts can either be a consumer and/or a provider. Once you connect a consumer with a provider the consumer starts receiving data from the provider, all this is done on the server side. Web Parts can be constructed in such way that it can have several consumer and provider connection-points, i.e.it can consume or provide information from several different sources. A provider connection-point can have several consumers but a consumer connection-point can have only one provider.

    The image, to the right, illustrates in the top; one Web Part connected to another. The middle sample shows how one provider Web Part is connected to two consumer Web Parts. The sample in the bottom shows a consumer Web Part that have two consumer end-points that are connected to two different provider Web Parts.

    Note: Web Parts Connections are a part of the ASP.NET 2.0 framework

    Why Connecting Web Parts?

    When you connect Web Parts you enhance the experience for the user. You can for example have one Web Part containing a list of items and let that one act as a provider and then have a consumer Web Part that shows detailed information of the item selected in the provider Web Parts.

    In SharePoint most of the default Web Parts are either consumers or providers. For example, with some easy clicks in the interface you can connect lists and make one a consumer and the other provider.

    Connecting Custom Lists Filtering

    The image above shows two custom lists that are connected. The Regions list contains the names of the regions, used in the Sales list. With this simple action we have built a Filter Web Part to filter our Sales list. More about Filter Web Parts later on in the series. The left image shows how you make the actual connection and the image to the right shows you how you can filter the Sales list using the radio buttons on the Regions list.

    I've been working a lot building dashboards and applications for BI-solutions and similar. Using connected Web Parts have both made the end-user experience a whole lot better (and more good looking) as well as the development of the dashboards.

    This was an introduction to Web Parts Connections, the next part will be up in a couple of days.

    Until next time.

  • SharePoint Web Part Event Flow in detail

    Tags: .NET, SharePoint, Web Parts

    I have been answering questions on the SharePoint forums at MSDN Forums, and while some are really tricky and interesting, some are really basic beginner mistakes. A couple of questions lately have been about Web Part development and how to and where to create your controls. Most of these is easily solved if you understand how the Web Part event model works.

    First of all you need basic ASP.NET understanding and know how the Page and Control objects work together, how a postback works etc. But I have even seen somewhat experienced ASP.NET developers failing at this point, probably due to the fact that Visual Studio have a slick interface for editing user controls and ASP.NET pages. When it comes to SharePoint you have no visual aids and you are out on thin water, and this knowledge is crucial.

    SharePoint Web Part - Event Flow chart

    To help new (or experienced) SharePoint Web Part developers out I created a chart that shows you how the different events flows from the Page, through the WebPartManager and WebPartZones, to the Web Part.

    WebPartEventModelChart

    You can either click on the image above, to get it as a JPEG image, or download it as a printable PDF or XPS file.

    Note: The Event Flow chart does not cover all events in the ASP.NET/SharePoint Page model, I have focused on the WebPart side.

    There are five segments in the chart, from left to right;

    • Page - events/methods happening in the Page (System.Web.UI.Page derivatives)
    • WebPartManager - events/methods in the SPWebPartManager (inherited from WebPartManager)
    • WebPartZone - the WebPartZone does not do really much in this scenario but rendering the WebParts.
    • WebPart - the events happening during a normal view of a WebPart
    • WebPart Postback - the event flow is a little bit different than the normal WebPart flow. Note that CreateChildControls is before the OnLoad and connections.

    The chart contains a few white notations; these are not actual events/methods but contains information on what is happening at that point.

    If you have any suggestions or comments about the flow, please feel free to contact me or post a comment. I’ll gladly keep the chart up to date.

  • Custom code with SharePoint Online and Windows Azure

    Tags: .NET, C#, SharePoint, Visual Studio, Microsoft Office, Office Open XML, Windows Azure

    When I first heard about SharePoint Online at the PDC 2008 I was a bit disappointed that you could not use custom code but had to rely on the built-in functionality and the things you could do with SharePoint Designer (which is quite powerful anyway, especially with jQuery).

    To read more about SharePoint online, head over to Tobias Zimmergrens blog.

    But with some clever techniques you can take advantage of the Windows Azure Hosted Services and create your custom code. I will show you how to create some custom code, which normally is done by SharePoint event receivers or timer jobs, using a Worker Role in Windows Azure.

    The post is quite lengthy but I have skipped some of the code snippets to make it easier to read. You will find downloads of the C# code at the end of this post.

    Scenario

    This sample assumes that we have a Document Library in SharePoint Online containing Word 2007 documents for Proposals. The library is called Proposals. We want to make sure that our Proposals has all comments removed before we send it away to our clients. This comment removal procedure will be initiated by a workflow.

    The Document Library

    Action column The Proposals Document Library is a standard SharePoint Document Library with versioning enabled. First we add a new column to the library called Action. This column will contain the status of the comment removal procedure. It has the type Choice and three possible values; RemoveComments, Processing and Done.

    The workflow

    Using SharePoint Designer we create a new workflow, called Prepare Proposal. The workflow has three stages. The workflow is initiated manually

    1. SPD Workflow designerSet the Action column to the RemoveComments value
    2. Wait for Action column to get the value Done
    3. Send e-mail the the author

    Pretty simple workflow but all using the out-of-the-box SharePoint Designer activities.

    So far everything is basic SharePoint Online “development”, but now we head on over to the custom coding parts.

    Create the Hosted Service Worker Role

    Using Visual Studio 2008 and the Windows Azure SDK we can create a new project of the type Worker Cloud Service. This cloud service will contain all our code for removing the comments from our Word documents.

    Cloud Service templates

    When the project is created, actually a solution with two projects, we add two references to our Worker Role project; WindowsBase.dll and DocumentFormat.OpenXml.dll (from Open XML SDK 1.0). The Open XML reference must also have the Copy Local property set to true, so that the assembly is deployed with the hosted service App Package.

    Note: Version 2 of Open XML SDK can not be used since it does not have the AllowPartiallyTrustedCallers attribute, which is required for all referenced assemblies in Windows Azure.

    Add a service reference

    The worker role will use the SharePoint Online web services to read and update data so we need to add a Service Reference to our SharePoint online site and the Lists.asmx web service. When this is done an App.config file is created, just delete it - we have to set our bindings and endpoints in the code so it is fully trusted.

    In your worker role Start method you create code as follows:

      1: BasicHttpBinding binding = new BasicHttpBinding();
    
      2: binding.Security.Mode = BasicHttpSecurityMode.Transport;
    
      3: binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
    
      4: binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
    
      5: binding.Security.Transport.Realm = WorkerRole.Realm;
    
      6: binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

    WorkerRole.Realm contains a string with your SharePoint Online Realm with a value something like this: “XXXXXmicrosoftonlinecom-1.sharepoint.microsoftonline.com”.

    Let’s code!

    The worker role will poll the Proposals library for new documents which has the RemoveComments value in the Action column. This is done with the GetListItems method and a query selecting only those documents.

      1: XElement query = new XElement("Query",
    
      2:     new XElement("Where",
    
      3:         new XElement("Eq",
    
      4:             new XElement("FieldRef",
    
      5:                 new XAttribute("Name", "Action")
    
      6:                 ),
    
      7:             new XElement("Value",
    
      8:                 new XAttribute("Type", "Choice"),
    
      9:                 "RemoveComments"))));
    
     10: 
    
     11: XElement queryOptions = new XElement("queryOptions");
    
     12: 
    
     13: var itemsXml = client.GetListItems("Proposals", string.Empty, query.GetXmlElement(), null, string.Empty, queryOptions.GetXmlElement(), string.Empty);
    
     14: 
    
     15: XNamespace s = "http://schemas.microsoft.com/sharepoint/soap/";
    
     16: XNamespace rs = "urn:schemas-microsoft-com:rowset";
    
     17: XNamespace z = "#RowsetSchema";
    
     18: 
    
     19: var docs = itemsXml.
    
     20:     GetXElement().
    
     21:     Descendants(z + "row").
    
     22:     Select(x => new {
    
     23:         Title = (string)x.Attribute("ows_LinkFilename"),
    
     24:         Id = (string)x.Attribute("ows_ID"),
    
     25:         Url = WorkerRole.Url + "/Proposals/" + (string)x.Attribute("ows_LinkFilename")
    
     26:     });
    
     27: 

    Now we have all our proposals in the docs variable and we can iterate over it.

      1: foreach (var doc in docs) {
    
      2:     RoleManager.WriteToLog("Information", "Processing: " + doc.Title);
    
      3:     setStatusOnDocument(client, doc.Id, "Processing");
    
      4: 
    
      5:     WebRequest request = HttpWebRequest.Create(doc.Url);
    
      6:     request.Credentials = new NetworkCredential(WorkerRole.Username, WorkerRole.Password);
    
      7: 
    
      8:     MemoryStream mems = new MemoryStream();
    
      9: 
    
     10:     using (WebResponse response = request.GetResponse()) {
    
     11:         using (Stream responseStream = response.GetResponseStream()) {
    
     12:             byte[] buffer = new byte[8192];
    
     13:             int offset = 0;
    
     14:             int count;
    
     15:             do {
    
     16:                 count = responseStream.Read(buffer, 0, 8192);
    
     17:                 offset += count;
    
     18:                 mems.Write(buffer, 0, count);
    
     19:             } while (count != 0);
    
     20:             using (WordprocessingDocument wpDoc = WordprocessingDocument.Open(mems, true)) {
    
     21:                 RemoveComments(wpDoc);
    
     22:             }
    
     23:             using (WebClient wc = new WebClient()) {
    
     24:                 wc.Credentials = new NetworkCredential(WorkerRole.Username, WorkerRole.Password);
    
     25:                 wc.UploadData(doc.Url, "PUT", mems.ToArray());
    
     26:             }
    
     27:         }
    
     28:     }
    
     29:     setStatusOnDocument(client, doc.Id, "Done");
    
     30:     RoleManager.WriteToLog("Information", "Comments removed from: " + doc.Title);
    
     31: }
    
     32: 

    First of all we have a method which updates the Action column of the item to Processing to indicate to the users that we are currently processing this document. Then we read the document into a stream and pass it into a WordprocessingDocument object. On that object we do the RemoveComments method which removes all comments in the Word 2007 document.

    Note: Have a look at Eric Whites blog for some nifty operations on your Open Xml documents, such as the remove comments function.

    When all comments are removed we upload the file back to SharePoint and set the status to Done, and we are all set.

    As you can see I use three different techniques to read from the SharePoint Online site; the SharePoint web services, request-response and a simple WebClient. Isn’t coding fun!

    Test

    One of Windows Azures beauties is that you can test it on your local machine using the Azure Development Fabric. Just hit F5 in Visual Studio.

    Development Fabric

    This allows you to debug and fine tune your code and see how it scales out.

    Deploy to Windows Azure Staging environment

    Hosted Service When you are sure that there are no bugs just choose Publish in Visual Studio and it will open up a web browser which directs you to the Azure Services Developer Portal, there you can create a new Hosted Service Project or choose an existing one to use for this Proposals service.

    To deploy this solution we have to upload two files; the  App Package containing all your code and references and the Configuration Settings file, both automatically created by Visual Studio.

    Deploying

    When this is done you have to wait a few minutes so Windows Azure can allocate resources for you and prepare the environment. Once this is done you are ready to test your service in the cloud.

    In staging

    Just hit the Run button and after a minute or so the Proposals Service is running - in the cloud!

    Deploy to Production

    For us used to the SharePoint environment and the mess it is to get from development to staging to production environment it’s so much fun to just hit Deploy in Windows Azure to move the Staging service to Production.

    Production

    As you can see from the image above this solution is now in production and started with one worker role.

    Run the workflow

    Now we can test our complete solution by uploading a document containing some comments. Then initiate the Prepare Proposals Workflow.

    Prepare Proposal

    The document will be updated with a new value in the Action column.

    In Progress

    After a few seconds the document is updated by the cloud worker role we created, the workflow completes, there are no more comments in the document and the author should have received an e-mail with information that the workflow is done.

     Done

    Summary

    This was a short demonstration on what you can do with the standard functionalities of Microsoft's cloud offerings such as SharePoint Online and Windows Azure. The scenario was quite simple but using the same techniques you can elevate your SharePoint Online experience and functionality a lot.

    Using Windows Azure is one possibility to host your online custom code, hosting it on on-premise servers is another option and it works just as fine.

    Note: I have not made this sample so it can scale out nor does it handle any exceptions. Take it what its for.

    If you would like to look at the code you can find it here.

    Happy coding!

  • Web Part Properties - part 6 - Complex Properties

    Tags: .NET, SharePoint, Web Parts

    To end my series of Web Part properties I would like to show how to store more complex values than just strings or integers. What happens if you would like to store a more complex object; an array or a coordinate etc?

    Editing these properties with the standard generated interface using the WebBrowsable and Personalizable attributes will not work, since it only accepts basic types, shown in part 1. To make these properties editable you have to (almost…continue reading) create an EditorPart, shown in part 2, and control the properties in the SyncChanges and ApplyChanges methods.

    Note: For more information on which basic types that can be used in the standard toolbar see the PropertyGridEditorPart documentation on MSDN.

    SharePoint Designer and complex properties

    If you are using SharePoint Designer to edit your Web Parts, you can manage your complex properties a little bit more. For example if you store have string array, it will not be visible in the web interface, but it can be edited in SharePoint Designer.

      1: [WebBrowsable]
    
      2: [Personalizable]
    
      3: public string[] AnArray {
    
      4:     get;
    
      5:     set;
    
      6: }

    The property above will not be seen in the web interface but in SharePoint Designer it will look like this:

    SPD

    If you click on the ellipsis button you will get a dialog in which you can edit the string array.

    Custom objects without EditorParts

    But if you still don’t want to create your own EditorPart you can use some .NET development techniques, familiar to you who have been working a lot with WinForms.

    Let’s say that we want to have a Coordinate property that we would like to use in our web part, the class should look like this:

      1: public class Coordinate {
    
      2:     public float Latiude;
    
      3:     public float Longitude;
    
      4:     public override string ToString() {
    
      5:         return this.Latiude.ToString(CultureInfo.CurrentCulture) + 
    
      6:                ":" + 
    
      7:                this.Longitude.ToString(CultureInfo.CurrentCulture);
    
      8:     }
    
      9: }

    And we expose it through our web part like this:

      1:  [WebBrowsable]
    
      2:  [Personalizable]
    
      3:  public Coordinate Coordinate {
    
      4:     get;
    
      5:     set;
    
      6: }

    This property will not be shown in the web interface and will not be editable in SharePoint Designer. Now to get this to work, editable in the web interface as well as in SPD, we have to create an implementation of the ExpandableObjectConverter class. We will override four methods so we can convert a Coordinate to and from a string representation. The string representation is implemented in the ToString() in the code above. The whole implementation of the class looks like this:

      1: public class CoordinateConverter : ExpandableObjectConverter {
    
      2:     public override bool CanConvertTo(ITypeDescriptorContext context, 
    
      3:                          System.Type destinationType) {
    
      4:         if (destinationType == typeof(Coordinate))
    
      5:             return true;
    
      6:         return base.CanConvertTo(context, destinationType);
    
      7:     }
    
      8:     public override object ConvertTo(ITypeDescriptorContext context, 
    
      9:                            CultureInfo culture, object value, 
    
     10:                            System.Type destinationType) {
    
     11:         if (destinationType == typeof(System.String) && 
    
     12:             value is Coordinate) {
    
     13:             Coordinate coord = (Coordinate)value;
    
     14:             return coord.ToString();
    
     15:         }
    
     16:         return base.ConvertTo(context, culture, value, destinationType);
    
     17:     }
    
     18: 
    
     19:     public override bool CanConvertFrom(ITypeDescriptorContext context, 
    
     20:                          System.Type sourceType) {
    
     21:         if (sourceType == typeof(string))
    
     22:             return true;
    
     23:         return base.CanConvertFrom(context, sourceType);
    
     24:     }
    
     25:     public override object ConvertFrom(ITypeDescriptorContext context, 
    
     26:                            CultureInfo culture, object value) {
    
     27:         if (value is string) {
    
     28:             try {
    
     29:                 string s = (string)value;
    
     30:                 string[] arr = s.Split(':');
    
     31:                 Coordinate coord = new Coordinate();
    
     32:                 coord.Latiude = float.Parse(arr[0], 
    
     33:                                 CultureInfo.CurrentCulture);
    
     34:                 coord.Longitude = float.Parse(arr[1], 
    
     35:                                   CultureInfo.CurrentCulture);
    
     36:                 return coord;
    
     37:             }
    
     38:             catch {
    
     39:                 throw new ArgumentException("Can not convert '" + 
    
     40:                           (string)value + "' to type a Coordinate");
    
     41:             }
    
     42:         }
    
     43:         return base.ConvertFrom(context, culture, value);
    
     44:     }
    
     45: }

    To make SharePoint and SharePoint Designer aware of that we now can convert our Coordinate class to a string representation we have to set the TypeConverter attribute on our Coordinate class. The final Coordinate class should look like this:

      1: [TypeConverter(typeof(CoordinateConverter))]
    
      2: public class Coordinate {
    
      3:     public float Latiude;
    
      4:     public float Longitude;
    
      5:     public override string ToString() {
    
      6:         return this.Latiude.ToString(CultureInfo.CurrentCulture) + 
    
      7:                ":" + 
    
      8:                this.Longitude.ToString(CultureInfo.CurrentCulture);
    
      9:     }
    
     10: }

    If we now modify our web part we will see this in the web interface, sweet huh?

    Coordinate

    If we try to set it to any other value than we allow in our ConvertFrom method above, then we will get a nice error:

    Coordinate error

    The Coordinate property can also be edited in SharePoint Designer:

    Coordinate editing in SPD

    Other methods

    There are other ways to make your web part handle complex properties. Wesley Bakker has a nice write up on how to use JSON notation to store and edit the values.

    That was all folks…

  • Web Part Properties - part 2 - Editor Parts

    Tags: .NET, C#, SharePoint, Web Parts

    TweetPart This is the second part of the Web Part Properties series. The last post walked through the basics on how to make editable properties on a Web Part. As a sample I used a Web Part that displayed tweets from Twitter - called TweetPart.

    Using the standard approach, by marking the properties using specific attributes, we made the Web Part editable as we wanted. But the user experience, for editing, was not optimal. First of all the properties we wanted to edit was located in their own category at the bottom, not that easy to find for inexperienced/untrained users. Secondly the properties has dependencies and requires validation.

    To WebPart or WebPart

    When developing Web Parts for Windows SharePoint Services 3.0 or Microsoft Office SharePoint Server 2007 you have two different Web Part classes to choose from:

    Which one should I use when building Web Parts? WSS 3.0 supports both…

    Tip: When checking out samples for Web Parts, note which class is used. Most samples on MSDN are using the older construct.

    The first class is a part of ASP.NET 2.0 and the other one is from the Microsoft.SharePoint.dll library. The latter is there to maintain backwards compatibility with SharePoint 2003 (built upon .NET 1.1, which did not have a built-in WebPart class). I strongly recommend using the ASP.NET 2.0 WebPart, since it’s a newer construct and will probably still be used in the upcoming SharePoint 14. The ASP.NET WebPart is still in the new .NET Framework 4.0, according to the PDC 08 pre-release bits, and I doubt that Microsoft will introduce a third WebPart class. What will happen to the SharePoint WebPart class is not known (to me).

    Note: Even though the two classes share the same functionality they differ in how to create custom editing tool panes, how Web Part connections work and how their Web Part Xml definitions look like.

    The EditorPart class

    ASP.NET 2.0 contains an abstract class called EditorPart, this class is used with the ASP.NET 2.0 WebPart class to create customized tool panes. By inheriting from this control you can customize the look and functionality of the tool pane and use standard ASP.NET constructs such as auto post backs, validations etc.

    Tip: since this is standard ASP.NET 2.0 techniques you can have this running outside of SharePoint if you implement your own Web Part based web site.

    In our TweetPart sample we had a drop-down, with the different display modes. Depending on the display mode selection the two text boxes should be shown or not. To achieve this we can create a new EditorPart class and replace the auto-generated Twitter category tool pane. Standard attribute properties, with automatic tool panes, can of course be combined with EditorParts - and in this sample we will leave the count of tweets as a standard attributed property.

    First of all we create a new class which inherits from System.Web.UI.WebControls.WebParts.EditorPart. In this class you have to override two abstract methods and add the controls that you are going to use.

    Add controls

    The controls are added in the CreateChildControls method. This is where you should place most of your control logic, in editor parts, web parts etc.

    Note: Make sure you understand the ASP.NET 2.0 event model!

    I have one select list and two textboxes, representing the different web part properties here.

    protected ListBox m_lbModes;
    protected TextBox m_tbUsername;
    protected TextBox m_tbSearchString;
    
    protected override void CreateChildControls() {
        // Add controls here
        m_lbModes = new ListBox();
        m_tbUsername = new TextBox();
        m_tbSearchString= new TextBox();
        foreach (string mode in Enum.GetNames(typeof(TwitterTimeLineMode))) {
            m_lbModes.Items.Add(mode);
        }
        this.Controls.Add(new LiteralControl("<b>Mode</b><br/>"));
        this.Controls.Add(m_lbModes);
        this.Controls.Add(new LiteralControl("<br/><b>Username</b><br/>"));
        this.Controls.Add(m_tbUsername);
        this.Controls.Add(new LiteralControl("<br/><b>Search string</b><br/>"));
        this.Controls.Add(m_tbSearchString);
    
        base.CreateChildControls();
        this.ChildControlsCreated = true;
    }

    SyncChanges

    The SynChanges method is used by the EditorPart to get the values from the Web Part into the Editor Part.

    public override void SyncChanges() {
        EnsureChildControls();
        TwitterWebPart twitterWebPart = (TwitterWebPart)this.WebPartToEdit;
        if (twitterWebPart != null) {
            // get values from WebPart
            m_lbModes.SelectedValue = twitterWebPart.Mode.ToString();
            m_tbUsername.Text = twitterWebPart.Username;
            m_tbSearchString.Text = twitterWebPart.SearchText;
        }
        return;
    }

    ApplyChanges

    The ApplyChanges method is executed when you click Ok or Apply and is used to set the property values of your Web Part. SyncChanges is always called directly after the ApplyChanges method, to make sure that the properties are in sync.

    public override bool ApplyChanges() {
        EnsureChildControls();
        TwitterWebPart twitterWebPart = (TwitterWebPart)this.WebPartToEdit;
        if (twitterWebPart != null) {
            twitterWebPart.Mode = (TwitterTimeLineMode)Enum.Parse(typeof(TwitterTimeLineMode), m_lbModes.SelectedValue);
            twitterWebPart.SearchText = m_tbSearchString.Text;
            twitterWebPart.Username = m_tbUsername.Text;
        }
        return true;
    }

    Modify the WebPart class

    Now we have to tell the web part that it should use this editor part, instead of the attributed properties. First of all we want to get rid of the automatic interface for the properties, this is done by removing the Personalizable attribute.

    Note: Just removing the Personalizable attribute and none of the others (WebBrowsable etc), will still allow you to configure these properties using tools such as SharePoint Designer.

    Note: Values of properties in the editor part have precedence over automatic generated properties.

    IWebEditable interface

    Now only one thing remains and that is to expose the editor part from the web part. To do this you have to make your web part class inherit from the IWebEditable interface and implement it. Don't forget to add an Id to the EditorPart class.

    EditorPartCollection IWebEditable.CreateEditorParts() {
        // control the editorparts
        List editors = new List();
        TwitterEditorPart editorPart = new TwitterEditorPart();
        editorPart.ID = this.ID + "_editorPart";
        editors.Add(editorPart);
        return new EditorPartCollection(editors);
    
    }
    
    object IWebEditable.WebBrowsableObject {
        get { return this; }
    }

    The CreateEditorParts method is used to tell the web part zone what editor parts you will show, in this case we only have one. But more advanced web parts may require that you have several.

    Tip: You can use the WebPartManager.Personalization status to add different editor parts. For example you can have one for the Shared scope and another for the User scope

    The WebBrowsableObject property is used to get a reference to the Web Part, just return the this object in your editor parts. This property is used by the editor part to get which web part to edit, via the WebPartToEdit method.

    The result

    If we now compile and test this web part we will have an interface that looks something like this. Now we have the edit part located at the top of the tool pane, instead of below - easier to find.

    First...

    It works, but looks awful.

    Make it more user friendly

    We only want the search string to be visible when the Search mode is selected, and the same for the username and User mode, so we have to hook up some events to this editor part. This is standard ASP.NET control programming and easily done.

    To make it look a bit nicer we reuse some SharePoint CSS classes and I also set a title of the editor part…

    protected override void CreateChildControls() {
    
        this.Title = "TweetPart properties";
    
        // Add controls here
        m_editorPanel = new Panel();
        m_editorPanel.CssClass = "ms-ToolPartSpacing";
        this.Controls.Add(m_editorPanel);
    
        m_modesPanel = new Panel();            
        m_modesPanel.Controls.Add(new LiteralControl("<div class='UserSectionHead'>Mode</div>"));
        m_modesPanel.Controls.Add(new LiteralControl("<div class='UserSectionBody'><div class='UserControlGroup'><nobr>"));
        m_lbModes = new ListBox();
        m_lbModes.CssClass = "UserInput";
        m_lbModes.Width = new Unit("176px", CultureInfo.InvariantCulture);
        foreach (string mode in Enum.GetNames(typeof(TwitterTimeLineMode))) {
            m_lbModes.Items.Add(mode);
        }
        m_lbModes.AutoPostBack = true;
        m_lbModes.SelectedIndexChanged += new EventHandler(m_lbModes_SelectedIndexChanged);
        m_modesPanel.Controls.Add(m_lbModes);
        m_modesPanel.Controls.Add(new LiteralControl("</nobr></div></div>"));
        m_editorPanel.Controls.Add(m_modesPanel);
    
        m_searchPanel = new Panel();
        ...
        m_editorPanel.Controls.Add(m_searchPanel);
    
    
        m_usernamePanel = new Panel();
        ...
        m_editorPanel.Controls.Add(m_usernamePanel);
    
        ...
    }

    I use a set of Panel objects, which I hide depending on the selection in the list box. The list box has an event handler for when the selected index changes and reloads the editor part, I also made it automatically post back when the user selects anything in the list box. Check out the source (provided below) for more information.

    Now it looks like this, a whole lot nicer. In upcoming posts I will show you have to make it even one notch better, using templates and less code.

    Final...

    And it works as it should. Also note that we still have the tweet count property as a automatic property, when in shared mode.

    Try it!

    If you would like the code, it’s available here but if you are interested in using the TweetPart you can download the WSP here. Visual Studio 2008 and STSDev are required to compile the code.

    Next part…

    Next part in this series, will focus on how to further improve the experience using Web Part properties and Editor Parts.

    Until next time…

  • Web Part Properties - part 1 - introduction

    Tags: .NET, C#, SharePoint, Web Parts

    I thought that I should kick off this new year with a series of posts on how to make your SharePoint Web Parts editable and how to enhance that out-of-the-box Web Part property editing combined with some tips and tricks.

    This first post may be to most of you SharePoint developers somewhat basic, but I have chosen to start from scratch here. Many of this first post topics are repeatedly asked in the MSDN development forums. The documentation in the SharePoint SDK on this topic is really bad; it just says do this and do that, never why you should do it. Often this makes developers unaware of pitfalls or possibilities.

    Note: Although I talk about SharePoint Web Parts here, most of these techniques can be used in plain ASP.NET 2.0 Web Parts also.

    Sample Web Part - TweetPart

    TweetPart I will throughout this series use a sample Web Part which reads information from Twitter and displays the tweets in the Web Part – called TweetPart. This Web Part will allow the users to choose what tweets to see; the public time line, a user time line or a Twitter search feed. Administrators are allowed to set how many tweets to display.

    All sample code are written using .NET 3.5.

    Properties of a Web Part

    A Web Part class can contain properties which can be edited in the web interface or application development environment. To be editable the property has to be marked with a set of attributes which specifies how and who can edit the property.

    Our sample Web Part needs four properties to work;

    • Display mode – an enumeration on what type of tweets to show
    • User name – a string, if the user time line mode is chosen
    • Search text – a string, if the Twitter search mode is chosen
    • Tweet Count – the number (integer) of tweets to show

    The TweetPart is a Web Part derived from the ASP.NET 2.0 WebPart class, more on this in the coming posts.

    Note: When creating editable properties for your Web Part you have to create properties that are read/write, public and called without parameters.

    I want all of these four properties to appear when someone modifies the Web Part, so I have to mark all four of these properties as WebBrowsable. This indicates to SharePoint that the property can be edited in the web the tool pane. The system will take care of how the user interface will look like; strings will be text boxes, booleans will be check boxes, enumerations will be dropdowns etc.

    Note: A common error here is that the Browsable attribute is used instead, which is used when designing components and controls for visual designers. This attribute was also used when developing Web Parts for SharePoint 2003 with the SharePoint WebPart class.

    To make the properties appear there is one more thing you have to do, you have to add the Personalizable attribute and set the personalization scope. This attribute tells the Web Part Manager that this property value is persisted. If you set the scope to User (default), then users (Members) can modify this property and if it’s set to Shared only editors (Owners) are allowed to change the property.

    Tip: If you omit this attribute, you cannot change it through the web interface, only through code or tools such as SharePoint Designer. This might be a preferred solution in some cases.

    This will make your custom tool pane look like this:

    Custom property

    Now things work, you can edit and save the value of the property and it is stored in SharePoint. But to further enhance the editing experience you should make it more user friendly.

    Make the tool pane more user friendly

    You should give it a name and a description, shown as a tooltip, to show in the editing tool pane that are more user friendly than the name of the property. Don’t rely on that your users or administrators interpret your property names correct. This is done with the WebDisplayName and WebDescription attributes.

    The tool pane has a set of categories (Appearance, Advanced and Layout) which are reserved for the base class properties. The custom properties will end up in a category called Miscellaneous, if you do not provide your own category with the Category attribute.

    Note: You cannot add properties to the reserved categories.

    So this is how we should define our custom properties, at the minimum:

    [WebBrowsable]
    [WebDisplayName("User name")]
    [WebDescription("The Twitter Username")]
    [Category("Twitter")]
    [Personalizable(PersonalizationScope.User)]
    public string Username {
        get;
        set;
    }

    This property now has a friendly name and a description, it’s located under the Twitter category and users can change the value of it, and have their own values.

    Note: If you make changes to it in the Shared view, default if you are an admin, it will be the default values for users who have not personalized the Web Part.

    The same is done for the other three properties and now the Twitter category looks like this when editing the Web Part:

    Shared tool pane view of TweetPart

    Shared only properties and storage

    I want the Tweet count property to be edited only by those who are allowed to edit the Shared view of the web part, therefore I change the PersonalizationScope of the Personalizable attribute to Shared. This means that this property will not be displayed when editing the personal (My) view of the Web Part.

    I also add and specify the WebPartStorage attribute to Shared, this makes the Web Part store only one set of value for this property. Default is the Personal storage mode, which means that every user has it’s own property value.

    Tip: If you set the storage to Shared and personalization scope to User then every user can edit the same (shared) value.

    Now this property looks like this:

    [WebBrowsable]
    [WebDisplayName("Tweet count")]
    [WebDescription("Number of tweets to show")]
    [Category("Twitter")]
    [Personalizable(PersonalizationScope.Shared)]
    [WebPartStorage(Storage.Shared)]
    public int TweetCount {
        get;
        set;
    }

    if you now open up the shared properties of the Web Part, then it looks the same as above, but if you instead go to the personal view then it looks like this:

    Personal tool pane view of TweetPart

    As you can see there is no Tweet Count property to edit, it’s only available in shared mode.

    Tip: To switch between Shared and Personal mode just add this parameter to the query string PageView=[Shared|Personal].

    Run it

    Now we have fixed the configuration of the TweetPart, let’s put it into action. As this series focuses on the editing of the properties I don not go into how I have created the actual rendering of the TweetPart using the Twitter API. It’s pretty simple and you can browse the code to see how it works.

    Public time line User time line Twitter Search
    TweetPart - public time line TweetPart - user time line TweetPart - Twitter Search

    The code

    Download the code sample below. It’s built using STSDev using Visual Studio 2008. If you prefer to just download the finished solution, it’s also available for download.

    Next step…

    Using this method of making your Web Part personalizable is fine, but there are some things that does not make it that user friendly or smooth. First of all the custom categories ends up last amongst the categories – your users might miss the properties to edit. Secondly this sample Web Part, has properties depending on each other (username is only required when using user time line and search text only when using search mode). Your own Web Parts may have more advanced dependencies or require that lists are filled during the editing.

    This is what I’m going to show during the next part of the series.

    Share your experience and stay tuned…

    Technorati tags: , ,

  • PDC 2008: Day 3, the picture is getting clearer

    Tags: .NET, SharePoint, Internet and the Web, Office Open XML, PDC 08, Windows 7

    Day three is officially over, I’m pretty tired today after staying up to late yesterday and playing around with the “goods”. I installed Windows 7 and tried it for a while, but to my disappointment I found out that the nice stuff that were shown on the keynote was missing in my release…

    This morning started with the last keynote of PDC 2008 and it was Microsoft Research that should be in the spotlight. An hour and a half was filled with stuff such as environment and healthcare studies done by MSR, important, but hey – you have an audience of 6.000 programmers/geeks here… The last 20-30 minutes was cool though, they showed up a kids-programming-language called Boku (not only for kids, for me too!) and Second Light an evolution of Surface, where you can project a secondary image onto a surface that is above, yup not in touch with, the surface. Really cool!

    First session I attended after the keynote was about how to architect services for the Live Framework – It’s all about using HttpWebRequest and RESTful services. If you know about these you can work with the Mesh and Azure. Now I’m just waiting for my activation codes for Azure and that Live Mesh will support non-English regional settings..

    I took a quick lunch so I could do one of the hands-on-labs with Microsoft Surface. Easy lab, but I spent some time extra and played with it. All is based on WPF and XAML and it’s really easy. Finishing the lab allowed me to claim the SDK for Surface, which otherwise is quite expensive, so I will have it within a few days. All that then remains is someone to hand me $12.500 so I can replace my living room table at home with a brand new Surface machine!

    Then it was time for some more of the Oslo stuff and this time the Quadrant application. Quadrant is the program to use when you are visualizing the repository you have described using the M-language. It’s one heck of a tool which you can turn inside out and more, but the question still remains – how will this really be useful? I’m sure that Don Box and his crew had a lot of fun making these tools and languages, but at this “pre-alpha” stage of Oslo, I have hard to tell how to apply this to my daily work.

    To ease things up I went to a talk about Oomph, an incubator project from Microsoft that tries to take advantage of the Microformats such as hCalendar and hCard. The session was a little to light-weight but shows the intention from Microsoft to take advantage of existing standards.

    Last session of the day was a long awaited talk from Miguel de Icaza on the Mono project, an open source version of .NET that runs on Linux, Max and Windows machines. Miguel made some really nice demos and it was neat to see how far Mono has come. I did participate in the first release of Mono with some contributions. Mono has some really nice features, such as the C#5(?) compiler as a service, and some sweet JIT optimizations that makes Mono worthy as a game framework. The Mono project also implements a Linux version of Silverlight, version 1.0 will ship any day now and version 2 will be at beta for Mix 2009.

    The Mono talk, Oomph talk, Windows 7 Wordpad with ODF/OpenXml support and a bunch of different framework released under the MS-PL open source license really makes me see a Microsoft in change.

    Before finishing the day off I walked around and talked to various experts in the Meet the Experts reception at the convention center. Tried to get some more information on Office “14”, but in vain…

    During this day the picture of Windows Azure is getting clearer, but the picture of Oslo is still quite blurry. I still have hard to find out to what Oslo is really about but I think I’m getting there – I have to try it some more.

  • PDC 2008: Day 1 and Windows Azure

    Tags: .NET, C#, SharePoint, PDC 08

    Back at the hotel and watching some Monday Night Football (which I could do that in Sweden!). Here is a summary and some reflections on my day.

    Woke up early and walked down to LA Convention Center and got me some breakfast (tomorrow I’ll eat at the hotel). I tried to get to the keynote hall as early as possible for some good seating. I ended up in 6th row and had a good overview of the stage and the huge screens. As this is my first PDC and first conference of this magnitude I’m really impressed with the size and organization of it all.

    Ray Ozzie, Microsoft Chief Architect, hit the stage and did after an introduction introduce Windows Azure – Microsoft’s new cloud server and offering. Windows Azure and the Windows Azure Platform is Microsoft’s way of hosting your services in the cloud. Microsoft will also have a set of services ready; such as Exchange Online, SharePoint Online, Dynamics CRM Online etc. Windows Azure pricing will be based on subscriptions and SLA’s and competitive.

    Windows Azure

    I think the Windows Azure Platform can be really interesting. The thing that really made me interested was that you can federate your Active Directory (and/or your customers) and use that as authentication on your services in the cloud. I really like what Patrik Löwendahl calls it (article in Swedish): “Outsourcing 2.0”.

    After the keynote I went to a session on which I had big expectations: SharePoint Online extending your service. This session was about the SharePoint Online service hosted on Windows Azure. Small summary: SharePoint is hosted by Microsoft and you pay per user! The session and the content was really bad – from several perspectives. First of all we in the audience, several SharePoint MVPs were there, expected more stuff for developers than just SharePoint Designer editing. The only way to add code that makes something real is to host it in a Silverlight application. And then the presenter had a rough mission presenting this non-interesting material for a demanding crowd, especially since this session was an Advanced session! I’ll try to ignore I was there…

    Then I headed over the the Big Room and got stuck when Chris Anderson made a spontaneous demo of the new M-language. It looked really cool when he on-the-fly showed the small crowd how to create a schema from a text and then validate your input and create structured data. Got a book with the draft specification of the language and I will browse it through until tomorrow when Chris and Don Box will have their keynote. After this I tried on some Hands-On Labs with the Windows Azure federated authentication – sweet!

    Chris Anderson demonstrating M

    Then I, and a lot of people, headed over to listen to Anders Hejlsberg (Anders was really the one who made me interested in programming with Turbo Pascal in the 80’s) talk about the future of C#. Anders presented some new stuff that will be in C# 4.0 such as the dynamic keyword, which will combine the features of dynamic languages with C#. Anders made some really nice demos of this, and he actually copied some JavaScript code and pasted it in the C# file, compiled it (just a few small changes) and run it. His demos did receive more applauses than Rays keynote this morning. Some other nice stuff Anders presented was optional and named parameters. He also gave us some hints on what will happen after C# 4.0 – “Eval” in C#! This is what I really look forward to, but that’s long down the road…

    I had hard then deciding which session to attend and I finally selected ASP.NET MVC. Really good session with really good presenters. I like lean and neat HTML code and the MVC model. I hope to get to do some nice projects with this in the future. Unfortunately I’m very bound to SharePoint now so that will likely not happen so soon, if not SharePoint “14” will use this…say no more!?!

    Verne Troyer at PDC 2008

    Last session for today became WF 4.0 – first look which was about the new stuff in Workflow Foundation. Good session and good speakers here too. Tools, persistence and performance was the mantra for this session. WF sounds so cool in English – dub-F, can’t really say that at home in Swedish…

    Then it was freebie time with food and beer in the sponsor area. I now have a set of t-shirts to wear when painting the house. Some interesting sponsors and some interesting give-aways. Did have some time to play with Surface a little more, if I win on lottery I'll order one right away!

    More keynotes tomorrow, more focused on the client side, the bits is distributed and then there is the attendee party at Universal Studios…

  • A request to the SharePoint Development Team

    Tags: .NET, SharePoint

    Microsoft SharePoint is a great development platform but it have some major areas where it could be improved. As of today you can create mediocre applications using the current SDK (which is not so well documented), but to create great applications you really need to understand how the internals of Windows SharePoint Services really works!

    I would like to show you an example of how bad the documentation and implementation is with a pretty common scenario.

    The problem

    Assume that you need to get your hands on an SPList object using the name of the list. MSDN contains an article called Development Tools and Techniques for Working with Code in Windows SharePoint Services 3.0 which has an example which goes like this:

    try
    {
        // -- Check if list exists.
        SPList list = web.Lists["MSDN Tasks"];
    }
    catch 
    {
        ...
    }

    This is the way to do it, except that you should use some nicer exception handling and not catch a generic exception. So take a look at the MSDN documentation for this one, there is no work about the exception or anything, not even that it fires an exception when not found. Most examples I see catches the base Exception class to be safe (and most often around larger code blocks than this!):

    try
    {
        // -- Check if list exists.
        SPList list = web.Lists["MSDN Tasks"];
    }
    catch (Exception ex)
    {
        ...
    }

    Any list or collection should throw an ArgumentOutOfrangeException or at least ArgumentException in these cases, nothing about that on MSDN. As I really like to have things in order, a quick check using Reflector on the methods shows that an ArgumentException is really thrown under these circumstances. So the correct way is to write:

    try
    {
        // -- Check if list exists.
        SPList list = web.Lists["MSDN Tasks"];
    }
    catch (ArgumentException ex)
    {
        ...
    }

    This is not only the correct way (with or without documentation), it’s the only. Imagine that you have this piece of code in your application and you frequently makes this check – how about performance. We all know that exception handling is process-cycle consuming, so this can be a real performance bottle neck if you don’t watch out.

    While checking out the code using the Reflector I found out that the indexer on the SPListCollection uses internal methods to find out if a list exists or not which does not involve exception throwing. The exception is only thrown when we poor developers use the APIs. Inside the SPListCollection object is an internal method called GetListByName which works just like the indexer, but has a second boolean parameter which can be used to tell the method if we want an exception to be thrown when not found or just return null. If we were allowed to use this method, then our sample would look like this:

    // -- Check if list exists.
    SPList list = web.GetListByName("MSDN Tasks", false);
    if(list == null) 
    {
        ...
    }

    Wow, now we could make some real use of this in high performance required scenarios – no exception handling involved.

    The request…

    To get this to work, all the SharePoint Development Team has to do is to make this method public! Please! I think it would be a great idea to go through the API’s of SharePoint and check these kind of things out.

    This is by no means the only sample of code that easily can be made more efficient for us developers (outside of Redmond).

    Technorati tags: , ,

  • Visual Studio 2008 Service Pack 1 available with new devenv.exe icon

    Tags: .NET, Visual Studio

    Microsoft has now released the final bits of Visual Studio 2008 Service Pack 1 and the .NET Framework 3.5 Service Pack 1, download here. A lot of stuff has been improved such as stability and performance, no need for me to repeat all this since you can find it a gazillion of blogs as well as in the Microsoft Knowledge Base.

    One improvement I did not read about is that they have fixed/updated the icon of the devenv.exe so you can distinguish VS 2008 and VS 2005 if you are running them simultaneously. The VS 2008 SP1 icon contains a 9 in the lower right corner.

    Visual Studio 2008 SP1 in the task bar

    Look at the icons in the images below; from left to right it is Visual Studio 2005, Visual Studio 2008 RTM and Visual Studio 2008 SP1. The 2008 version is a bit more glossy, but the smallest icons look pretty similar (VS 2005 on top).

    Visual Studio icons image

    Great!

    Technorati tags: , ,

About Wictor...

Wictor Wilén is a Director and SharePoint Architect working at Connecta AB. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for four consecutive years.

And a word from our sponsors...

SharePoint 2010 Web Parts in Action