How to implement printing in ASP.Net MVC3

19,295

Solution 1

  • Define a print stylesheet for your page. You do this by using the @media print declaration.
  • What you can then do is wrap each partial view on the page that you are going to print in a div and apply the 'page-break-before: always' CSS attribute to it.

This will ensure that each partial view ends up on a different page. Call 'window.print()' on the page load and you're done!


Given the extensive questions posed in the comments for this answer, here is a more detailed description of what needs to be done:

Preparation

  • A stylesheet needs to be defined and applied to the page which defines what the page will look like when printed.
    • This can either be done by using a @media print { } declaration in an existing stylesheet, or by applying the media="print" attribute to the link tag in your page which includes the stylesheet. You appear to have done this correctly.
    • This stylesheet must include a page-break-before: always declaration for all elements before which you would like there to be a page break. You seem to have done this with inline styles. Personally I would have rather done this in the print stylesheet than as an inline style. This step is integral to you being able to print one item per page.

Printing

  • window.print() allows you as the page author to define when the page is printed. This does the same thing as CTRL + P or as clicking the print button, except you can do it from your JavaScript.
  • Ajax has nothing intrinsically to do with printing. Ajax is a means to asynchronously make HTTP calls from your page without changing or reloading it and updating your page as a result. If you wanted to dynamically populate your page with items to print based on user input, then you could very well do so with Ajax. If you merely want to print the page, then you don't need to use Ajax. the navigator.**

Two important points:

  • window.print() prints the page that is currently onscreen. If you want to print a different page, you need to load the other page in some way shape or form (perhaps through a popup) and call window.print() on that page.
  • The print stylesheet defines what the printed page will look like in contrast to the onscreen version. This means that you can have a page of items and lots of other stuff, and print only the items when the user clicks the print button. You would do this by setting the display: none property in your print stylesheet on all the elements that you do not want to appear on the printed page.

About PDFs:

I have nothing against exporting pages to PDF when necessary, but as you did not specifically ask about a PDF solution, I have given you the HTML+CSS solution to your question. PDFs also take a minute to generate and load. They are great, however, when your users will want to save copies of what they are printing. If this is the case for your site I strongly recommend that you consider such a solution.

Testing:

How do you test a print stylesheet? The easiest way is to simply click the print button in Chrome which will show you a lovely preview of what your site is going to look like when it is printed.

Final word:

For now, forget about window.print() and just focus on getting your page looking like it should by applying the appropriate CSS. Write your CSS, run your page, look at the output in Chrome, modify your print stylesheet as needed... Rinse and repeat. Only once you have the page appear exactly as you want it when clicking the print button should you then look at calling the print function automatically in your JavaScript.

Solution 2

How I do printing in MVC:

  1. Create a view with exactly what you want to print layed out how you want it to look
  2. Use the Rotativa library to turn your MVC View in a pdf document.

Simple as changing your Action to look like this

public ActionResult PrintInvoice(int invoiceId)
{
  return new ActionAsPdf(
                 "Invoice", 
                 new { invoiceId= invoiceId }) 
                 { FileName = "Invoice.pdf" };
}

I believe it will obey the css page-break, so if you need to only print one item per page you can use that markup to force items to new pages.

Solution 3

I will create a PDF to better control the layout of the page.

With jQuery I will get the selected items from the user than make an ajax call, or a simple POST, to an action method that accept a list of your items as parameter and then return a filestream containing your pdf.

There are a lot of libraries free and commercial to create a pdf both at runtime or at design time.

I personally use DevExpress and I'm happy with it.

As an opensource alternative you can consider PDFSharp

Share:
19,295
Naresh
Author by

Naresh

Updated on June 04, 2022

