Saturday, January 06, 2007

How to add a "print list" option to the list actions menu


It's been a long time since I published a cute and useful code sample, so here we go!

The idea - add a "print list" button to the actions menu of a list, so that when a user click it he will be shown a print-friendly version of the list.



The print list menu item










The print view for an announcement list


Please remember that this is a code sample, and while it works, I can think of many ways to improve it. For example - the current code will always use the default view of the list for the printing, and I would like to improve it so that it shows a print view for the view the user was looking at.
Another example - the current code doesnt display the list title or any other details on the list, and that will be a useful (and easy) modification. I will leave it up to you to try and do it, and if you find yourself in trouble - comment and I will look into what you want to add.



Solution Architecture




The solution will be deployed as a wss feature, which allows us an easy way to add a menu item to the sharepoint menus. The feature will define that the item we want to add will be added to the actions menu of all lists, in a site collection. You can ofcourse change it so that it behaves differently and connects only to lists of a certain type if you so wish, or maybe move the menu item to a different place. I recommend reviewing the msdn article on the possible configurations.
The solution is based on 3 files:

  1. feature.xml
    Defines the feature, its scope and its title that you will see in the "site features" (or site collection features or farm features - depending on the scope)


  2. PrintList.xml
    Defines what action we want to add to what menu and what will happen when the user clicks the menu item. This is where you configure the text of the item, and the link to the page that will print the list. which just happens to be the last file:


  3. PrintList.aspx
    Contains the code that shows the list in a print-friendly view. This file should be deployed to the layouts folder and must be called with the site's context (more about that shortly).





To the Code!




note - when I talk about the "12 hive" I am referring to the folder C:\Program Files\Common Files\Microsoft Shared\web server extensions\12


Create the page that prints a list:



  1. Log on to the server, and open the template\layouts folder in the 12 hive.

  2. Create a new text file in the folder, and name it "PrintList.aspx"

  3. Open the empty file in your editor of choice (notepad is fine) and paste the following code into it:



    <%@ Page Language="C#" Inherits="System.Web.UI.Page" %>



    <%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"


    Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>


    <%@ Import Namespace="Microsoft.SharePoint" %>


    <html>


    <head>


    <title>SharePoint List Print</title>


    <link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/core.css" />



    <script type="text/javascript" language="javascript" src="/_layouts/1033/init.js"></script>



    <script type="text/javascript" language="javascript" src="/_layouts/1033/core.js"


    defer></script>



    <script type="text/javascript" language="javascript" src="/_layouts/1033/ie55up.js"></script>



    <script type="text/javascript" language="javascript" src="/_layouts/1033/search.js"


    defer></script>



    </head>


    <body>


    <%




    string listId = "";


    string referrer = "";


    //get the list id (guid in a string format) from the query string


    listId = Page.Request.QueryString["list"];


    //get the http referrer (for the back button\action)


    referrer = Page.Request.ServerVariables["http_referer"];


    //make sure the list parameter was passed


    if (listId == null)


    {


    //if a referrer url exists (since the page may have been opened from a direct link, this is not always the case) redirect the user back


    if (referrer != null && referrer.Trim().Length != 0)


    {


    Page.Response.Write("<p>The list ID parameter ('list') is missing from the address.<br>Please go to the list you want to print and try again.</p>");


    Page.Response.Write("<p><a href=\"" + referrer + "\" title=\"Go Back\">Click here to go back to the page you came from</p>");


    }


    else


    {


    Page.Response.Write("<p>The list ID parameter ('list') is missing from the address.<br>Please go to the list you want to print and try again.</p>");



    }


    }


    else


    {


    try


    {


    //load the web object for the site that the page is now in context of


    using (SPWeb web = SPControl.GetContextWeb(Context))


    {


    //load the list that was passed in the 'list' querystring parameter to the page


    SPList list = web.Lists[new Guid(listId)];


    //load the query of the default view. note - need to modify code in the future to enable multiple view printing


    SPQuery query = new SPQuery(list.DefaultView);


    //write the list to the page


    Page.Response.Write(list.RenderAsHtml(query));


    //add the print script


    %>



    <script type="text/javascript" language="javascript">


    window.print();


    </script>



    <%




    }



    }


    catch (Exception ex)


    {


    Page.Response.Write("<p>There was an error loading the list information:<br />");



    Page.Response.Write(ex.ToString());


    Page.Response.Write("</p>");


    }


    }





    %>


    </body>


    </html>









