Wednesday, January 13, 2010

SharePoint Custom Action: Execute Code from the EditControlBlock Location

There are a few great blogs available to show how to develop custom actions. However, it is quite tricky to attach custom code to a EditControlBlock location.















Normally with most custom action locations, you can simply specify the assembly and control class in the Elements.xml file.



Example:
ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"
ControlClass="LaunchDocItemCustEvent.LaunchDocWriter";


But in the case of EditControlBlock you will get an “Invalid URL” error when you try execute the code.


You have to specify a custom target URL and not an assembly..example:
UrlAction Url=http://www.google.com


This article will show you how to work around this problem by applying a bit of Javascript and additional custom code.

The tutorial will show all the steps required to get our URLAction in the EditControlBlock to initiate a postback and we will then trap the postback in another (second) custom action which has a control class in place. From here we can then execute any custom code.


So, We will change to UrlAction from:
     UrlAction Url=http://www.google.com/
to
     UrlAction Url="javascript:__doPostBack('MyEventTarget',{ItemId});"

Here are the steps:



1. Install WSPBuilder


2. To start, go ahead and create a new WSPBuilder project called “LaunchDocItemCustEvent”.















and add a Blank Feature to it named “WriteTextFile”.


















 Construct the elements.xml file (I removed the '<' and '/>' characters in this post) :
?xml version="1.0" encoding="utf-8" ?

Elements xmlns="http://schemas.microsoft.com/sharepoint/"
CustomAction
Id="WriteDocId"
Title="Write Doc ID to Text File"
Location="EditControlBlock"
Description="Write Doc ID to Text File"
RegistrationType="List"
RegistrationId="101"
ShowInLists="TRUE"
UrlAction Url="http://www.google.com"/
CustomAction
Elements


Build the project.



Enable Output Window.

Build WSP


 
 





View results in Output Window. Ensure there are no errors.



















Deploy the solution






















Remember that your solution will deploy to the web url you specified in the project properties...go to Project --&gt; Properties --&gt; Debug.. enter the web url to which you want to deploy.

After deployment go to your SharePoint site, refresh and then navigate to a document library. Select a document item and click on the dropdown actions menu.
You will see the new custom action menu item.
When you click on the custom action you will see that you are redirected to Google.com

















OK, so we have a foundation in place and now we can start tweaking it to NOT redirect, but rather to execute our custom code.

Add new C# class your solution – name it LaunchDocWriter

In the new Class add references to:
Microsoft.SharePoint
System.Web

Add the following Code:
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;
using System.IO;


Inherit from SPLinkButton. The IMPORTANT thing is also that your class must be public.

public class LaunchDocWriter : SPLinkButton
{
} 

Overwrite the onload event:

protected override void OnLoad(EventArgs e)
{
this.EnsureChildControls();
base.OnLoad(e);


if (this.Page.Request["__EVENTTARGET"] == "MyEventTarget")
{
int itemId = Convert.ToInt32(this.Page.Request["__EVENTARGUMENT"]);


System.IO.TextWriter mywriterFired = new StreamWriter(@"C:\zzz_CodeBehindFileItemMenu.txt", true);


mywriterFired.WriteLine("Event Fired at:" + DateTime.Now.ToLongTimeString() + ": Item ID:" + itemId.ToString());


mywriterFired.Close();
}
}


Now we need to somehow instruct SharePoint to NOT redirect to a url, but to rather execute the new code.

In Elements.xml change (I left out the '&lt;' and '/&gt;' characters for this post to work, but you should include them in your code):
UrlAction Url=http://www.google.com/
to
UrlAction Url="javascript:__doPostBack('MyEventTarget',{ItemId});"

?xml version="1.0" encoding="utf-8" ?
Elements xmlns="http://schemas.microsoft.com/sharepoint/"
CustomAction
Id="WriteDocId"
Title="Write Doc ID to Text File"
Location="EditControlBlock"
Description="Write Doc ID to Text File"
RegistrationType="List"
RegistrationId="101"
ShowInLists="TRUE"
UrlAction Url="javascript:__doPostBack('MyEventTarget',{ItemId});"


CustomAction
CustomAction Id="UserInterfaceCustomActions.SiteActionsToolbar"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="MY SITE ACTIONS BUTTON"
ControlAssembly=""
ControlClass="LaunchDocItemCustEvent.LaunchDocWriter"
CustomAction
Elements

Rebuild your project.

Add

ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"
To
CustomAction Id="UserInterfaceCustomActions.SiteActionsToolbar"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="MY SITE ACTIONS BUTTON"
ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"
ControlClass="LaunchDocItemCustEvent.LaunchDocWriter"
/CustomAction
/Elements

Right click on your project and select "Build WSP"
Right click on your project and select "Deploy WSP"


If you did not get any errors you can refresh your SharePoint site.
Attach your project to all w3wp processes and add a breakpoint.
you will now see that your code execute when the user click on the menu item.

Enjoy !















23 comments:

Laura R said...

Wow. Thank you!! This is exactly what I wanted to do on my site. Thank you so much for the detailed instructions. This really helped me out. Most of the examples I've found for custom actions in the ECB have been for URLAction to pages.

Mike said...

I think there is a mistake in the last part of the elements.xml file. The id of the "siteactions" action should be the same as the eventname of the javascript, in this case "MyEventTarget".

-------------------------

So the last part should read:
CustomAction Id="MyEventTarget"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="MY SITE ACTIONS BUTTON"
ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"
ControlClass="LaunchDocItemCustEvent.LaunchDocWriter"
/CustomAction
/Elements

