简体   繁体   English

如何在执行打印预览时阻止出现“打印进度”对话框

[英]How can I prevent the Print Progress dialog appearing when performing a print preview

In my C# application, I'm attempting to generate a print preview without the progress dialog appearing on screen. 在我的C#应用​​程序中,我正在尝试生成打印预览而屏幕上没有显示进度对话框。

I believe you can use PrintDocument.PrintController to prevent this when printing for real (ie not a print preview), however it doesn't seem to work when performing a print preview. 我相信你可以使用PrintDocument.PrintController来打印真实的(即不是打印预览),但是在执行打印预览时它似乎不起作用。

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? 建议好吗?

This works for me: 这对我有用:

Set the printcontroller of your document to a StandardPrintController . 将文档的printcontroller设置为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));
        }
    }

Just to confirm the answer from Pooven. 只是为了确认Pooven的答案。 I had the same problem and tried to solve, the solution from Stefan also did not worked from me. 我有同样的问题并试图解决,Stefan的解决方案也没有对我有用。 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. 如果需要隐藏状态对话框,请寻找除PrintPreviewControl之外的其他解决方案。 Here is the source code of the PrintPreviewControl. 这是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);
        }
    }

Source http://reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/WinForms/Managed/System/WinForms/Printing/PrintPreviewControl@cs/1305376/PrintPreviewControl@cs 来源http://reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/WinForms/Managed/System/WinForms/Printing/PrintPreviewControl@cs / 1305376 / PrintPreviewControl @ CS

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 (ie 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. 不幸的是,我过于专注于尝试让打印预览对话按照我的意愿行事,而不是考虑更大的问题。

I think I did it. 我想我做到了。 Use this class instead of PrintPreviewControl: 使用此类而不是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());
        }
    }
}

您可能会对PreviewPrintController而不是StandardPrintController 感到满意

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. 似乎PrintPreviewControl使用的PrintPreviewDialog将替换PrintDocumentPrintController ,以便它在预览渲染过程中使用PrintControllerWithStatusDialog Once the Print operation is done, the PrintController is restored to its previous value. Print操作完成后, PrintController将恢复为其先前的值。 It seems that it would not be possible to customize the PrintPreviewControl to use any other PrintController . 似乎无法自定义PrintPreviewControl以使用任何其他PrintController

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. 解决方法是使用EnumChildWindows API查找窗口的句柄,如果找到,请使用带有SW_HIDE标志的ShowWindow API来隐藏窗口。

Here are an example for using FindWindow if you know the title of the window: 以下是使用FindWindow的示例,如果您知道窗口的标题:

#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); 

}

A solution that works for me is to use Harmony (v1.2) and patch the ComputePreview function of the PrintPreviewControl mentioned above: 对我有用的解决方案是使用Harmony (v1.2)并修补上面提到的PrintPreviewControlComputePreview函数:

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: 要应用修补程序,您需要在应用程序启动时包含以下2行:

var harmony = Harmony.HarmonyInstance.Create("Application.Namespace.Reversed");
harmony.PatchAll(Assembly.GetExecutingAssembly());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM