0

I made an invoice that has a listview on the bottom to list all of the line items. This can run over the one page mark so I overloaded the DocumentPaginator class to allow for me to print multiple pages. However, sometimes it cuts the page in the middle of a line of the listview. I found an article that uses a bitmap of the wpf control, then checks the color of pixels of a line to determine if there is whitespace or data (code below). When I make my control into a bitmap though, the spacing and line height is different than when I print the wpf control as an xps or to the printer. Any other ideas out there on how to intelligently break pages or get the bitmap to match the xps?

 private void GetGoodCut()
    {
        int goodCut = _lastCut; 
        int lastNumber = 0;
        int numberCount = 1;
        // At most, it will take 32 pixel lines to find a white space
        for (int i = 0; i < 32; i++)
        {
            int number = rowPixelWhiteCount(_bitmap, goodCut);
            goodCut--;

            if (number == lastNumber)
            {
                numberCount++;
                // White space count between LV lines is 12 
                if (numberCount == 12)
                {
                    lastNumber = i - 6;
                    break;
                }
            }
            else
            {
                // If we started inside a white space, can break if starting before/at middle of the white space
                if (numberCount > 5)
                {
                    lastNumber = i - 6;
                    break;
                }
                numberCount = 1;
            }

            lastNumber = number;
        }

        _lastCut -= lastNumber;
    }

 private int rowPixelWhiteCount(System.Drawing.Bitmap bmp, int row)
    {
        int colorCount = 0;
        System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
        int stride = bmpData.Stride;
        IntPtr firstPixelInImage = bmpData.Scan0;

        unsafe
        {
            byte* p = (byte*)(void*)firstPixelInImage;
            p += stride * row;  // find starting pixel of the specified row
            for (int column = 0; column < bmp.Width; column++)
            {
                // Printing in black/white, look for non-black pixels
                byte blue = p[0];
                byte red = p[1];
                byte green = p[3];
                if (blue > 0 && red > 0 && green > 0)
                    colorCount++;

                // go to next pixel
                p += 3;
            }
        }
        bmp.UnlockBits(bmpData);
        count.Add(colorCount);

        return colorCount;
    }
Todes3ngel
  • 308
  • 3
  • 10

1 Answers1

0

I believe that the secret to printing multiple pages from a WPF Application is to use multiple FixedDocument elements... you can also use your DocumentPaginator element in this process. As this is well documented online, I won't go over it all again here. Instead, please refer to the WPF Printing Part 2 – The Fixed Document page on the NBD Tech website for the full story.

As additional help, you can also refer to the Advanced WPF Part 2 of 5: Printing in Windows Presentation Foundation page on Abhishek Shukla's website.

Finally, if all else fails, you might be interested in using the code from the WPF Print Engine: Part I page on Code Project.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • The first two links didn't mention anything about page breaks. The last link gave me the idea to switch out my ListView out for a DataGrid , which doesn't look as good, but it does manage itself on page breaks. However, on a different form i'm printing, has a dynamic ListView on it that cannot be changed into a DataGrid . So still looking for an answer. – Todes3ngel Aug 18 '14 at 19:09