Как предотвратить появление диалогового окна «Ход выполнения печати» при предварительном просмотре печати

В моем приложении C # я пытаюсь создать предварительный просмотр печати без появления на экране диалогового окна выполнения.

Я считаю, что вы можете использовать PrintDocument.PrintController, чтобы предотвратить это при реальной печати (т.е. не при предварительном просмотре), однако, похоже, это не работает при выполнении предварительного просмотра.

Мой код выглядит следующим образом:

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;
}

Предварительный просмотр печати работает именно так, как я хочу, за исключением того факта, что отображается диалоговое окно выполнения предварительного просмотра.

Предложения, пожалуйста?


person Bryan    schedule 31.08.2009    source источник
comment
PrintDeliveryNotes - это класс, который печатает массив накладных. Однако в этом случае я не вызываю метод Print (), вместо этого я просто извлекаю свойство PrintDocument и передаю его в свой PrintPreviewControl в настраиваемой форме.   -  person Bryan    schedule 31.08.2009


Ответы (8)


Это работает для меня:

Установите для контроллера печати вашего документа значение 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));
        }
    }
person Matt Jacobsen    schedule 01.09.2009
comment
У меня это сработало, хотя я не делаю предварительный просмотр. См. Здесь примечания о различных доступных контроллерах печати: msdn. microsoft.com/en-us/library/. PrintController по умолчанию является PrintControllerWithStatusDialog. - person AceJordin; 17.11.2011

Просто чтобы подтвердить ответ от Pooven. У меня была такая же проблема и я пытался ее решить, решение от Стефана у меня тоже не сработало. Затем я, наконец, просмотрел исходный код и обнаружил, что он жестко запрограммирован, поэтому его нельзя изменить. Если вам нужно скрыть диалоговое окно состояния, ищите другое решение, кроме 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);
        }
    }

Источник http://reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/WinForms/Managed/System/WinForms/Печать/PrintPreviewControl@cs/1305376/PrintPreviewControl@cs

person darpet    schedule 17.10.2014
comment
Поскольку Winforms теперь имеет открытый исходный код, можно извлечь код PrintPreviewControl и его зависимости, чтобы изменить его контроллер печати. - person Xam; 22.07.2020

Думаю, у меня получилось. Используйте этот класс вместо 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());
        }
    }
}
person Leszek Masłowski    schedule 16.12.2016

Ненавижу отвечать на свой вопрос, но решение смотрело мне прямо в глаза.

Поскольку я уже закодировал возможность распечатать накладную, моим следующим шагом было предоставить копию на экране (т.е. не было намерения печатать бумажную копию). Диалог предварительного просмотра печати казался простым выходом.

В конце концов, я просто создал настраиваемую форму и рисовал прямо на ней, не видя никаких элементов управления предварительным просмотром печати.

К сожалению, я слишком сосредоточился на том, чтобы заставить диалог предварительного просмотра печати вести себя так, как я хотел, вместо того, чтобы смотреть на более серьезную проблему.

person Bryan    schedule 11.10.2009

Возможно, вам повезет с PreviewPrintController вместо StandardPrintController.

person Matt Jacobsen    schedule 31.08.2009
comment
Да, однако я уже пробовал это, и он по-прежнему отображает диалог о ходе выполнения. - person Bryan; 31.08.2009
comment
Я обновил образец кода, включив в него весь класс в его нынешнем виде. - person Bryan; 31.08.2009

Решение, которое мне подходит, - использовать Harmony (v1.2) и исправить ComputePreview функцию PrintPreviewControl упоминалось выше:

Класс патча выглядит так

[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;
    }
}

Чтобы применить патч, вам необходимо включить следующие 2 строки в автозагрузку вашего приложения:

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

Обходной путь - использовать EnumChildWindows API для поиска дескриптора окна и, если он найден, использовать ShowWindow API с флагом SW_HIDE, чтобы скрыть окно.

Вот пример использования 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); 

}
person Stefan    schedule 31.08.2009

Кажется, что PrintPreviewControl, используемый PrintPreviewDialog, заменит PrintController PrintDocument, так что он использует PrintControllerWithStatusDialog во время процесса рендеринга предварительного просмотра. По завершении операции Print PrintController восстанавливается до своего предыдущего значения. Похоже, что было бы невозможно настроить PrintPreviewControl для использования любого другого PrintController.

person Pooven    schedule 24.05.2012