Install the feature


  1. Open the \TEMPLATE\FEATURES folder under the 12 hive

  2. Create a folder called PrintListMenuAction

  3. In that folder, create 2 text files, one called feature.xml and the second printlist.xml



  4. In your editor of choice (notepad is fine) open the feature.xml file and paste into it the following:





    <?xml version="1.0" encoding="utf-8" ?>


    <Feature Id="769826dd-9dd2-11db-96ca-005056c00008"


    Title="Print List"


    Description="This feature adds a print command in the Actions menu for Windows SharePoint Services lists."


    Version="1.0.0.0"


    Scope="Site"


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


    <ElementManifests>


    <ElementManifest Location="PrintList.xml" />


    </ElementManifests>


    </Feature>








  5. In your editor of choice open the printlist.xml and paste the following:


    <?xml version="1.0" encoding="utf-8" ?>


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


     


      <!-- Add the action to the List Toolbar Actions Menu Dropdown -->


      <CustomAction Id="SPSTIPS.PrintListActionsToolbar"


        RegistrationType="List"   


        GroupId="ActionsMenu"


        Location="Microsoft.SharePoint.StandardMenu"


        Sequence="1000"


        Title="Print List">


        <UrlAction Url="{SiteUrl}/_layouts/PrintList.aspx?list={ListId}"/>


      </CustomAction>


     


    </Elements>










Almost done - install the feature and test it!




To install the feature, open command line (start>run>cmd) and navigate to the bin folder in the 12 hive.

Once there, run the following command to install the feature:

stsadm -o installfeature -name PrintListMenuAction -force


After you ran that command successfuly, you can activate the feature in the site collection either using the user interface (site actions> site settings> site collection features):




or you can (more easily since you are already in the command line) just run the following command, entering the site path:



stsadm -o activatefeature -name PrintListMenuAction -url [your site url here] -force




That's it! if you now go to any list in that site, you should have the print menu action.
Please let me know if any of the steps doesnt work for you or if there is any problem with the pasted code (I am trying the SourceCodeToHTML addin for visual studio, and I am not sure what that will do to simple copy-paste actions on your side).


Update 19/1/2007 :
Some people have remarked that the printlist.aspx isnt working for them. I went over the code and couldnt find a problem with it (well, there are some improvments I can think of, but nothing to cause what they are describing). I suggest you try to troubleshoot it by:


  1. Make sure you copied all of the text in the code sample. Missing a line or even a character will cause what you are describing

  2. Try changing the trust level in the web.config file for the sharepoint application to "Full". This shouldnt be a requirement for this solution, but who knows...

  3. Try removing pieces of code to see what part causes the crash.

  4. Contact me. Write to my anti-spam email address with the subject "Problem with list printing" (any other subject and I will automatically delete the email). The address is (replace the '$' with '@'):
    "dontwantspamhere$gmail.com"
    (replace the '$' with '@')



Update 28/09/2007 :

I have noticed that the action only works from within a list view page, and not from a web part (a list view web part) that is displayed on a web part page, not from the list context. I have no idea how to solve it, so for now be aware that this will not work in web parts.

33 comments:

lmarrou said...

What about using a printlist.aspx using codebehind that would be installed into sharepoint and keeping the sharepoint layout?

S Jaiswal said...

Hi there,

Very informative post. I sometimes do presentations on SharePoint and was wondering if I could use your Print List example in my presentations and refer my audience to your website for further info.

Please let me know. Thanks again!

- Jaiswal

Anonymous said...

Ok, cool feature! I just cannot get it to work.

I believe the problem is with the PrintList.aspx file. When I select 'Print List', the URL (server)/_layouts/PrintList.aspx?list={GUID} opens. However, it just says 'Unknown Error'.

Any thoughts?

This is on WSS 3.0

Thanks

Matthias Glubrecht said...

Hi Ishai,
thank you for the helpful post.
I just noted one small detail in the code that I find is worth mentioning:
You write
using (SPWeb web = SPControl.GetContextWeb(Context))
{
...
},
thereby disposing the SPWeb object when your code block is exited. While this may not be problematic in this specific sample, you should generally not call Dispose() on the SPWeb object returned from the GetContextWeb() function, because this is an object which will be used in many places during one request and it will be disposed of by the Sharepoint infrastructure code after the request is completely handled.
See the complete technical article on this topic here: http://msdn2.microsoft.com/en-us/library/aa973248.aspx
Regards, Matthias

Anonymous said...

Very good feature indeed however i get the same "Unknown Error" when I select 'Print List' and the URL (server)/_layouts/PrintList.aspx?list={GUID} opens.

Anonymous said...

It is very simple actually to fix the unknown error problem (i posted the second comment about this). When you create the printlist.aspx Windows will create it as a txt file so the full name it's like this: printlist.aspx.txt Just remove the .txt extension and the print it will work. It's amazing!!!

Michael Bollhoefer said...

I ran into a similar issue and the problem was with the querystring. See my blog post on the subject at http://sharepointinsight.com/blog/Lists/Posts/Post.aspx?ID=32

Anonymous said...

Hit Control P and it will print -Nick Burns. IE7 prints better to.

chandru said...

Hi Ishai,

Really your post is very help ful,Thanks.

