From: Zach on
Say I have PrintDocument pd = new PrintDocument();
Say I have a file c:\trialk.txt
How do I associate the two in order to privide input for ptinting?

Thanks,
Zach
From: Peter Duniho on
Zach wrote:
> Say I have PrintDocument pd = new PrintDocument();
> Say I have a file c:\trialk.txt
> How do I associate the two in order to privide input for ptinting?

What kind of association are you looking for?

If you want to print the text found in the file, you need to do that
yourself. Use the File class, or FileStream, or StreamReader, or
whatever to read the text from the file. Once you have a string or
strings from the file representing the text found in the file, then you
need to handle the Print event for the document and draw the text to the
page using the Graphics.DrawString() method or similar.

Pete
From: Zach on
"Peter Duniho" <NpOeStPeAdM(a)NnOwSlPiAnMk.com> wrote in message
news:bNydnSYxqcio_InRnZ2dnUVZ_q2dnZ2d(a)posted.palinacquisition...
> Zach wrote:
>> Say I have PrintDocument pd = new PrintDocument();
>> Say I have a file c:\trialk.txt
>> How do I associate the two in order to privide input for ptinting?
>
> What kind of association are you looking for?
>
> If you want to print the text found in the file, you need to do that
> yourself. Use the File class, or FileStream, or StreamReader, or whatever
> to read the text from the file. Once you have a string or strings from
> the file representing the text found in the file, then you need to handle
> the Print event for the document and draw the text to the page using the
> Graphics.DrawString() method or similar.
>
> Pete

Pete, could you pls look through the code below for me. It works
but that might not mean that it is ok.

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;

namespace InfraStructure
{
public class Print:Form
{
Font printFont;
StreamReader streamToPrint;
public Print(out bool result)
{
result = execute();
}
bool execute()
{
// select file
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Open a file";
ofd.InitialDirectory = "c:\\";
ofd.Filter = "txt files (*.txt)|*.txt";
if (DialogResult.OK == ofd.ShowDialog(this))
{
streamToPrint = new StreamReader(ofd.FileName);
}
else return false;

// font dialog
FontDialog font = new FontDialog();
if (DialogResult.OK == font.ShowDialog(this))
{
printFont = font.Font;
}
else return false;

//setting margins
PageSetupDialog setup = new PageSetupDialog();
PrintDocument document = new PrintDocument();
setup.Document = document;
setup.ShowDialog();

//select printer
PrintDialog select_printer = new PrintDialog();
select_printer.Document = document;
if (select_printer.ShowDialog() == DialogResult.OK)
{
try
{
document.PrintPage += new
PrintPageEventHandler(document_PrintPage);
document.Print();
streamToPrint.Close();
}
catch
{
return false;
}
}
else return false;

return true;
}

void document_PrintPage(object sender, PrintPageEventArgs ev)
{
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = ev.MarginBounds.Left;
float topMargin = ev.MarginBounds.Top;
string line = null;
linesPerPage = ev.MarginBounds.Height /
printFont.GetHeight(ev.Graphics);
while (count < linesPerPage && ((line =
streamToPrint.ReadLine()) != null))
{
yPos = topMargin + (count *
printFont.GetHeight(ev.Graphics));
ev.Graphics.DrawString(line, printFont, Brushes.Black,
leftMargin, yPos, new StringFormat());
count++;
}
if (line != null)
ev.HasMorePages = true;
else
ev.HasMorePages = false;
}
}
}

From: Peter Duniho on
Zach wrote:
> Pete, could you pls look through the code below for me. It works
> but that might not mean that it is ok.

Well, after a quick glance, I only see one real problem in terms of
obtaining exactly the output you expect, and that one being relatively
minor. That is, it appears to me that the code will potentially print a
blank page at the end. If the number of lines of text in the file is
exactly a multiple of the lines you can print on a page, then your code
will incorrectly report it has additional text to print, when in fact
there's none, causing one last blank page to be printed.

In general, my approach is to create a "print status" class that
persists the state of printing between pages. This would allow you to
pre-fetch a line of text even if you've reached the end of the page, so
that you can detect the end of the stream even in that case. The class
would then contain that line of text that was read, so that it's not
lost before you continue on to the next page.

