Sunday, February 13, 2011

Customizing the Quick Launch menu: Adding fly-out menus to SharePoint navigation


In this post, I’ll show you how to customize the Quick Launch menu to display several levels of data in a dynamic way and use this customized menu for quick access to all Views within a List without consuming space on the Quick Launch.
First, let’s add a List and make sure it shows on the Quick Launch. Let’s call this list “Navigation Test List”, and then add 4 Views to the list.
Next, let’s write some OM code that, when run, adds a link to each of the List’s Views under the List Link on the Quick Launch. Add the following code to a new C# Console Application in Visual Studio .NET or 2005 (and don’t forget to add a reference to Microsoft.Sharepoint.dll).
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            SPSite site = new SPSite("http://server");
            SPWeb web = site.OpenWeb();
            SPList list = web.Lists["Navigation Test List"];
            SPNavigationNode rootListLink = web.Navigation.GetNodeByUrl(list.DefaultViewUrl);
            SPNavigationNode node = null;
            foreach (SPView view in list.Views)
            {
                node = new SPNavigationNode(view.Title, view.Url, false);
                rootListLink.Children.AddAsFirst(node);
            }
        }
    }
}

At this point, we have links to all of the Views under the List, but they cannot be displayed since the menu control ignores the links after the second level. So, let’s modify the menu control to display what we want. Perform the following to accomplish this task:

1.     Navigate to the master page gallery: From the home page click on Site Actions, then Site Settings, and then on Master Pages, under the Galleries column
2.     Click on the drop down menu for the master page you want to modify, and then click on Edit in Microsoft Office SharePoint Designer
3.     Locate the Quick Launch Menu control, and modify the StaticDisplayLevels and MaximumDynamicDisplayLevels attributes:
<SharePoint:AspMenu
id="QuickLaunchMenu"
DataSourceId="QuickLaunchSiteMap"
runat="server"
Orientation="Vertical"
StaticDisplayLevels="2"
ItemWrap="true"
MaximumDynamicDisplayLevels="1"
StaticSubMenuIndent="0"
SkipLinkText="">
4.     Save your changes and reload the page from the browser. Hover over the Links on the Quick Launch. The end result should look like this:

5.     Optional: Modify other properties in the menu control to match the look and feel of your site. The above steps can also be applied to the Top Link Bar.

Sunday, December 12, 2010

Search Core results webpart

To implement a search UI quickly, we can use the content editor web part to generate the UI.  After you get the UI on track, how do you get the search working.
1. Add the search core results web part to the page.
2. Configure the search core results web part:
image





  1.  a) Set the number of results to display.
  2.  b) Set the selected columns that you want to display. These columns are basically managed properties which can be changed/added in the shared service provider. Once you add the columns that you want, they can be rendered using the XSL for the search results web part.
  3.  c). Set the Cross-Web Part Query ID property to “User Query”. This value tells the web part to pick up the search criteria from the query string.
d) Change the XSL, so that it renders the results as you require. I have mentioned an easy way of generating the XSL at the end of this blog.










The search results web part works on query string parameters.
1. The parameter “K”: This parameter can be used to specify keyword or any other managed properties that you want to include and search for. For example: if you have a managed property called “StoreLocation”, then you include the following in the value of the K parameter. http://server/pages/default.aspx?k=StoreLocation:Illinois
You could add the keywords to the K parameter in addition to any managed property.
Now that you know what the search results web part expects, all we have to do is to write a small javascript in our Content Editor Web Part which will gather the values from all the controls and generate this query string. Once this query string is generated, add the following statement to the end of the javascript, window.location = window.location.pathname  + strGeneratedQueryString;
This will redirect to the same page with the correct parameters and the search results will come up.
You could add another button to clear the search results, all you have to do on the click event of the button is to clear the query string and redirect to the same page.
window.location = window.location.pathname;
* You will have to write some additional script to make sure the controls in the Content Editor Web Part retain the values that the user has searched for.

XSL Generation:
I learnt this technique from one of Patrick Tisseghem’s books. 
1. Edit the XSL from the search core results web part.
2. At the end of XSL, where you find a match for the root element (“/”), add the following statement : <xsl:copy-of select=”*”/>
3. Save and let the search component render.
4. Right click on the page and hit View Source.
5. Locate the XML that is generated by the search results web part.
5. Save this XML as results.XML ( File name is irrelevant)
6. Open Sharepoint Designer, and open any aspx page that you could use for your temporary work.
7. In the data source library, add a new data source for XML. Import the results.xml.
8. Now drop a Data View web part,  and drag and drop the columns from the xml data source that we just defined.
9. You can now edit the xsl as you would for any data view web part. Add grouping, sorting etc.
10. Once your done, go to the source view and copy the XSL style sheet element from the data view web part and paste it in your search results web part xsl editor window.
Now you have a brand new rendering of the search results.

