Resolved How to pass extra parameter to PRintPageEventHandler

Jfisher387

Member
Joined
Dec 14, 2022
Messages
21
Programming Experience
Beginner
I am trying to print a page for each item within my BindingList.

I'm all but there. but struggling to work out how to pass the item from the list without getting an error.
Below is the code I am currently at.
My error is on line 15
i get "There is no argument given that corresponds to the required parameter 'ev' of 'JB_Helper.pd_PrintPage(object, PrintPageEventArgs, JB_Helper.JobData)'


Loop for item to print:
private void btn_Print_Click(object sender, EventArgs e)
        {
            //Adds data from each row into a list, then apply that list to a print function
            foreach ( JobData item in jobs)
            {
                if (PrinterSettings.InstalledPrinters.Count >= 1)
                {
                    if (printersList.SelectedItem != null)
                    {
                        PrintDocument pd = new PrintDocument();

                        //pd.PrinterSettings.PrinterName = "Zebra ZP450";
                        pd.PrinterSettings.PrinterName = printersList.SelectedItem.ToString();

                        pd.PrintPage += new PrintPageEventHandler(pd_PrintPage(item));

                        pd.Print();
                    }
                }
                else
                {
                    MessageBox.Show("Printer not found!");
                }
            }

            //finally clear out the DGV and inputs if needed,await for next label to be created
            label_DGV.Rows.Clear();
            label_DGV.Refresh();
        }
        public void pd_PrintPage(object sender,PrintPageEventArgs ev, JobData job)
        {
            StringFormat sf = new StringFormat();
            sf.LineAlignment = StringAlignment.Near;
            sf.Alignment = StringAlignment.Near;

            Rectangle rect1 = new Rectangle();
            rect1.Height = 100;
            rect1.X = 100;
            rect1.Y = 100;

            Rectangle rect2 = new Rectangle();
            rect2.Width = 200;
            rect2.Height = 100;
            rect2.X = 100;
            rect2.Y = 150;

            Rectangle rect3 = new Rectangle();
            rect3.Width = 200;
            rect3.Height = 100;
            rect3.X = 100;
            rect3.Y = 200;

            //Create a font Arial with size 16
            Font font = new Font("Arial", 14);

            //Create a solid brush with black color
            SolidBrush brush = new SolidBrush(Color.Black);

            //Get the Graphics object
            Graphics g = ev.Graphics;

                g.DrawString("Part #: " + Convert.ToString(job.PartNumber), font, brush, rect1, sf);

                g.DrawString("QTY: " + Convert.ToString(job.OrderQty), font, brush, rect2, sf);

                g.DrawString("Desc./RAL: " + job.ExtDesc, font, brush, rect3, sf);

        }
 
You don't. You pass around information the same your button click got its extra data -- via class variables.

I don't know why you are starting a new print document for each JobData and only printing about 3 lines of text per page, but if your on a mission to kill trees, or the person who wrote the specs for your application is on a mission to kill trees, that's a different issue.

Assuming that you want to continue on that mission, and you want to make minimal code changes, you would create another class that has the print page event handler and the reference to the job data. Something like:
C#:
record class JobDataPage(JobData Job)
{
   public void PrintPage(object sender, PrintPageEventArgs ev)
    {
        :
        g.DrawString("Part #: " + Convert.ToString(Job.PartNumber), font, brush, rect1, sf);
        g.DrawString("QTY: " + Convert.ToString(Job.OrderQty), font, brush, rect2, sf);
        g.DrawString("Desc./RAL: " + Job.ExtDesc, font, brush, rect3, sf);
    }
}

And then you would go and instantiate that class and use the event handler from that instance. So lines 15 would be replaced by something like:
C#:
var jobDataPage = new JobDataPage(item);
pd.PrintPage += new PrintPageEventHandler(jobDataPage.PrintPage);

(Actually, there maybe an even less code change way to do things by using lambdas to define the print page event handler within the loop, but you need to be careful about lambda variable captures.)

Personally, though I would go for bigger changes and replace the record class above that knows how to print itself and you would just call a Print() method on it. Within that method, it would instantiate the print document, hook up the local print page event handler, and then proceed to print. Also, I would add code to dispose off the fonts and brushes created.
 