Comments

  • Naresh
    Naresh almost 2 years

    As part of my current task in a given list of items, user can select some of them and invoke 'Print' no the selected items.

    For each selected item we need to print the details. It is similar to printing invoices of selected items in a sales system.

    I have created a partial view to write each record details but I am not sure how to use it as per my requirement.

    Can I call jQuery print on document.ready to achieve my requirement?

    As @Levib suggested, calling partial view in my PrintView. And PrintView's document.reay function is calling window.print. But when I try to invoke 'Print', I can not see print dialogue.

    This is my view,

    @section Styles
    {
        <link rel="stylesheet" href="AdminStyle.css" type="text/css" media="all" />
        <link rel="stylesheet" href="AdminPrintOrder.css" type="text/css" media="print" />
    }
    
    @foreach (var item in Model)
    {
        <div id="content" style="page-break-before: always">
            @{Html.RenderPartial("_OrderDetailView", item);}
        </div>   
    }
    
    @section scripts
    {
        <script type="text/javascript">
            $(document).ready(function () {
                debugger;
                window.print();
            });
        </script>
    }
    

    And my print invoker view is

     function printInvoices(){
                $.ajax({
                    type: 'POST',
                    url: '/Batch/PrintInvoices',
                    data: '{ "allocationId" : "' + unSelected.toString() + '"}',
                    contentType: "application/json; charset=utf-8",
                    traditional: true,
                    success: printedView,
                    error: errorInSubscribing
                });
            }
    

    Do I need to handle ajax reposne to populate print dialogue.

     function printedView() {
                unSelected = [];
            }
    

    And controller action is

    [HttpPost]
            public ActionResult PrintInvoices(string allocationId)
            {
                var context = new BatchContext();
                var orderDetails =  context.GetOrderDetails(RetriveList(allocationId));
                return View(orderDetails);
            }
    
  • Levi Botelho
    Levi Botelho over 11 years
    Yup, or directly in your JS if the script is at the end of the page.
  • Naresh
    Naresh over 11 years
    So if I return this action on my print click, it will come up with a print dialogue. Plase corrent me if I am wrong.
  • Levi Botelho
    Levi Botelho over 11 years
    Absolutely! This calls the equivalent of CTRL+P.
  • Naresh
    Naresh over 11 years
    Levib, I ahve tried as you said. But I am not getting the print dialogue. I am using ajax post to call my controller which is returning view of print data. This print suppose to invoke.
  • Levi Botelho
    Levi Botelho over 11 years
    You aren't calling window.print() correctly. That is all you need to do--type window.print() into your preferred JS console on any site and you will see that it works. If you have layout problems then it is to do with the way you have structured your print stylesheet, but if you have problems calling the print dialog then your error is in your JS.
  • Malcolm O'Hare
    Malcolm O'Hare over 11 years
    By default this method prints the page header (page title) and footer (page address). If you don't want those and don't trust your user to configure their browser to not print them then you need to generate a PDF file
  • Naresh
    Naresh over 11 years
    @levib, is that I am not calling window.print() correctly or do I need to handle tha ajax response in parent page. As of now I am not handling the ajax response.
  • Levi Botelho
    Levi Botelho over 11 years
    @MalcolmOHare That is inncorrect. Window.print() examines the stylesheet defined for print media and prints the page as rendered through that stylesheet. It could indeed only print the h + f if your print stylesheet defined that but it is not the "default". Naresh, give me a couple hours I am going to amend my answer when I get the chance instead of responding in the comments.
  • Naresh
    Naresh over 11 years
    I have used PDF Sharp before. But the problem is we need to spend some more time to get the required output in PDF.
  • Naresh
    Naresh over 11 years
    @levib Thanks for your detailed response. But unfortunately I am not clear about how to load the second page and invoke print on that page. I tried of using iFrame and invoking print on it but didn't succeeded and also tried using div instead of iFrame. It really doesn't matter to me to go for ajax call or a normal invoking. Thanks for your help once again. I spent lot of time on this but not getting the result :(.
  • Levi Botelho
    Levi Botelho over 11 years
    @Naresh - I don't know how else I can explain this to you. This has nothing to do with Ajax and nothing at its heart to do with iframes. It is a very, very simple concept but I think that maybe your site is quite complicated and that complexity is getting in the way of you understanding it. The only thing I can recommend to you is this: Create a new HTML page. Put some content in it. A div or two and some text. Create two stylesheets--one for print media and one normal. On the page load call window.print. See what happens...
  • Levi Botelho
    Levi Botelho over 11 years
    ...see how you can use the CSS print sheet to make your printed page look however you'd like. Then read this post again and see how you can make it apply to your own site. If you still don't understand then you need to improve your basic comprehension of window.print() and CSS. If your problems are getting window.print() to work, then you might want to consider posting your JS in a separate question. If it is with how the printed page looks, then you might want to do the same but with your CSS. You'll get it, you just need to invest a bit more time and effort. Best of luck.