Reputation:
In my C# application, I'm attempting to generate a print preview without the progress dialog appearing on screen.
I believe you can use PrintDocument.PrintController to prevent this when printing for real (i.e. not a print preview), however it doesn't seem to work when performing a print preview.
My code is as follows:
public FrmDeliveryNotePrintPreview(DeliveryNote deliveryNote)
{
InitializeComponent();
this.Text = "Delivery Note #" + deliveryNote.Id.ToString();
// The print preview window should occupy about 90% of the
// total screen height
int height = (int) (Screen.PrimaryScreen.Bounds.Height * 0.9);
// Making an assumption that we are printing to A4 landscape,
// then adjust the width to give the correct height:width ratio
// for A4 landscape.
int width = (int) (height / 1.415);
// Set the bounds of this form. The PrintPreviewControl is
// docked, so it should just do the right thing
this.SetBounds(0, 0, width, height);
PrinterSettings printerSettings = new PrinterSettings();
PrintDeliveryNotes pdn = new PrintDeliveryNotes(
new DeliveryNote[] { deliveryNote },
printerSettings);
PrintDocument printDocument = pdn.PrintDocument;
printDocument.PrintController = new PreviewPrintController();
ppcDeliveryNote.Document = printDocument;
}
The print preview works exactly as I want, apart from the fact that the print preview progress dialog is displayed.
Suggestions please?
Upvotes: 7
Views: 13488
Reputation: 975
A solution that works for me is to use Harmony (v1.2) and patch the ComputePreview
function of the PrintPreviewControl
mentioned above:
The patch class looks like this
[Harmony.HarmonyPatch(typeof(System.Windows.Forms.PrintPreviewControl))]
[Harmony.HarmonyPatch("ComputePreview")]
class PrintPreviewControlPatch
{
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var cis = new List<CodeInstruction>(instructions);
// the codes 26 to 28 deal with creating the
// progress reporting preview generator that
// we don't want. We replace them with No-Operation
// code instructions.
cis[26] = new CodeInstruction(OpCodes.Nop);
cis[27] = new CodeInstruction(OpCodes.Nop);
cis[28] = new CodeInstruction(OpCodes.Nop);
return cis;
}
}
To apply the patch you need to include the following 2 lines in the startup of your application:
var harmony = Harmony.HarmonyInstance.Create("Application.Namespace.Reversed");
harmony.PatchAll(Assembly.GetExecutingAssembly());
Upvotes: 1
Reputation: 41
I think I did it. Use this class instead of PrintPreviewControl:
public class PrintPreviewControlSilent : PrintPreviewControl
{
public new PrintDocument Document
{
get { return base.Document; }
set
{
base.Document = value;
PreviewPrintController ppc = new PreviewPrintController();
Document.PrintController = ppc;
Document.Print();
FieldInfo fi = typeof(PrintPreviewControl).GetField("pageInfo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
fi.SetValue(this, ppc.GetPreviewPageInfo());
}
}
}
Upvotes: 4
Reputation: 3131
Just to confirm the answer from Pooven. I had the same problem and tried to solve, the solution from Stefan also did not worked from me. Then I finally looked in the source code and find out that it is hard coded so it cannot be changed. If you need to hide the status dialog, then seek for another solution than PrintPreviewControl. Here is the source code of the PrintPreviewControl.
private void ComputePreview() {
int oldStart = StartPage;
if (document == null)
pageInfo = new PreviewPageInfo[0];
else {
IntSecurity.SafePrinting.Demand();
PrintController oldController = document.PrintController;
// --> HERE they have hardcoded it! Why they do this!
PreviewPrintController previewController = new PreviewPrintController();
previewController.UseAntiAlias = UseAntiAlias;
document.PrintController = new PrintControllerWithStatusDialog(previewController,
SR.GetString(SR.PrintControllerWithStatusDialog_DialogTitlePreview));
// Want to make sure we've reverted any security asserts before we call Print -- that calls into user code
document.Print();
pageInfo = previewController.GetPreviewPageInfo();
Debug.Assert(pageInfo != null, "ReviewPrintController did not give us preview info");
// --> and then swap the old one
document.PrintController = oldController;
}
if (oldStart != StartPage) {
OnStartPageChanged(EventArgs.Empty);
}
}
Upvotes: 3
Reputation: 1764
It seems that the PrintPreviewControl
used by PrintPreviewDialog
will replace the PrintController
of the PrintDocument
so that it uses a PrintControllerWithStatusDialog
during the preview rendering process. Once the Print
operation is done, the PrintController
is restored to its previous value. It seems that it would not be possible to customize the PrintPreviewControl
to use any other PrintController
.
Upvotes: 0
Reputation:
I hate to answer my own question, but the solution was staring me in the face.
As I've already coded the ability to print a delivery note, my next step was to provide an on screen copy (i.e. no intention of printing a hard copy). The print preview dialog seemed like an easy way out.
In the end, I just created a custom form and painted directly on to it with no print preview control in sight.
Unfortunately, I got too focused on trying to get the print preview dialogue to behave as I wanted, rather than looking at the bigger problem.
Upvotes: 2
Reputation: 5884
This works for me:
Set the printcontroller of your document to a StandardPrintController
.
static class Program
{
static void Main()
{
PrintDocument doc = new PrintDocument();
doc.PrintController = new StandardPrintController();
doc.PrintPage += new PrintPageEventHandler(doc_PrintPage);
doc.Print();
}
static void doc_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.DrawString("xxx", Control.DefaultFont, Brushes.Black, new PointF(e.PageBounds.Width / 2, e.PageBounds.Height / 2));
}
}
Upvotes: 6
Reputation: 11509
A workaround would be to use the EnumChildWindows API to find the handle to the window, and If found, use the ShowWindow API with the SW_HIDE flag to hide the window.
Here are an example for using FindWindow if you know the title of the window:
#region Constants
private const int SW_HIDE = 0;
private const int SW_SHOWNORMAL = 1;
private const int SW_SHOW = 5;
#endregion Constants
#region APIs
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool EnableWindow(IntPtr hwnd, bool enabled);
#endregion APIs
public static void ShowProgress()
{
IntPtr h = FindWindow(null, "titleofprogresswindow");
ShowWindow(h, SW_SHOW);
EnableWindow(h, true);
}
public static void HideProgress()
{
IntPtr h = FindWindow(null, "titleofprogresswindow");
ShowWindow(h, SW_HIDE);
EnableWindow(h, false);
}
Upvotes: 0
Reputation: 5884
You may have some luck with PreviewPrintController instead of StandardPrintController.
Upvotes: 0