Печать и вывод PDF в Windows-бизнес-приложениях — выбор между System.Drawing.Printing, WPF и библиотеками отчётов
· Го Комура · CSharp, .NET, WinForms, WPF, Печать, PDF, Отчёты, Разработка Windows, Техническая консультация
Печать в Windows-бизнес-приложении не заканчивается фразой «нарисуем что-нибудь PrintDocument-ом». Не работают переносы страниц, смещаются поля, preview не совпадает с реальным выводом, между приложением и нужным PDF появляется диалог печати — обычно такие проблемы начинаются с реализации без понимания механизма печати.
Здесь систематизированы четыре подхода: System.Drawing.Printing в WinForms, FlowDocument/FixedDocument в WPF, библиотеки генерации PDF и отчёты через Excel/Word. Главный вопрос — как выбирать их по требованиям.
1. Итог сначала
- Для простых списков или продолжения существующих WinForms-активов достаточно
PrintDocument. Перенос страниц устроен как повторение событияPrintPage, покаHasMorePagesне станетfalse; если забыть это, страницы после второй не выйдут. 12 - DPI печати — не DPI экрана.
PageSettings.PrinterResolutionописывает разрешение принтера, а поля состоят изPageSettings.HardMarginX/HardMarginY— физически непечатаемой зоны принтера — иMargins— логических полей приложения. Простое повторное использование экранных координат сдвигает layout из-за разницы DPI и координатных систем. 345 - В WPF стандартный путь печати Windows разделён на GDI и XPS. WPF-приложение изначально использует XPS-путь; при отправке принтеру без XPSDrv вывод автоматически преобразуется в GDI. 67
- Документы WPF имеют разную философию:
FlowDocument— для потока,FixedDocument— для фиксированного layout.FlowDocumentставит читаемость выше и перераскладывается по размеру окна и разрешению, аFixedDocumentставит выше точность на устройствах отображения и печати. 89 - В WPF бумага и лоток задаются через
PrintDialogиPrintTicket/PrintQueue. Перед печатью принято проверить и слить запрос с реальными возможностями принтера черезPrintQueue.MergeAndValidatePrintTicket. 1011 - Microsoft Print to PDF — драйвер печати, рассчитанный на интерактивную работу. Это поставляемая ОС очередь и пакет драйвера; как правило, при каждом запуске появляется выбор пути сохранения, поэтому для незаметного пакетного процесса он не подходит. 12
- Microsoft не поддерживает и не рекомендует Office COM automation на сервере или из службы. Office проектировался для интерактивного рабочего стола и профиля пользователя; в unattended/non-interactive окружении возможны нестабильность и deadlock. 13
- Службы Windows работают в session 0, поэтому не могут показывать диалог и не должны зависеть от принтера по умолчанию из пользовательской сессии. Учитывайте эту границу в самом начале при проектировании резидентной печати. 14
- Если в долгоживущем процессе не освобождать GDI-объекты (handles), можно достичь предела на процесс и получить падение. Предел конечен и настраивается через
GDIProcessHandleQuota; бесконечно выделять объекты нельзя. 15
Таблица выбора: требование × средство
| Требование | Подходящее средство | Причина |
|---|---|---|
| Напечатать несколько простых списков или накладных (WinForms) | PrintDocument |
Достаточно стандартных классов и можно использовать существующую GDI+-отрисовку |
| Отчёты с большим числом линий, разной бумагой, сложным layout | Библиотека отчётов или фиксированный layout на FixedDocument |
Самостоятельный расчёт координат, переносов и японской типографики дорог |
| Массовая пакетная печать без оператора | Программный PrintDocument.Print() / прямая отправка в XpsDocumentWriter |
Нужно закончить без диалогов и не зависеть от принтера по умолчанию |
| Нужен только PDF без печати | Прямо генерировать PDF библиотекой | Нет зависимости от диалога, принтера по умолчанию и состояния spooler |
| Нужен preview и важна внутренняя проверка | PrintPreviewDialog (WinForms), DocumentViewer (WPF) |
Можно использовать стандартный UI проверки перед печатью |
| Нужно использовать существующий шаблон Excel | Прямая генерация Open XML SDK или ограниченный COM automation | Активы переиспользуются, но COM не следует запускать в резидентной службе |
Далее разберём пункты подробнее.
2. Самое необходимое о печати в Windows
Архитектура печати Windows состоит из spooler и драйверов отдельных принтеров. Приложение вызывает независимые от устройства функции и может послать задачу самым разным выходам: лазерному принтеру, векторному plotter, растровому принтеру или факсу. 16
Есть два главных пути печати.
- GDI-путь. Когда печатает Win32 GDI-приложение, графический движок GDI кладёт команды рисования как EMF (enhanced metafile) в spooler либо вместе с драйвером сразу рендерит печатаемое изображение. По этому пути идут традиционные WinForms-приложения. 166
- XPS-путь. Это путь для драйверов на основе XPS (XML Paper Specification). WPF-приложения изначально используют его, отправляя в spooler XPS-документы. Если целевой принтер не имеет XPSDrv, данные автоматически преобразуются в GDI перед отправкой. 67
Почему экран и распечатка отличаются. Самая частая причина — путаница DPI. Экранный Graphics обычно работает около 96 DPI, а Graphics принтера — с разрешением PageSettings.PrinterResolution, часто около 600 DPI. 3 Если передать в печатный Graphics пиксельные координаты, рассчитанные для экрана, результат будет намного меньше — либо при другой настройке больше — ожидаемого. Для печати безопаснее строить координаты в hundredths of an inch или физических единицах (миллиметры/дюймы), не завися от разрешения Graphics.
Другая часто упускаемая вещь — физически непечатаемая зона принтера. Многие принтеры не могут печатать несколько миллиметров от края бумаги. Это ограничение доступно через PageSettings.HardMarginX/HardMarginY; документация описывает его как физические поля, установленные принтером. 4 Логические поля приложения — PageSettings.Margins (по умолчанию один дюйм со всех сторон); даже если поставить их в ноль, печатать внутри hard margin нельзя. 5 Многие дефекты «поле поставили нулевым, но край режется или всё смещается» происходят от игнорирования этих физических полей.
3. WinForms: практическое использование System.Drawing.Printing
Печать WinForms строится вокруг PrintDocument: создаётся документ, настраиваются PrinterSettings и DefaultPageSettings, в событии PrintPage выполняется рисование, а Print() запускает печать. 1
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
public sealed class ReportPrinter
{
// Данные для печати. Предполагается одна позиция документа в каждой строке.
private readonly IReadOnlyList<string> _lines;
private int _lineIndex;
public ReportPrinter(IReadOnlyList<string> lines) => _lines = lines;
public void Print(string printerName)
{
using var document = new PrintDocument();
document.DocumentName = "Детали заказа";
if (!string.IsNullOrEmpty(printerName))
{
document.PrinterSettings.PrinterName = printerName;
}
// При неизвестном имени принтера проверка вернет false (не подходит для обнаружения автономного режима).
if (!document.PrinterSettings.IsValid)
{
throw new InvalidOperationException(
$"Указанный принтер не найден: {printerName}");
}
_lineIndex = 0;
document.PrintPage += Document_PrintPage;
document.Print();
}
private void Document_PrintPage(object? sender, PrintPageEventArgs e)
{
// MarginBounds — доступная область рисования с учетом логических полей (Margins).
// PageBounds охватывает весь лист; содержимое может быть обрезано даже при рисовании внутри аппаратного поля.
using var font = new Font("Segoe UI", 10);
float lineHeight = font.GetHeight(e.Graphics);
float y = e.MarginBounds.Top;
while (_lineIndex < _lines.Count)
{
if (y + lineHeight > e.MarginBounds.Bottom)
{
// Эта страница завершена. Так как есть продолжение, переходим к следующей странице.
e.HasMorePages = true;
return;
}
e.Graphics.DrawString(_lines[_lineIndex], font, Brushes.Black,
e.MarginBounds.Left, y);
y += lineHeight;
_lineIndex++;
}
// Все строки нарисованы; это последняя страница.
e.HasMorePages = false;
}
}
Типичный случай ошибки «не печатается вторая страница» — забыть явно поставить HasMorePages в false (значение по умолчанию — false) либо ошибиться в условии и выйти, оставив его всегда false. Событие PrintPage повторяется, пока это свойство не станет false; перед установкой явно определяйте, остались ли строки для вывода. 12 Если по страницам различаются настройки бумаги или ориентации, используйте вместе с PrintPage событие QueryPageSettings.
Типичный случай «съехали поля» — построить координаты от e.Graphics.VisibleClipBounds или e.PageBounds, игнорируя MarginBounds (зона с логическими полями) и HardMarginX/HardMarginY (физическое ограничение). 4 В частности, у принтера разработки физическое поле может быть маленьким и скрыть проблему, а у модели заказчика быть больше, из-за чего обрезаются линии и поля. Проверка на нескольких моделях — этап, который легко пропустить.
Чтобы дать preview, присвойте тот же PrintDocument свойству Document у PrintPreviewDialog; логика PrintPage будет использоваться без изменений. 1 Если нужно менять вывод по разрешению принтера, получите варианты из PrinterSettings.PrinterResolutions и задайте их в PageSettings.PrinterResolution. 3
4. WPF: FlowDocument / FixedDocument и PrintDialog
В WPF выбор между FlowDocument и FixedDocument зависит от природы документа.
FlowDocument. Документ, который динамически перераскладывает содержимое по переменным выполнения, таким как размер окна или настройки шрифта, и ставит читаемость выше. Он имеет штатные возможности поиска, pagination и смены режима отображения. 8FixedDocument. WYSIWYG-документ, в котором приложение полностью контролирует layout и ставит выше точность на устройстве отображения и печати. Подходит, когда нужна высокая воспроизводимость. 9
Для внутреннего отчёта, где важна читаемость, берите FlowDocument; для накладной или этикетки, где положение линий и полей должно быть фиксировано до пикселя, — FixedDocument.
Базовая печать делается через System.Windows.Controls.PrintDialog, отдельный WPF-класс, не равный System.Windows.Forms.PrintDialog. 10
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
public static class FlowDocumentPrinter
{
public static void Print(FlowDocument document, string jobName)
{
var printDialog = new PrintDialog();
// Печатать только если пользователь нажал OK.
if (printDialog.ShowDialog() != true)
{
return;
}
// FlowDocument использует разные предпосылки для размера страницы при отображении и печати, поэтому
// размер страницы и поля печатаемого содержимого нужно привести к области печати принтера.
var paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
paginator.PageSize = new Size(
printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
printDialog.PrintDocument(paginator, jobName);
}
}
Для точного задания размера бумаги, лотка и двусторонней печати используйте PrintQueue и PrintTicket/PrintCapabilities. PrintTicket описывает инструкцию задания, PrintCapabilities — реально поддерживаемые функции принтера; принято слить и проверить запрошенные настройки с допустимыми значениями принтера через PrintQueue.MergeAndValidatePrintTicket. 711
using System.Linq;
using System.Printing;
public static class DuplexPrintTicketBuilder
{
public static PrintTicket BuildDuplexTicket(PrintQueue printQueue)
{
PrintCapabilities capabilities = printQueue.GetPrintCapabilities();
// Заранее проверить, поддерживает ли принтер двустороннюю печать (переплет по длинной стороне).
bool supportsDuplex = capabilities.DuplexingCapability
.Contains(Duplexing.TwoSidedLongEdge);
var requestedTicket = new PrintTicket();
if (supportsDuplex)
{
requestedTicket.Duplexing = Duplexing.TwoSidedLongEdge;
}
// Объединить со стандартным PrintTicket пользователя только запрос на двустороннюю печать.
// Неподдерживаемые элементы автоматически заменяются допустимыми значениями.
ValidationResult result = printQueue.MergeAndValidatePrintTicket(
printQueue.UserPrintTicket, requestedTicket);
return result.ValidatedPrintTicket;
}
}
Если отчёт с фиксированным layout строится как FixedDocument и отправляется прямо по XPS-пути, задание добавляется в PrintQueue методами Write/WriteAsync XpsDocumentWriter. Для принтера без XPSDrv внутри выполняется автоматическое преобразование в GDI, так что вызывающей стороне не нужно учитывать путь. 7
5. Варианты вывода PDF
Требование «нужно вывести PDF» меняет проектирование в зависимости от одного из трёх смыслов.
- Как продолжение печати достаточно, чтобы пользователь вручную выбрал сохранение PDF.
- Нужно генерировать PDF из приложения через диалог печати.
- Не печатать вообще, а массово создавать только PDF-файлы в unattended batch.
Microsoft Print to PDF подходит для случаев 1 и 2. Это функция, поставляемая с Windows 10: очередь печати и пакет драйвера, которую приложение видит как обычный принтер. 12 Но она предполагает интерактивное поведение с запросом имени файла назначения при каждой печати; официально контроль предоставлен лишь как управление этой очередью и пакетом драйвера. 12 Для случая 3, где путь фиксирован и PDF тихо массово выводятся, механизм не спроектирован. Здесь естественнее библиотека, генерирующая PDF напрямую без конвейера печати.
При выборе PDF-библиотеки до рекомендации конкретного продукта упорядочьте требования компании по следующим осям.
| Ось | Что проверить |
|---|---|
| Лицензия | OSS (MIT/Apache либо GPL/AGPL) или коммерческая. При внешнем распространении/продаже приложения проверить в первоисточниках — тексте лицензии и официальном сайте поставщика — что обязанность раскрыть код, условия перераспространения и коммерческое использование не противоречат своей модели |
| Японские шрифты | Встраивание subset японских шрифтов, возможность не получать mojibake на компьютере без шрифта, а при необходимости бизнеса — вертикальное письмо и варианты IVS |
| Возможности отчётов | Template-based определения, barcode/QR, электронная подпись, PDF/A для долгого хранения и простота переноса существующего бумажного layout |
| Зависимости и среда | Работа на сервере без GUI (Windows Server, containers), зависимости от native library и опыт работы в .NET Core/.NET вне Framework |
| Производительность | Использование памяти при batch generation многих страниц/задач и поведение при параллельном создании |
Условия лицензирования меняются по продукту и версии. Перед выбором всегда подтверждайте официальную документацию или сам текст лицензии. Здесь не рекомендуется конкретная библиотека или продукт — показаны только критерии сравнения.
6. Отчёты через Excel / Word
Если уже есть отчёт, управляемый шаблоном Excel, часто реалистичнее использовать этот актив, чем создавать всё с нуля. Есть два крупных способа.
- Генерировать или редактировать xlsx/docx напрямую через Open XML SDK и т. п. Исполняемый файл Excel/Word не запускается, ZIP + XML читается и пишется напрямую, поэтому подход стабилен на сервере. Он хорошо сочетается с сохранением линий и оформления шаблона при подстановке только значений; подробнее — в «Как строить вывод Excel-отчёта: COM/Open XML/templates».
- Управлять настоящим
Excel.Applicationчерез Excel COM Interop. Этот путь выбирают, когда требуется переиспользовать существующую книгу с macros или сложным recalculation, но распространена проблема, что EXCEL.EXE остаётся из-за неосвобождённых COM-references. Меры и критерии приведены в статье о сохранении EXCEL.EXE при работе с Excel из C#.
Важно, что Microsoft официально заявляет: Office automation на сервере или из Windows-службы не рекомендуется и не поддерживается. Office спроектирован под интерактивный desktop и профиль пользователя, поэтому в unattended/non-interactive окружении возможны нестабильность и deadlock. 13 Лицензии также обычно не предполагают предоставление клиентам функций Office автоматизацией на стороне сервера. 13
Поэтому при встраивании вывода отчётов в резидентную службу или batch job, даже если используется шаблон Excel, безопаснее не запускать Excel.exe в runtime через COM Interop, а перейти к прямой генерации файлов посредством Open XML SDK. Если COM Interop совершенно необходим, реалистично отделить его как резидентное приложение, а не службу, в интерактивной вошедшей пользовательской сессии.
7. Практические ловушки
Печать из Windows-службы и session 0
Запросы встроить печать в резидентную службу встречаются часто, но службы Windows выполняются в session 0. Начиная с Windows Vista session 0 зарезервирована для служб и процессов, не связанных с интерактивными пользователями, и отделена от пользовательской сессии. 14 Поэтому диалог, который показывает служба, пользователь не увидит, а код, ожидающий его ввода — например диалог печати, — выглядит зависшим. 14
Другой практический риск — видимость сетевых или назначенных отдельному пользователю принтеров. Сетевой принтер, подключённый пользователем, часто виден в его интерактивной сессии, но не обязательно в другом контексте, например в процессе службы session 0. Для резидентного процесса с печатью в начале проектирования подтвердите, какие принтеры видны какой учётной записи и сессии. Разделение сессий описано в «Как понимать isolation сессий Windows», а базовая реализация и эксплуатация служб — в «Как создавать и эксплуатировать службы Windows».
Когда принтера нет или он offline
Если задать несуществующее имя в PrinterSettings.PrinterName или запустить в окружении без default printer, попытка печати может привести к исключению или неудаче. Как минимум заранее проверяйте через PrinterSettings.IsValid и проектируйте повторные попытки и уведомление об ошибке. Когда сетевой принтер временно offline, job может остаться в spooler без реального вывода; не заканчивайте проверку на «отправить удалось», а при необходимости проверяйте состояние job.
Риск зависимости от default printer
Реализация, которая не задаёт PrinterSettings.PrinterName и всегда полагается на «принтер по умолчанию», со временем накапливает риск. Пользователь может его изменить, ноутбук может сменить default в другом месте, и важный документ уйдёт не туда. Для значимых бизнес-отчётов явно храните имя принтера назначения в конфигурации или экране настроек, чтобы не зависеть от смены default.
Утечка GDI handles при долгой работе
Если в коде печати не освобождать через using или Dispose() GDI/GDI+ ресурсы вроде Graphics, Font, Brush и Pen, после долгой работы исчерпываются handles GDI-объектов и вызовы рисования начинают отказывать. Handles имеют предел на процесс; это конечный ресурс, который через реестр GDIProcessHandleQuota можно настроить от 256 до 65 536. 15 Чем чаще печатает резидентное приложение, тем выше шанс, что такая утечка проявится только в production. Практика исследования и изоляции разобрана на примере в статье о падении промышленной камеры от утечки handles.
Связанные статьи
- Как строить вывод Excel-отчёта: COM/Open XML/templates
- Проблема, когда EXCEL.EXE остаётся при работе с Excel из C#: освобождение COM references и выбор замены
- Как создавать и эксплуатировать службы Windows: от Task Scheduler до превращения BackgroundService в службу
- Как понимать isolation сессий Windows: Session 0, RDP и одновременная работа нескольких пользователей
- Исследование длительных падений промышленной камеры: утечка handles
Связанные области консультаций
KomuraSoft LLC проводит технические консультации по проектированию функций печати и вывода отчётов в Windows-бизнес-приложениях, перестройке отчётов с использованием существующих Excel-активов и проектированию печати/вывода из резидентных служб.
Справочные ссылки
-
Microsoft Learn, PrintDocument Class. О роли
PrintDocument— задатьDocumentNameиPrinterSettings, начать печатьPrint()— и указании использовать namespaceSystem.Printingдля печати WPF. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, PrintPageEventArgs.HasMorePages Property. О значении по умолчанию
falseи повторенииPrintPage, пока свойство не станетfalse. ↩ ↩2 -
Microsoft Learn, PageSettings.PrinterResolution Property. О том, что разрешение печати страницы по умолчанию — разрешение принтера по умолчанию, и о получении вариантов из
PrinterSettings.PrinterResolutions. ↩ ↩2 ↩3 -
Microsoft Learn, PageSettings.HardMarginX Property. О том, что hard margin представляет физическое поле, установленное принтером. ↩ ↩2 ↩3
-
Microsoft Learn, PageSettings.Margins Property. О полях по умолчанию в один дюйм со всех сторон и расчёте печатаемой области с
BoundsвPrintPage. ↩ ↩2 -
Microsoft Learn, Windows Print Path Overview. О двух главных путях Windows: GDI для Win32-приложений и XPS для WPF либо XPS Print API. ↩ ↩2 ↩3
-
Microsoft Learn, Printing documents overview. О XPS-пути WPF, базовой печати
PrintDialog, расширенной печатиPrintTicket/PrintCapabilities/PrintQueue/XpsDocumentWriterи автоматическом преобразовании в GDI для принтеров без XPSDrv. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Flow Document Overview. О перераскладке
FlowDocumentпо переменным вроде размера окна и разрешения с приоритетом читаемости. ↩ ↩2 -
Microsoft Learn, FixedDocument Class. О том, что
FixedDocumentставит выше точное WYSIWYG-воспроизведение для дисплея и печати, в отличие отFlowDocument. ↩ ↩2 -
Microsoft Learn, PrintDialog Class. О том, что
System.Windows.Controls.PrintDialogстроитPrintTicketиPrintQueueна основе ввода пользователя и отличается отSystem.Windows.Forms.PrintDialog. ↩ ↩2 -
Microsoft Learn, How to: Validate and Merge PrintTickets. О проверке возможностей через
PrintQueue.GetPrintCapabilitiesи слиянии/проверке запроса сMergeAndValidatePrintTicket. ↩ ↩2 -
Microsoft Learn, RemoveMPDW. О Microsoft Print to PDF как установленной по умолчанию optional feature, настраиваемой/удаляемой как очередь печати и пакет драйвера. ↩ ↩2 ↩3
-
Microsoft Support, Considerations for server-side Automation of Office. О том, что Microsoft не рекомендует и не поддерживает автоматизацию Office из unattended/non-interactive приложений, включая ASP/ASP.NET/DCOM/NT services, и что Office предполагает интерактивный desktop и user profile. ↩ ↩2 ↩3
-
Microsoft Learn, Service Changes for Windows Vista - Session 0 Isolation. О том, что с Windows Vista session 0 зарезервирована для служб и приложений, не связанных с интерактивными пользователями, а службы не могут напрямую показывать диалоги. ↩ ↩2 ↩3
-
Microsoft Learn, GDI Objects. О том, что handles GDI-объектов имеют предел на процесс, а
GDIProcessHandleQuotaпозволяет менять его от 256 до 65 536. ↩ ↩2 -
Microsoft Learn, Introduction to printing. О составе архитектуры печати Windows из spooler и драйверов и о том, как команды рисования Win32 GDI отправляются в spooler как EMF. ↩ ↩2
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Не только appsettings.json — практическое руководство по управлению конфигурацией Windows-бизнес-приложений (настройки окружений, секреты и место записи)
Практический разбор управления конфигурацией Windows-бизнес-приложений: слои appsettings.json, выбор между IConfiguration и семейством IO...
Как точно найти причину «медленной работы» с PerfView и dotnet-trace — практическое введение в анализ производительности .NET
Когда бизнес-приложение «работает медленно», «загружает ЦП под завязку» или «иногда зависает», какой инструмент выбрать и на что смотреть...
Введение в журнал событий Windows и ETW — как использовать стандартные механизмы ОС для логов бизнес-приложения
Ваше Windows-бизнес-приложение опирается только на файловые логи? Журнал событий и ETW — это записи другого уровня, видимые операционному...
Google Ads для BtoB с небольшим бюджетом — как получить результат при нескольких десятках тысяч иен в месяц
Практическое руководство для BtoB-компаний, которые начинают Google Ads с бюджетом в несколько десятков тысяч иен в месяц. Разбираются ср...
Как сделать сайт заметным по запросам с названием района — практическое руководство по локальному SEO для малого и среднего бизнеса
Для компаний, которые не появляются по запросу «название района + отрасль», собран порядок исправлений для локального SEO: подготовка Goo...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Поток UI и таймеры
Поток UI WPF / WinForms, асинхронные операции, Dispatcher и проектирование таймеров.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Проектирование и реализация функций печати и вывода PDF в бизнес-приложениях относятся к консультациям по разработке Windows-приложений.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Что выбрать: PrintDocument или печать WPF?
- Если экран построен на WinForms, естественный выбор — PrintDocument; если на WPF — FlowDocument/FixedDocument. Не нужно смешивать технологии: практический критерий — framework экранов существующего приложения. Для нового WPF-проекта заранее решите, будет ли отчёт преимущественно поточным или с фиксированным layout, и выберите соответственно FlowDocument либо FixedDocument.
- Нужно ли покупать библиотеку отчётов?
- Если высока стоимость самостоятельного создания сложных отчётов с большим числом линий, несколькими размерами бумаги, встраиванием японских шрифтов или вертикальным письмом средствами GDI+/WPF, стоимость библиотеки отчётов часто оказывается ниже. Для простого списка A4 собственный PrintDocument или FixedDocument обычно достаточен. Безопаснее сначала оценить сложность требований.
- Можно ли генерировать только PDF и не пользоваться печатью?
- Да. PDF — лишь один из форматов вывода; прямая генерация библиотекой PDF, не зависящей от диалога печати и принтера по умолчанию, часто лучше подходит для пакетной обработки и автоматизации. Microsoft Print to PDF — драйвер для интерактивных операций и не годится для создания PDF без участия пользователя.
- Поддерживаются ли принтеры этикеток и чековые принтеры?
- Это возможно, но не всегда решается простым продолжением PrintDocument/FixedDocument. У многих принтеров этикеток есть собственный язык команд или SDK, и управление идёт не по стандартному пути печати Windows. Сначала выясните, работает ли целевая модель как обычный драйвер Windows или требует специального SDK.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.
Публичные ссылки