Tuesday, December 7, 2010

Integrating ASP.NET AJAX with SharePoint

Microsoft ASP.NET AJAX 1.0: A Background
Microsoft ASP. NET AJAX 1.0 lets developers build Web 2.0 sites using the latest Ajax techniques. 
ASP.NET AJAX extends ASP.NET 2.0 and makes several new tools and techniques available to help you build applications more quickly:
  • Extensions to JavaScript.  ASP.NET AJAX extends the JavaScript library to bring standard object oriented concepts to JavaScript.  It brings a formal type declaration system, with support for inheritance.  It also provides a significant number of out of the box types, including types such as Sys.Net.WebRequest for working with web services.  Finally, it helps to abstract some cross-browser issues such as XML element traversal.  This makes it much easier to create robust JavaScript libraries and frameworks which are commonly needed by rich internet applications.
  • ASP.NET Control Extenders.  Extenders are additional ASP.NET controls which can extend the functionality of existing controls with additional Ajax capabilities.  A common example is an extender which allows existing textbox controls to have autocomplete functionality with no modification to the extended control.   (The autocomplete extender is included with the ASP.NET AJAX Control Toolkit.)
  • UpdatePanels.  UpdatePanels allow your existing ASP.NET controls and web parts to achieve the fluid, no-postback updates of Ajax-based applications with minimal re-coding of your control or part.  Quite simply, controls within the UpdatePanel control which ordinarily would post back to update their data will now be routed through an Ajax-style callback, resulting in a silent update back to the server.  This makes your application “postback” much less, making interaction with your control more seamless.
With Microsoft ASP.NET AJAX 1.0, you can build more dynamic applications that come closer to the rich style of interruption-free interaction you may see in standard client applications.
Microsoft ASP.NET AJAX 1.0 and SharePoint
Windows SharePoint Services version 3 builds much more directly on top of ASP.NET 2.0; therefore, many of the capabilities of ASP.NET AJAX work directly with SharePoint. 
However, in a few cases there are some compatibility issues between ASP.NET AJAX and SharePoint which are anticipated to be addressed in the first service pack of Windows SharePoint Services.  For this reason, until that first Service Pack of Windows SharePoint Services, we are unable to offer formal support through Microsoft Product Support Services for usage of ASP.NET AJAX within a SharePoint Web site.  This post is intended to provide developers with some guidelines for evaluating ASP.NET AJAX and WSS3.0. 
Specifically, there are some limitations on usages of the UpdatePanel in your web parts and controls.  Some approaches are described below to address these limitations, but these are workarounds and as such may cause other issues in your application.
Here are some common scenarios in SharePoint you should be able to achieve with Microsoft ASP.NET AJAX 1.0:
  1. Building a more powerful, re-usable JavaScript libraries you can use in your web controls and parts
  1. Enabling your web services to render via JSON, resulting in easier usage in JavaScript/Ajax Applications
  2. Building a web part that takes advantage of Extender technology to provide richer interaction styles, such as autocomplete on a textbox.
  3. Using an UpdatePanel in your web part or control for more fluid, no postback interaction. (this will require some workarounds, however.)
Adding Microsoft ASP.NET AJAX Technology to SharePoint Pages
To extend your SharePoint site with Microsoft ASP.NET AJAX 1.0, you’ll need to perform a few steps. 
  • First, you will need to download and install ASP.NET AJAX on servers in your farm.
  • Second, you need to extend web.config with some settings to enable ASP.NET AJAX technology. 
  • Third, you will need to add the ASP.NET AJAX Script Manager into your master page to enable scenarios such as Extenders or UpdatePanels.
Installing ASP.NET AJAX on servers in your farm
You will want to install the full "ASP.NET 2.0 AJAX Extensions 1.0" from ajax.asp.net.
Extending SharePoint web.config files with Microsoft ASP.NET AJAX 1.0
Extending SharePoint web.config files with ASP.NET AJAX requires that you interleave some Ajax registration entries in-line with WSS registration entries.  To do this you will need to edit your SharePoint web.config file, typically in a directory like c:\inetpub\wwwroot\wss\virtualdirectories\80.
1. Add a <sectionGroup>element to the <configSections>tag:
<configSections>
    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
          <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication"/>
        <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
          <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere" />
          <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
          <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
        </sectionGroup>
      </sectionGroup>
    </sectionGroup>