You don't. You pass around information the same your button click got its extra data -- via class variables.

I don't know why you are starting a new print document for each JobData and only printing about 3 lines of text per page, but if your on a mission to kill trees, or the person who wrote the specs for your application is on a mission to kill trees, that's a different issue.

Assuming that you want to continue on that mission, and you want to make minimal code changes, you would create another class that has the print page event handler and the reference to the job data. Something like:
C#:
record class JobDataPage(JobData Job)
{
   public void PrintPage(object sender, PrintPageEventArgs ev)
    {
        :
        g.DrawString("Part #: " + Convert.ToString(Job.PartNumber), font, brush, rect1, sf);
        g.DrawString("QTY: " + Convert.ToString(Job.OrderQty), font, brush, rect2, sf);
        g.DrawString("Desc./RAL: " + Job.ExtDesc, font, brush, rect3, sf);
    }
}

And then you would go and instantiate that class and use the event handler from that instance. So lines 15 would be replaced by something like:
C#:
var jobDataPage = new JobDataPage(item);
pd.PrintPage += new PrintPageEventHandler(jobDataPage.PrintPage);

(Actually, there maybe an even less code change way to do things by using lambdas to define the print page event handler within the loop, but you need to be careful about lambda variable captures.)

Personally, though I would go for bigger changes and replace the record class above that knows how to print itself and you would just call a Print() method on it. Within that method, it would instantiate the print document, hook up the local print page event handler, and then proceed to print. Also, I would add code to dispose off the fonts and brushes created.

Thanks for the reply,

This will be for label printing, I'm hoping that when I swap to an actual label printer that it will pretty much be plug and play, move the graphics to fit and be done.

I ended up figuring it out but left the post to see better options.

I ended up with the following code.
C#:
 private void btn_Print_Click(object sender, EventArgs e)
        {
            //Adds data from each row into a list, then apply that list to a print function
            foreach (JobData item in jobs)
            {
                if (PrinterSettings.InstalledPrinters.Count >= 1)
                {
                    if (printersList.SelectedItem != null)
                    {
                        PrintDocument pd = new PrintDocument();

                        //pd.PrinterSettings.PrinterName = "Zebra ZP450";
                        pd.PrinterSettings.PrinterName = printersList.SelectedItem.ToString();
                        pd.PrintPage += (sender1, ev) => pd_PrintPage(sender1, ev, item);
                        pd.Print();
                    }
                }
                else
                {
                    MessageBox.Show("Printer not found!");
                }
            }

            //finally clear out the DGV and inputs if needed,await for next label to be created
            label_DGV.Rows.Clear();
            label_DGV.Refresh();
        }

C#:
 public void pd_PrintPage(object sender, PrintPageEventArgs ev, JobData job)
        {
            StringFormat sf = new StringFormat();
            //sf.LineAlignment = StringAlignment.Near;
            //sf.Alignment = StringAlignment.Near;
            Rectangle rect4 = new Rectangle();
            rect4.X = 20;
            rect4.Y = 10;

            Rectangle rect1 = new Rectangle();
            rect1.X = 20;
            rect1.Y = 25;

            Rectangle rect2 = new Rectangle();
            rect2.Width = 200;
            rect2.X = 20;
            rect2.Y = 40;

            Rectangle rect3 = new Rectangle();
            rect3.Width = 200;
            rect3.X = 20;
            rect3.Y = 55;

            //Create a font Arial with size 16 
            Font font = new Font("Arial", 8);

            //Create a solid brush with black color 
            SolidBrush brush = new SolidBrush(Color.Black);

            //Get the Graphics object 
            Graphics g = ev.Graphics;

            g.DrawString("Part #: " + Convert.ToString(job.PartNumber), font, brush, rect1, sf);

            g.DrawString("QTY: " + Convert.ToString(job.OrderQty), font, brush, rect2, sf);

            g.DrawString("Desc./RAL: " + job.ExtDesc, font, brush, rect3, sf);

            g.DrawString("Job #: " + Convert.ToString(job.JobNumber), font, brush, rect4, sf);

        }
 
Back
Top Bottom