Solved

Need help with this code...

Posted on 2006-11-17
3
708 Views
Last Modified: 2008-01-16
I have found an article (http://www.devarticles.com/c/a/C-Sharp/Printing-Using-C-sharp/) which develops a "print engine"... I like the theory, but after copying the code, it doesn't seem to work (only prints or previews the header and footer, and the print dialog appears for each line/object to be printed)... I would be willing to double the points (max is 500, so I would submit another question for an additional 500 (for a total of 1000) for the help).  The code is as follows:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //-----------------------------------    class PrintEngine    -----------------------------------
    public class PrintEngine : PrintDocument
    {
        // members...
        private ArrayList _printObjects = new ArrayList();
        public Font PrintFont = new Font("Arial", 10);
        public Brush PrintBrush = Brushes.Black;
        public PrintElement Header;
        public PrintElement Footer;
        private ArrayList _printElements;
        private int _printIndex = 0;
        private int _pageNum = 0;

        public PrintEngine()
        {
            // create the header...
            Header = new PrintElement(null);
            Header.AddText("Report");
            Header.AddText("Page: [pagenum]");
            Header.AddHorizontalRule();
            Header.AddBlankLine();

            // create the footer...
            Footer = new PrintElement(null);
            Footer.AddBlankLine();
            Footer.AddHorizontalRule();
            Footer.AddText("Confidential");
        }

        // AddPrintObject - add a print object the document...
        public void AddPrintObject(IPrintable printObject)
        {
            _printObjects.Add(printObject);
        }

        // OnBeginPrint - called when printing starts
        protected override void OnBeginPrint(PrintEventArgs e)
        {
            // reset...
            _printElements = new ArrayList();
            _pageNum = 0;
            _printIndex = 0;

            // go through the objects in the list and create print elements for each one...
            foreach (IPrintable printObject in _printObjects)
            {
                // create an element...
                PrintElement element = new PrintElement(printObject);
                _printElements.Add(element);

                // tell it to print...
                element.Print();
            }
        }


        // OnPrintPage - called when printing needs to be done...
        protected override void OnPrintPage(PrintPageEventArgs e)
        {

            _pageNum++;  // adjust the page number...

            // now, render the header element...
            float headerHeight = Header.CalculateHeight(this, e.Graphics);
            Header.Draw(this, e.MarginBounds.Top, e.Graphics, e.MarginBounds);
           
            // also, we need to calculate the footer height...
            float footerHeight = Footer.CalculateHeight(this, e.Graphics);
            Footer.Draw(this, e.MarginBounds.Bottom - footerHeight, e.Graphics, e.MarginBounds);
           
            // now we know the header and footer, we can adjust the page bounds...
            Rectangle pageBounds = new Rectangle(e.MarginBounds.Left,(int)(e.MarginBounds.Top + headerHeight), e.MarginBounds.Width,
                  (int)(e.MarginBounds.Height - footerHeight - headerHeight));
            float yPos = pageBounds.Top;
           
            // ok, now we need to loop through the elements...
            bool morePages = false;
            int elementsOnPage = 0;
            while (_printIndex < _printElements.Count)
            {
                // get the element...
                PrintElement element = (PrintElement)_printElements[_printIndex];
                // how tall is the primitive?
                float height = element.CalculateHeight(this, e.Graphics);

                // will it fit on the page?
                if (yPos + height > pageBounds.Bottom)
                {
                    // we don't want to do this if we're the first thing on the page...
                    if (elementsOnPage != 0)
                    {
                        morePages = true;
                        break;
                    }
                }
                // now draw the element...
                element.Draw(this, yPos, e.Graphics, pageBounds);

                // move the ypos...
                yPos += height;

                // next...
                _printIndex++;
                elementsOnPage++;
            }
            // do we have more pages?
            e.HasMorePages = morePages;
        }


        // ReplaceTokens - take a string and remove any tokens replacing them with values...
        public String ReplaceTokens(String buf)
        {
            // replace...
            buf = buf.Replace("[pagenum]", _pageNum.ToString());

            // return...
            return buf;
        }


        // ShowPreview - show a print preview...
        public void ShowPreview()
        {
            // now, show the print dialog...
            PrintPreviewDialog dialog = new PrintPreviewDialog();
            dialog.Document = this;

            // show the dialog...
            dialog.ShowDialog();
        }

    }  //  end class PrintEngine


    //-----------------------------    class Customer    -------------------------------------
    public interface IPrintable
    {
        // Print
        void Print(PrintElement element);
    }


    //--------------------------------    class PrintPrimitiveRule    ---------------------------------
    public interface IPrintPrimitive
    {
        // CalculateHeight - work out how tall the primitive is...
        float CalculateHeight(PrintEngine engine, Graphics graphics);

        // Print - tell the primitive to physically draw itself...
        void Draw(PrintEngine engine, float yPos, Graphics graphics, Rectangle elementBounds);
    }

    public class PrintPrimitiveRule : IPrintPrimitive
    {
        // CalculateHeight - work out how tall the primitive is...
        public float CalculateHeight(PrintEngine engine, Graphics graphics)
        {
            // we're always five units tall...
            return 5;
        }

        // Print - draw the rule...
        public void Draw(PrintEngine engine, float yPos, Graphics graphics, Rectangle elementBounds)
        {
            // draw a line...
            Pen pen = new Pen(engine.PrintBrush, 1);
            graphics.DrawLine(pen, elementBounds.Left, yPos + 2,
                          elementBounds.Right, yPos + 2);
        }
    }


    //--------------------------    class PrintPrimitiveText    ---------------------------------------
    public class PrintPrimitiveText : IPrintPrimitive
    {
        // members...
        public String Text;

        public PrintPrimitiveText(String buf)
        {
            Text = buf;
        }
        // CalculateHeight - work out how tall the primitive is...
        public float CalculateHeight(PrintEngine engine, Graphics graphics)
        {
            // return the height...
            return engine.PrintFont.GetHeight(graphics);
        }
        // Print - draw the text...
        public void Draw(PrintEngine engine, float yPos, Graphics graphics, Rectangle elementBounds)
        {
            // draw it...
            graphics.DrawString(engine.ReplaceTokens(Text), engine.PrintFont,
            engine.PrintBrush, elementBounds.Left, yPos, new StringFormat());
        }
    }


    //------------------------------    class PrintElement    ---------------------------------------------
    public class PrintElement
    {
        // members...
        private ArrayList _printPrimitives = new ArrayList();
        private IPrintable _printObject;

        public PrintElement(IPrintable printObject)  //  constructor
        {
            _printObject = printObject;
        }

        public void Print()
        {
            // now, show the print dialog...
            PrintDialog dialog = new PrintDialog();
            //   dialog.Document = this;

            // show the dialog...
            dialog.ShowDialog();
        }

        // AddText - add text to the element...
        public void AddText(String buf)
        {
            // add the text...
            AddPrimitive(new PrintPrimitiveText(buf));
        }

        // AddPrimitive - add a primitive to the list...
        public void AddPrimitive(IPrintPrimitive primitive)
        {
            // add it...
            _printPrimitives.Add(primitive);
        }

        // AddData - add data to the element...
        public void AddData(String dataName, String dataValue)
        {
            // add this data to the collection...
            AddText(dataName + ": " + dataValue);
        }

        // AddHorizontalRule - add a rule to the element...
        public void AddHorizontalRule()
        {
            // add a rule object...
            AddPrimitive(new PrintPrimitiveRule());
        }

        // AddBlankLine - add a blank line...
        public void AddBlankLine()
        {
            // add a blank line...
            AddText("");
        }

        // AddHeader - add a header...
        public void AddHeader(String buf)
        {
            AddText(buf);
            AddHorizontalRule();
        }

        public float CalculateHeight(PrintEngine engine, Graphics graphics)
        {
            // loop through the print height...
            float height = 0;
            foreach (IPrintPrimitive primitive in _printPrimitives)
            {
                // get the height...
                height += primitive.CalculateHeight(engine, graphics);
            }

            // return the height...
            return height;
        }

        // Draw - draw the element on a graphics object...
        public void Draw(PrintEngine engine, float yPos, Graphics graphics, Rectangle pageBounds)
        {
            // where...
            float height = CalculateHeight(engine, graphics);
            Rectangle elementBounds = new Rectangle(pageBounds.Left, (int)yPos, pageBounds.Right - pageBounds.Left, (int)height);

            // now, tell the primitives to print themselves...
            foreach (IPrintPrimitive primitive in _printPrimitives)
            {
                // render it...
                primitive.Draw(engine, yPos, graphics, elementBounds);

                // move to the next line...
                yPos += primitive.CalculateHeight(engine, graphics);
            }
        }
    }  //  end class


    public class ListContents : IPrintable
    {
        // members...
        public String bookNumber;
        public String title;
        public String ISBN;
        public String location;
        public String price;
        public String status;

        // Print...
        public void Print(PrintElement element)
        {
            // tell the engine to draw a header...
            element.AddHeader("Contents of List");

            // now, draw the data...
            element.AddData("Book Nbr", bookNumber);
            element.AddData("Title", title);
            element.AddData("ISBN", ISBN);
            element.AddData("Location", location);
            element.AddData("Price", price);
            element.AddData("Status", status);

            // finally, add a blank line...
            element.AddBlankLine();
        }
    }
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
and the calling code is as follows:


    public class ListContents : IPrintable
    {
        // members...
        public String bookNumber;
        public String title;
        public String ISBN;
        public String location;
        public String price;
        public String status;

        // Print...
        public void Print(PrintElement element)
        {
            // tell the engine to draw a header...
            element.AddHeader("Contents of List");

            // now, draw the data...
            element.AddData("Book Nbr", bookNumber);
            element.AddData("Title", title);
            element.AddData("ISBN", ISBN);
            element.AddData("Location", location);
            element.AddData("Price", price);
            element.AddData("Status", status);

            // finally, add a blank line...
            element.AddBlankLine();
        }
    }

            PrintEngine _engine = new PrintEngine();

            SqlCommand cmd = new SqlCommand(inclusiveSearchString);
            cmd.Connection = bookConn;
            SqlDataReader rdr = cmd.ExecuteReader();

            while (rdr.Read())
            {
                ListContents lc = new ListContents();
               
                lc.bookNumber = (string)rdr["BookNbr"];
                lc.title = (string)rdr["Title"];
                lc.ISBN = (string)rdr["ISBN"];
                lc.location = (string)rdr["Locn"];
                lc.price = rdr["Price"].ToString();
                lc.status = (string)rdr["Stat"];
                _engine.AddPrintObject(lc);  //  add item to the list to print

            }

            _engine.ShowPreview();

        }
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0
Comment
Question by:rmmarsh
  • 2