But, if i place the custom list as a web part in web page this feature is not working. Am facing the this error.

There was an error loading the list information:
System.FormatException: Expected hex 0x in '{0xdddddddd, etc}'. at System.Guid..ctor(String g) at ASP._layouts_printlist_aspx.__Render__control1(HtmlTextWriter __w, Control parameterContainer)

I believe the problem is with the Query string of listid.

Any thoughts on this?

Matthew said...

chandru

I have an easy work around for your problem

rather than going straight from your page to actions>print list, open the list from the heading link and run print list from there.

works like a charm

Anonymous said...

Thank you for this post!

Is there a way to get this to print the calendar view? It works great for the all events view (if its the default). But the default calendar view prints a blank page.

Stephen K said...

Regarding your update about the action not working when used in the listviewwebpart of a webpart page. This is because of a bug see http://chrissyblanco.blogspot.com/2007/12/bug-with-customaction-in-actions-menu.html.

For the solution visit http://stephenkaye.blogspot.com/2008/02/bug-with-customactions.html and download

Anonymous said...

Hi!

Create post! I tried it and it worked (after I changed the file extensions from txt to aspx $ xml!).

Is there a way to add an icon to the Print List action?

Thanks again!

MJ

Anonymous said...

Hello again...

MJ here. Actually, after some research, I have been able to add both an icon and a description.

Here is the code:

Description="Send this list to the printer"
ImageUrl="{SiteUrl}/_layouts/images/menureply.gif"

Hope this helps!

...MJ

Chris White said...

Has anyone found a way of using the sequence attribute of the customaction element to determine where abouts in the actions menu the new item appears ?

No matter what I set this value to it always appears as if the menu item is added to the bottom of the actions menu ?

Anonymous said...

Try setting the sequence to 1

sukiakisu said...

After I installed the feature I was unable to navigate to Site Features or Site COllection Features or Web Application Features. It was as if something disconnected upon install. Did anyone else have this problem? I'm new to the SharePoint dev world, and haven't installed any features before. Any explanation is welcome!

Gopinath said...

Nice article....

Moderator said...

Very nice example, thanks. I had a slightly different problem: I wanted to print all InfoPath forms in a document library. Required the same techniques, with some variations. Here's my VB code to show you how it works:

sample code

Anonymous said...

Has anyone tried Printing Services for SharePoint from www.sharepointprinting.com.

Rico said...

This worked like a charm, I used notepad as the editor, but had to go back and clean up the spaces that it applied from the paste and it would not show up in the features of SharePoint, but using the stsadm.exe dos prompt worked and now its cool. I want to know is there a way to make it a default font on Print.

bhargavi said...

Hi, thanks for the article, very useful indeed. But I have one concern, I need to open up a new window to display PrintList.aspx. I am calling it from the Display Form.This is the code i use - "UrlAction Url="javascript:void window.open('/_layouts/PrintList.aspx?itemID={ItemId}&listID={ListId}')"

Its works fine, but when the PrintList.aspx page opens, the parent page(DisplayForm.aspx) is getting refreshed, is there a postback happening. How can I prevent that?

Kent said...

Works like a charm. Thank you!

Anonymous said...

Amazing feature..thanks a lot!!!!

Anonymous said...

This is a very nice feature. The only step I did forget after the install and stsadm commands was the iisreset command to apply the feature set to the website. Thanks again.

Jon - Minneapolis

Anonymous said...

This was a great tip and it works fine. Is there a way to tell it which view to print? I have a grouped view but the print doesn't quite work, it only prints the group header names.

Ravi.Annam@indianriverschools.org

Anonymous said...

I got it working but my list has more than 100 records and when I try to print the list its only letting me print the first 100 records. Is there a way to print the whole list for 1000 records?

Thanks.

Anonymous said...

Hello All -

MJ, what file did you add the code for the icon and description?

Thanks,
Cis

Anonymous said...

ImageUrl="{SiteUrl}/_layouts/images/menureply.gif"

since the image is apparently in the '_layouts' folder, there's no need to prepend the SiteUrl. So

ImageUrl="/_layouts/images/menureply.gif" will do fine. Browsers now have to retrieve this image only once and canuse the cached version a lot more often.

Cheers,

Wes

Kalaravi said...

Thanks alot for this article.....its very useful....keep posting articles like this

Anonymous said...

I needed to print SharePoint calendar & I saw your blog. I wrote a similar feature that could print calendars too:
SPPrint

One point:
- To overcome the 100 items limit you should set an higher limit in the SPQuery.

FelipeLodi.Com said...

Thanks for this simple but incredible feature. It is working perfectly.

Cheers,

Lodi

Anonymous said...

Has anyone figured out how to get this to print grouped by views? I am trying to figure out a way to get the print to retrieve all the data and display it in expanded mode before printing.

Thank for your help!
Sincerely,
Tim