</configSections> 
2. Add a <controls> section as a child of the <system.web>/<pages> tag:
<pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </controls>
</pages>
3. Add the following tag to the <assemblies> tag, within <compilation>:
<assemblies>
       <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</assemblies>
4. Add some new registrations to the end of the <httpHandlers> section:
 <httpHandlers>
      <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
</httpHandlers>
5. Add a new registration to the HttpModules section, beneath any existing registrations:
<httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
6. Add a SafeControl entry for the System.Web.UI namespace from Microsoft Ajax Extensions, within the <SharePoint>/<SafeControls>section:
<SafeControls>
      <SafeControl Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TypeName="*" Safe="True" />
</SafeControls>
7. Finally, add the following configuration tags at the bottom of web.config, near the bottom before the end <configuration> tag:
<system.web.extensions>
    <scripting>
      <webServices>
      <!-- Uncomment this line to enable the authentication service. Include requireSSL="true" if appropriate. -->
      <!--
        <authenticationService enabled="true" requireSSL = "true|false"/>
      -->
      <!-- Uncomment these lines to enable the profile service. To allow profile properties to be retrieved and modified in ASP.NET AJAX applications, you need to add each property name to the readAccessProperties and writeAccessProperties attributes. -->
      <!--
      <profileService enabled="true"
                      readAccessProperties="propertyname1,propertyname2"
                      writeAccessProperties="propertyname1,propertyname2" />
      -->
      </webServices>
      <!--
      <scriptResourceHandler enableCompression="true" enableCaching="true" />
      -->
    </scripting>
  </system.web.extensions>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-Integrated" />
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode"
           type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </handlers>