3 Comments
 
LVL 15

Accepted Solution

by:
ozymandias earned 500 total points
ID: 17969052
>>after copying the code, it doesn't seem to work
You seem to have a got the code from that articel all mixed up.

>>print dialog appears for each line/object to be printed
That's becauase in the PrintElement class you have a Print method which calls a PrintDialog and shows it.
Then in the PrintEngine Class in OnBeginPrint you call that method for every PrintElement in the document in a loop...why ?

foreach (IPrintable printObject in _printObjects)
{
    // create an element...
    PrintElement element = new PrintElement(printObject);
    _printElements.Add(element);

    // tell it to print...
    element.Print();      <---- what are you doing here ?
}

>>only prints or previews the header and footer
That is because you have no Draw method in your PrintElement so it has no way of rendering itself onto the PrintDoument's graphics space.

You need to read the article thoroughly so that you understand what each piece of code is actually doing then you will be able to assemble the code correctly from the article.
0
 

Author Comment

by:rmmarsh
ID: 17969557
Well, I think I would rather had you do what you did (made me read the article and re-copy the code) than fix it yourself... I learned more... and did find one error which I was able to fix myself... one is never too old to learn new things...

Thank you so much for your advice and help... it works like a champ...
0
 
LVL 15

Expert Comment

by:ozymandias
ID: 17970824
Thanks.
Well done for taking the longer, harder route.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This video discusses moving either the default database or any database to a new volume.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now