-------------------------

After that it worked for me. Many thanks for the tutorial!

langdall said...

The code gets executed again if the user hit f5 right after clicking on the new ECB menu item. It seems that event arguments aren't reset on postbacks.

Bob Peterson said...

It does not look correct to perform the button action in OnLoad when normally the click event is when an action should be done. OnLoad is triggered when the class is called in order to build the button HTML, not when a button click event has occurred. What am I missing here?

Unknown said...

Hi, I'm trying to implement this example, but I have an exception, when I deploy the final project appear this message: Inner exception(1): El archivo de soluci¢n ubicado en "LaunchDocItemCustEvent.wsp" no parece ser una actualizaci¢n v lida para la soluci¢n "launchdocitemcustevent.wsp".Ambas soluciones deben tener los mismos tipos de recurso (de  mbito global o de aplicaci¢n Web).

Anonymous said...

hi i try to implement this code but i got this error in deploy process:Inner exception(1): The solution file located at "LaunchDocItemCustEvent.wsp" does not appear to be a valid upgrade for solution "LaunchDocItemCustEvent.wsp".The two solutions must have the same resource types (global or Web-application scoped).
Do You have Any idea about this exception
Thanks in Advance

Unknown said...

Hello thanks for you post really it's very helpful for my but how to send two parameters ItemID and ListID
Thanks,

Frodo82 said...
This comment has been removed by the author.
Frodo82 said...

hello, would you know how to have the server code return javascript to the current page? For instance i click on the action button which does the java postback, then look up the secret name from my assemby, then send back a message box saying "Hello:"+secretName... any tip to get that figured out faster? or how to do it? Just need the data back to be used with the javascript

Anonymous said...

Hi Fodo82,

Did u get your code executed? I followed all the steps mentioned above but some how I am not able to debug my custom page. Can you Please guide on this.

Thanks,
Ashish Chotalia

AshishChotalia said...

Hi,

I have followed each step mentioned above. I have successfully place menu item in ECB. Now I want to execute some code before final redirection.

I didn't get any error while configuring above steps. I tried to debug my custom page, but somehow it's not executing my page. I guess I am missing some thing.

Please help on this.

Thanks,
Ashish Chotalia

Johan Olivier said...

Hi Ashish Chotalia,
Have you declared the LaunchDocWriter class which inherits from SPLinkButton as public?
eg.
public class LaunchDocWriter : SPLinkButton
{
} 

I had the same problem before and found my mistake was that my class was NOT public. After I changed it to public it worked well.

Regards
Johan

John Deo said...

Not working for me. I attach w3wp process. code is not running in debug.
I did exactly you wrote except I did not do last part(SiteAction) because I do not understand why SiteActions is involved here...when we are talking about EditControlBlock Menu.

CustomAction
CustomAction Id="UserInterfaceCustomActions.SiteActionsToolbar"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="MY SITE ACTIONS BUTTON"
ControlAssembly=""
ControlClass="LaunchDocItemCustEvent.LaunchDocWriter"
CustomAction
Elements

Rebuild your project.

Add

ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"
To
CustomAction Id="UserInterfaceCustomActions.SiteActionsToolbar"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="MY SITE ACTIONS BUTTON"
ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"
ControlClass="LaunchDocItemCustEvent.LaunchDocWriter"
/CustomAction
/Elements

PLEASE HELP!!!

Phil Hayton said...

Hi Guys

did anyone get this working? I followed this tutorial word for word and nope it's not working. I can attach to the process but the Vis Studio is not catching the event so therefore I guess it's not firing.

I'm using VS2010 on SharePoint 2010 but I'm hoping that this should not make a difference, any guidance would be appreciated

PhilH

Shafaqat Ali said...

Hi

I want to add ECB menu to a list through code not from elements.xml file, is iot possible?

Anonymous said...

Hi,

Did anyone get this working in Sharepoint 2010 and Visual Studio 2010 environment.I followed the article but it did not work for me.

Thanks,

Anonymous said...

Hi,

nice BUT:
wehen I Add

ControlAssembly="LaunchDocItemCustEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63316a326efb84ec"

The Menu item will never be shown.

When I remove ControlAssembly=".." the menu item will be shown..

strange. I really need the ControlAssembly-attribute.

Has anybody an idea?

THANKS

Anonymous said...

Thanks, great article!

Here you find another sample to add a custom action to a ribbon bar. The sample adds a "Export to PDF" button to export SharePoint list data into a PDF document using a templating system:
http://www.parago.de/2011/04/how-to-export-sharepoint-task-list-data-to-pdf-using-a-templating-system/

Anonymous said...

HI..Thank you for the post, But i have problem with this when i click on the item added in context menu which have _dopostback function, then this custom action removed from the context menu,
note: my business required me to be on the same page that contain the custom action, any solution PLease.

Imran said...

Hi,
This post looks nice. I have two document libraries i want to check from which library code is going to execute and also item link. How can i get doc library name and SPlistItem object in code.
...
Thanks
Imran

Erasmus Humphrey said...

SharePoint 2010 provides several javascript methods to open an url in a modal dialog. One of them is OpenPopUpPageWithTitle method defined in core.js.

Rumana Haaris said...

Hi,
I have a C# code(console application) that calculates the total duration of Employee from the list in SharePoint 2010. I have used LINQ, and its working fine. What i have to do now is, Add a button or something, and on click of that it should run my c# code.
Any HELP would be greatly appreciated.
Thank You.

Dinesh Talekar said...

Hey Hello please give the similar sample also for creating the custom ribbon button

Post a Comment