</system.webServer>
Adding a ScriptManager into a SharePoint MasterPage
Many components of ASP.NET AJAX require the inclusion of a .NET ScriptManager control within a page. 
Although it may be possible in some cases to dynamically insert a script manager from within a control, in many cases the control may not be able to insert the script manager early enough in the page lifecycle depending on how the control is used, making this tricky to get right.  Also, the control implementer will need to ensure that multiple instances of their control (or other controls) do not result in the addition of multiple script managers within the page. For these reasons, dynamic insertion of a ScriptManager control from another control is not recommended.
To statically embed a script manager into a page, it is recommended that you add the ScriptManager into the master page of a site.
To do this, open up the master page for your site.  Typically, this will be located at <site url>/_catalogs/masterpage.  You can edit this file by opening it in an editor such as Microsoft SharePoint Designer, or directly in Notepad by opening your master page library via DAV (typically file://server/%3Cpathtosite%3E/_catalogs/masterpage.)
Add the following into the markup of your page.  A recommended location is right beneath the WebPartManager registration  (search for  <WebPartPages:SPWebPartManager id="m" runat="Server" />): 
    <asp:ScriptManager runat="server" ID="ScriptManager1"></asp:ScriptManager>
Using UpdatePanels within SharePoint
UpdatePanels are a very useful addition to ASP.NET AJAX, and represent the simplest way to convert existing, standard ASP.NET controls and parts to take advantage of Ajax techniques.  However, there are some changes within Windows SharePoint Services which may get in the way of working with ASP.NET AJAX.
Windows SharePoint Services JavaScript has a “form onSubmit wrapper” which is used to override the default form action.  This work is put in place to ensure that certain types of URLs, which may contain double byte characters, will fully work across most postback and asynchronous callback scenarios.  However, if your scenarios do not involve double byte character URLs, you may successful disable this workaround and gain the ability to use ASP.NET AJAX UpdatePanels.
To do this, you may need to register a client startup script which disables this workaround, in addition to resetting the default form action:
    <script type='text/javascript'>_spOriginalFormAction = document.forms[0].action; _spSuppressFormOnSubmitWrapper=true;</script>
This script may be directly embedded in the page, or could be emitted by a control that uses the UpdatePanel.  The following is an example of a very simple ASP.NET Web Part which uses UpdatePanel capabilities:
using System;
using System.Collections;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI;
namespace MS.Samples
{
    public class AjaxUpdatePanelPart : WebPart
    {
        private Label label;
        private TextBox textBox;
        protected override void  CreateChildControls()
        {
      base.CreateChildControls();
            this.EnsureUpdatePanelFixups();
            UpdatePanel up = new UpdatePanel();
            up.ID = "UpdatePanel1";
            up.ChildrenAsTriggers = true;
            up.UpdateMode = UpdatePanelUpdateMode.Conditional;
            this.Controls.Add(up);
            this.textBox = new TextBox();
            this.textBox.ID = "TextBox";
            up.ContentTemplateContainer.Controls.Add(this.textBox);
            this.label = new Label();
            this.label.Text = "Enter your name.";
            up.ContentTemplateContainer.Controls.Add(this.label);
            Button button = new Button();
            button.Text = "Say Hello";
            button.Click += new EventHandler(HandleButtonClick);
            up.ContentTemplateContainer.Controls.Add(button);
        }
        private void HandleButtonClick(object sender, EventArgs eventArgs)
        {
            this.label.Text = "Hello " + this.textBox.Text;
        }
        private void EnsureUpdatePanelFixups()
        {
            if (this.Page.Form != null)
            {
                string formOnSubmitAtt = this.Page.Form.Attributes["onsubmit"];
                if (formOnSubmitAtt == "return _spFormOnSubmitWrapper();")
                {
                    this.Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();";
                }
            }
            ScriptManager.RegisterStartupScript(this, typeof(AjaxUpdatePanelPart), "UpdatePanelFixup", "_spOriginalFormAction = document.forms[0].action; _spSuppressFormOnSubmitWrapper=true;", true);
        }
    }
}
Output Caching and ASP.NET AJAX
ASP.NET AJAX infrastructure is not compatible with output caching features.  This output caching infrastructure is a featured component of managed content pages such as those supported by web content management features in Microsoft Office SharePoint Server.  For this reason, many scenarios which involve output cached features may not be able to take advantage of components like UpdatePanel.  However, you will be able to successfully use other ASP.NET AJAX features, such as the JavaScript library, combined with your output cached pages.
Compatibility with output caching is targeted for a future release of ASP.NET AJAX infrastructure.
Conclusion
Microsoft ASP.NET AJAX 1.0 provides great building blocks for building rich Ajax-enabled applications.  Combined with the power of the SharePoint platform, and knowing some of the integration limitations, you can build powerful Web2.0 applications that bring together the best of both of these technologies.

Tuesday, November 30, 2010

HOWTO: Create an Event Handler for SharePoint(MOSS 2007)

As I see this question popping up on many forums, I thought it would be time to write a tutorial about it, even though there are already quite a few of them handling the subject.
Prerequisites:
How-to Create an Event Handler by making use of a feature:
To start with : what exactly is an event handler for SharePoint? It’s a piece of code that is triggered when something (an event!) happens. When that happens, our event handler can replace what is supposed to happen with our own code. How do we build that in Visual Studio (using WSP Builder)?
First of all, we will be creating a WSP Builder Project called MyEventHandler:
image
Once the project is created, we will right-click the project and select add new item. In the left column, select WSPBuilder and select Event Handler in the template list. In the name field I chose to call it DemoEventHandler.
image
You’ll get a new screen where you can define the scope of the feature. You can leave it at Web
image
After this step your project will have three additional files added to it and a few folders:
image
feature.xml: the CAML based declaration of your feature.
elements.xml: the CAML based declaration of the element(s) in your feature, which is your event handler in this case.
DemoEventHandler.cs : the code that will be overriding the existing SharePoint Event Handlers.
Let’s take a look at our feature.xml code:
<?xml version=
1.0 encoding=utf-8?>


<Feature Id=
875e92bb-782c-40b4-a5a9-f55423df667e


    Title=
DemoEventHandler


    Description=
Description for DemoEventHandler


    Version=
12.0.0.0


    Hidden=
FALSE


    Scope=
Web


    DefaultResourceFile=
core




    xmlns=
http://schemas.microsoft.com/sharepoint/>


    <ElementManifests
>


      <ElementManifest Location=
elements.xml/>


   </ElementManifests
>


</Feature>
What this file does is identify the feature for SharePoint (Id), give it a title and description (which will be shown on the feature activation site), define a scope (where Web means site, where Site means Site Collection and then there is Web Application and Farm as possible scopes.
Another important part of the feature is the <ElementManifests> area. That area defines all the items that make part of the feature while the manifests themselves describe that specific part. As it is here the case with the event handler:
<?xml version=
1.0 encoding=utf-8 ?>


<Elements xmlns=
http://schemas.microsoft.com/sharepoint/>


   <Receivers ListTemplateId=
100>


      <Receiver
>


         <Name>
AddingEventHandler</Name>


         <Type>
ItemAdding</Type>


         <SequenceNumber>
10000</SequenceNumber>


         <Assembly>
MyEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ca176e059473d6b1</Assembly>


         <Class>
MyEventHandler.DemoEventHandler</Class>


         <Data></Data
>


          <Filter></Filter
>


      </Receiver
>


   </Receivers
>


</Elements>
What is important for us? First of all the ListTemplateId. The ListTemplateId defines to which List Types the Event Handler will be targeting. The table here below shows which list types there are available in SharePoint 2007:


IDName
100Generic list
101Document library
102Survey
103Links list
104Announcements list
105Contacts list
106Events list
107Tasks list
108Discussion board
109Picture library
110Data sources
111Site template gallery
112User Information list
113Web Part gallery
114List template gallery
115XML Form library
116Master pages gallery
117No-Code Workflows
118Custom Workflow Process
119Wiki Page library
120Custom grid for a list
130Data Connection library
140Workflow History
150Gantt Tasks list
200Meeting Series list
201Meeting Agenda list
202Meeting Attendees list
204Meeting Decisions list
207Meeting Objectives list
210Meeting text box
211Meeting Things To Bring list
212Meeting Workspace Pages list
300Portal Sites list
301Blog Posts list
302Blog Comments list
303Blog Categories list
1100Issue tracking
1200Administrator tasks list
2002Personal document library
2003Private document library


Once we have defined which list we are going to target we will define that we are overriding an ItemAdding event. ItemAdding means that the event will be fired right before the item is added to the list. This allows us to modify the item before it is saved to the list. The other parameters aren’t that important at the moment, apart from the Assembly and Class that will be linking to the assembly that contains the code of your event handler.
Possible events that you can override:
ItemAdded
ItemAdding
ItemAttachmentAdded
ItemAttachmentAdding
ItemAttachmentDeleted
ItemAttachmentDeleting
ItemCheckedIn
ItemCheckedOut
ItemCheckingIn
ItemCheckingOut
ItemDeleted
ItemDeleting
ItemFileConverted
ItemFileMoved
ItemFileMoving
ItemUncheckedOut
ItemUncheckingOut
ItemUpdated
ItemUpdating
Ok, so we checked out the feature.xml and the elements.xml, but there is also the DemoEventHandler.cs file. That contains the actual code of our event handler:
using
System;


using
System.Collections.Generic;


using
System.Text;


using
Microsoft.SharePoint;




namespace
MyEventHandler


{


    class DemoEventHandler : SPItemEventReceiver


    {


      public override void ItemAdded(SPItemEventProperties properties)


      {


          base.ItemAdded(properties);


      }




      public override void ItemAdding(SPItemEventProperties properties)


      {


          base.ItemAdding(properties);


      }




      public override void ItemUpdated(SPItemEventProperties properties)


      {


          base.ItemUpdated(properties);


      }




      public override void ItemUpdating(SPItemEventProperties properties)



      {


          base.ItemUpdating(properties);


      }




    }


}
If you deploy it like this your event handler will run, but it will just call the base class and nothing special will happen. Let’s change the ItemAdding Event (as it is already defined in our CAML to be deployed). We will change the itemadding event so that it will check, when an item is being added, by making sure the CheckValue column does not contain the string “dontadd”. If it does contain dontadd, an error message is displayed and the item is NOT added to the list. To do this, we modify the ItemAdding Event to this:
public override void ItemAdding(SPItemEventProperties properties)


{


    if (properties.AfterProperties["CheckValue"].ToString() == “dontadd”)


    {


        properties.ErrorMessage = string.Format(“The CheckValue column equals dontadd -> item will not be added.”);


        properties.Status = SPEventReceiverStatus.CancelWithError;


        properties.Cancel = true;


    
}


}
A little extra explanation. The AfterProperties contain the NEW values of an item. The BeforeProperties contain the OLD values of an item in case of an update. For an ItemAdding event the BeforeProperties are empty. What we do here is check the CheckValue properties value. If it contains “dontadd” we show the error message and by making use of properties.Status = SPEventReceiverStatus.CancelWithError we cancel the base.ItemAdding(properties) call. By adding properties.Cancel = true we cancel the Itemadding event.
Ok, so now we built this, but how do we get this working on our SharePoint site? With WSPBuilder that is quite easy. Rightclick on your project, select WSPBuilder / Build WSP. This will create a solution file to be deployed on your SharePoint farm. Once that is done, select WSPBuilder / Deploy and the solution will be installed and deployed to your farm.
 image  
Ok, one thing to note here is that the event handler will be targeting all lists. This means that every list that does not contain the CheckValue column will no longer work. But checking if the column exists is something that you should be able to do yourself. Once it is deployed to your SharePoint farm, create a new Custom List and Add the column CheckValue of type text. Then go to Site Settings, Site Features (NOT Site Collection Features as the scope was Web) and activate our newly deployed feature:
image
Ok, now we can test it by adding a new item with CheckValue equal to dontadd.
image
If you did everything according to plan, this is the information you should be receiving when you click ok:
image
Happy Coding!
In addition I added a few other interesting bits regarding Event Handlers
How-to Register an Event Handler through C# code:
The following code allows you to register an event handler by making use of code. RunWithElevatedPrivileges isn’t always necessary, but I added it to it so that you know that you can’t run the code in an application page as a user who doesn’t have the necessary rights.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
   impersonateweb.AllowUnsafeUpdates = true;
   _spListAanwezige.EventReceivers.Add(SPEventReceiverType.ItemAdded, “Namespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=61942ef99a051977″, “Namespace.EventClass”);
   _ impersonateweb.AllowUnsafeUpdates = false;
});
How-to see if your event handler is deployed properly to the list:
Out of the box SharePoint doesn’t display if your event handler is correctly hooked to a list. I make use of SharePoint Inspector(http://www.codeplex.com/spi) to check out my SharePoint Farm. To see if something is hooked to your list go to the following structure in your SharePoint Inspector to check out which events are registered to your list:
image

Friday, November 26, 2010

Setting Permissions on SharePoint Views

 
Heres a little hack that you can do, in order to create permissions on views of any list or library.  I’m not going to say this is the most pretty or perfect solution, but it’s at least a way to accomplish this.  It gets asked all the time.  “How can I set permissions so that only certain people can see certain views of my list?” 

So the next option is a non-supported approach, but my favorite: use HTTP modules!

Http modules intercept page requests and allow custom code to run before the page actually renders. Thus, we can intercept the request and check if it is an application page. Then we can change the master page reference dynamically as the page renders.

To achieve this, follow these steps:
1.       Create a new VS project (Class Library project) and call it HttpModule
2.       Rename Class1 to MyHttpModule and add the following code to it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.IO;
using Microsoft.SharePoint;

namespace HttpModule
{
    public class MyHttpModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.PreRequestHandlerExecute += new EventHandler(validation_PreRequestHandlerExecute);
        }

         void validation_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            Page page = HttpContext.Current.CurrentHandler as Page;
            if (page != null)
            {
                page.PreInit += new EventHandler(validation_PreInit);
            }
        }
        void validation_PreInit(object sender, EventArgs e) {
            Page page = sender as Page;
            if (page != null) {
                string url = page.Request.Url.ToString ();
                if (url.Contains("/Lists/wjc/summary.aspx"))// Lists/wjc/summary.aspx is the relative url of list view.
                {
                    if (HttpContext.Current.User.Identity.Name != "MICRO\\porter")//MICRO\\porter is login name.
                    {
                        page.Response.Redirect("/_layouts/accessdenied.aspx");
                    }
                }
                if (url.Contains("/_layouts/accessdenied.aspx")&&page.Request .UrlReferrer .ToString ().Contains ("/Lists/wjc/summary.aspx")) {
                    if (HttpContext.Current.User.Identity.Name == "MICRO\\porter")
                    {
                        page.Response.Redirect("/Lists/wjc/summary.aspx");
                    }
                }
            }
        }
        public void Dispose()
        {
        }
    }
}


1.       Sign and build the project, then place the dll in the GAC
2.       Go to your site’s virtual directory location (usually at c:\Inetpub\wwroot\wss\VirtualDirectories\SITENAME)
3.       Add the next line to your web.config within the “httpModules” section:
<add name=”HttpModule” type=”HttpModule.MyHttpModule, HttpModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ca0f662d5d7f9d5d″ />

Hope this helps!