Such a class could also store pagination information, such as text
height and the font, along with the input stream, etc. (lines per page
may still need to be recalculated, if you are using per-page print
settings, but otherwise that could be cached as well).

You also have several places in your code where you present a dialog and
then return a failure if the user cancels the dialog. Not a problem per
se, but my preference, rather than code that looks like this (as yours
does):

if (dialog.ShowDialog() == DialogResult.OK)
{
// do something
}
else
{
return false;
}

to instead just write it like this:

if (dialog.ShowDialog() != DialogResult.OK)
{
return false;
}

// do something

That is, just make the failure case return, and the success case be the
main flow through the method. IMHO this makes the method more readable.

A somewhat more significant problem is that you are failing to dispose a
number of disposable objects. Most never get disposed at all (dialogs,
and your font), but even the StreamReader is disposed only on success.

You should use "using" statements liberally to address this problem.

Finally, you should not be catching all exceptions around your call to
Print(). You should limit your "catch" clause to only those exceptions
that are expected and don't represent a terminal failure. Catching any
and all exceptions and just ignoring them can lead to very
hard-to-reproduce problems and subtle data corruption bugs.

This sort of problem is very rare, but when it happens it's very hard to
figure out if the code is simply silently catching all exceptions, even
those that were not anticipated at the time the code was written. It's
much better to just write the code more robustly in the first place.

Pete
From: Zach on
"Peter Duniho" <NpOeStPeAdM(a)NnOwSlPiAnMk.com> wrote in message
news:maadnQA5To3cFonRnZ2dnUVZ_rOdnZ2d(a)posted.palinacquisition...
> Zach wrote:
>> Pete, could you pls look through the code below for me. It works
>> but that might not mean that it is ok.
>
> Well, after a quick glance, I only see one real problem in terms of
> obtaining exactly the output you expect, and that one being relatively
> minor. That is, it appears to me that the code will potentially print a
> blank page at the end. If the number of lines of text in the file is
> exactly a multiple of the lines you can print on a page, then your code
> will incorrectly report it has additional text to print, when in fact
> there's none, causing one last blank page to be printed.
>
> In general, my approach is to create a "print status" class that persists
> the state of printing between pages. This would allow you to pre-fetch a
> line of text even if you've reached the end of the page, so that you can
> detect the end of the stream even in that case. The class would then
> contain that line of text that was read, so that it's not lost before you
> continue on to the next page.
>
> Such a class could also store pagination information, such as text height
> and the font, along with the input stream, etc. (lines per page may still
> need to be recalculated, if you are using per-page print settings, but
> otherwise that could be cached as well).
>
> You also have several places in your code where you present a dialog and
> then return a failure if the user cancels the dialog. Not a problem per
> se, but my preference, rather than code that looks like this (as yours
> does):
>
> if (dialog.ShowDialog() == DialogResult.OK)
> {
> // do something
> }
> else
> {
> return false;
> }
>
> to instead just write it like this:
>
> if (dialog.ShowDialog() != DialogResult.OK)
> {
> return false;
> }
>
> // do something
>
> That is, just make the failure case return, and the success case be the
> main flow through the method. IMHO this makes the method more readable.
>
> A somewhat more significant problem is that you are failing to dispose a
> number of disposable objects. Most never get disposed at all (dialogs,
> and your font), but even the StreamReader is disposed only on success.
>
> You should use "using" statements liberally to address this problem.
>
> Finally, you should not be catching all exceptions around your call to
> Print(). You should limit your "catch" clause to only those exceptions
> that are expected and don't represent a terminal failure. Catching any
> and all exceptions and just ignoring them can lead to very
> hard-to-reproduce problems and subtle data corruption bugs.
>
> This sort of problem is very rare, but when it happens it's very hard to
> figure out if the code is simply silently catching all exceptions, even
> those that were not anticipated at the time the code was written. It's
> much better to just write the code more robustly in the first place.
>
> Pete
-------------------------------------------------------------------------------
Hi Pete,

Thank you very much. I think I can make changes to allow for your comment,
however, I might find your "print status" suggestion a difficult one to
realize. I might like to get back on that one, after trying myself first,
if I may.

Many thanks,
Zach.