Jak wyświetlić okno dialogowe drukowania (WPF .NET)
Chcesz wydrukować z aplikacji? Możesz użyć PrintDialog klasy , aby otworzyć standardowe okno dialogowe drukowania systemu Microsoft Windows. Oto, jak to zrobić.
Uwaga
Kontrolka System.Windows.Controls.PrintDialog używana dla platformy WPF i omówiona w tym miejscu nie powinna być mylona ze składnikiem System.Windows.Forms.PrintDialog windows Forms.
Klasa PrintDialog zapewnia jedną kontrolkę do konfigurowania wydruku i przesyłania zadań drukowania. Kontrolka jest łatwa w użyciu i można utworzyć wystąpienie za pomocą znaczników XAML lub kodu. Poniższe przykłady tworzą i wyświetlają PrintDialog
wystąpienie przy użyciu kodu.
Możesz użyć okna dialogowego drukowania, aby skonfigurować opcje drukowania, takie jak:
- Drukuj tylko określony zakres stron.
- Wybierz z drukarek zainstalowanych na komputerze. Aby utworzyć te typy dokumentów, możesz użyć opcji Składnik zapisywania dokumentów XPS firmy Microsoft:
- XML Paper Specification (XPS)
- Specyfikacja open XML Paper Specification (OpenXPS)
Drukuj cały dokument
W tym przykładzie są wyświetlane wszystkie strony dokumentu XPS. Domyślnie kod będzie:
- Otwórz okno dialogowe drukowania z monitem użytkownika o wybranie drukarki i uruchomienie zadania drukowania.
- Utwórz wystąpienie XpsDocument obiektu z zawartością dokumentu XPS.
XpsDocument
Użyj obiektu , aby wygenerować DocumentPaginator obiekt, który zawiera wszystkie strony dokumentu XPS.- Wywołaj metodę PrintDocument , przekazując
DocumentPaginator
obiekt, aby wysłać wszystkie strony do określonej drukarki.
/// <summary>
/// Print all pages of an XPS document.
/// Optionally, hide the print dialog window.
/// </summary>
/// <param name="xpsFilePath">Path to source XPS file</param>
/// <param name="hidePrintDialog">Whether to hide the print dialog window (shown by default)</param>
/// <returns>Whether the document printed</returns>
public static bool PrintWholeDocument(string xpsFilePath, bool hidePrintDialog = false)
{
// Create the print dialog object and set options.
PrintDialog printDialog = new();
if (!hidePrintDialog)
{
// Display the dialog. This returns true if the user presses the Print button.
bool? isPrinted = printDialog.ShowDialog();
if (isPrinted != true)
return false;
}
// Print the whole document.
try
{
// Open the selected document.
XpsDocument xpsDocument = new(xpsFilePath, FileAccess.Read);
// Get a fixed document sequence for the selected document.
FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();
// Create a paginator for all pages in the selected document.
DocumentPaginator docPaginator = fixedDocSeq.DocumentPaginator;
// Print to a new file.
printDialog.PrintDocument(docPaginator, $"Printing {Path.GetFileName(xpsFilePath)}");
return true;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return false;
}
}
''' <summary>
''' Print all pages of an XPS document.
''' Optionally, print all pages without showing a print dialog window.
''' </summary>
''' <param name="xpsFilePath">Path to source XPS file</param>
''' <param name="hidePrintDialog">Whether to hide the print dialog window (shown by default)</param>
''' <returns>Whether the document printed</returns>
Public Shared Function PrintWholeDocument(xpsFilePath As String, Optional hidePrintDialog As Boolean = False) As Boolean
' Create the print dialog object and set options.
Dim printDialog As New PrintDialog
If Not hidePrintDialog Then
' Display the dialog. This returns true if the user presses the Print button.
Dim isPrinted As Boolean? = printDialog.ShowDialog()
If isPrinted <> True Then Return False
End If
' Print the whole document.
Try
' Open the selected document.
Dim xpsDocument As New XpsDocument(xpsFilePath, FileAccess.Read)
' Get a fixed document sequence for the selected document.
Dim fixedDocSeq As FixedDocumentSequence = xpsDocument.GetFixedDocumentSequence()
' Create a paginator for all pages in the selected document.
Dim docPaginator As DocumentPaginator = fixedDocSeq.DocumentPaginator
' Print to a new file.
printDialog.PrintDocument(docPaginator, $"Printing {Path.GetFileName(xpsFilePath)}")
Return True
Catch e As Exception
MessageBox.Show(e.Message)
Return False
End Try
End Function
Drukowanie zakresu stron
Czasami chcesz wydrukować tylko określony zakres stron w dokumencie XPS. W tym celu rozszerzymy klasę abstrakcyjną DocumentPaginator , aby dodać obsługę zakresów stron. Domyślnie kod będzie:
- Otwórz okno dialogowe drukowania z monitem użytkownika o wybranie drukarki, określenie zakresu stron i uruchomienie zadania drukowania.
- Utwórz wystąpienie XpsDocument obiektu z zawartością dokumentu XPS.
- Użyj obiektu ,
XpsDocument
aby wygenerować obiekt domyślny DocumentPaginator , który przechowuje wszystkie strony dokumentu XPS. - Utwórz wystąpienie klasy rozszerzonej
DocumentPaginator
obsługującej zakresy stron, przekazując obiekt domyślnyDocumentPaginator
i PageRange strukturę zwróconą PrintDialogprzez element . - Wywołaj metodę PrintDocument , przekazując wystąpienie klasy rozszerzonej
DocumentPaginator
, aby wysłać określony zakres stron do określonej drukarki.
/// <summary>
/// Print a specific range of pages within an XPS document.
/// </summary>
/// <param name="xpsFilePath">Path to source XPS file</param>
/// <returns>Whether the document printed</returns>
public static bool PrintDocumentPageRange(string xpsFilePath)
{
// Create the print dialog object and set options.
PrintDialog printDialog = new()
{
UserPageRangeEnabled = true
};
// Display the dialog. This returns true if the user presses the Print button.
bool? isPrinted = printDialog.ShowDialog();
if (isPrinted != true)
return false;
// Print a specific page range within the document.
try
{
// Open the selected document.
XpsDocument xpsDocument = new(xpsFilePath, FileAccess.Read);
// Get a fixed document sequence for the selected document.
FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();
// Create a paginator for all pages in the selected document.
DocumentPaginator docPaginator = fixedDocSeq.DocumentPaginator;
// Check whether a page range was specified in the print dialog.
if (printDialog.PageRangeSelection == PageRangeSelection.UserPages)
{
// Create a document paginator for the specified range of pages.
docPaginator = new DocPaginator(fixedDocSeq.DocumentPaginator, printDialog.PageRange);
}
// Print to a new file.
printDialog.PrintDocument(docPaginator, $"Printing {Path.GetFileName(xpsFilePath)}");
return true;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return false;
}
}
/// <summary>
/// Extend the abstract DocumentPaginator class to support page range printing. This class is based on the following online resources:
///
/// https://www.thomasclaudiushuber.com/2009/11/24/wpf-printing-how-to-print-a-pagerange-with-wpfs-printdialog-that-means-the-user-can-select-specific-pages-and-only-these-pages-are-printed/
///
/// https://social.msdn.microsoft.com/Forums/vstudio/en-US/9180e260-0791-4f2d-962d-abcb22ba8d09/how-to-print-multiple-page-ranges-with-wpf-printdialog
///
/// https://social.msdn.microsoft.com/Forums/en-US/841e804b-9130-4476-8709-0d2854c11582/exception-quotfixedpage-cannot-contain-another-fixedpagequot-when-printing-to-the-xps-document?forum=wpf
/// </summary>
public class DocPaginator : DocumentPaginator
{
private readonly DocumentPaginator _documentPaginator;
private readonly int _startPageIndex;
private readonly int _endPageIndex;
private readonly int _pageCount;
public DocPaginator(DocumentPaginator documentPaginator, PageRange pageRange)
{
// Set document paginator.
_documentPaginator = documentPaginator;
// Set page indices.
_startPageIndex = pageRange.PageFrom - 1;
_endPageIndex = pageRange.PageTo - 1;
// Validate and set page count.
if (_startPageIndex >= 0 &&
_endPageIndex >= 0 &&
_startPageIndex <= _documentPaginator.PageCount - 1 &&
_endPageIndex <= _documentPaginator.PageCount - 1 &&
_startPageIndex <= _endPageIndex)
_pageCount = _endPageIndex - _startPageIndex + 1;
}
public override bool IsPageCountValid => true;
public override int PageCount => _pageCount;
public override IDocumentPaginatorSource Source => _documentPaginator.Source;
public override Size PageSize { get => _documentPaginator.PageSize; set => _documentPaginator.PageSize = value; }
public override DocumentPage GetPage(int pageNumber)
{
DocumentPage documentPage = _documentPaginator.GetPage(_startPageIndex + pageNumber);
// Workaround for "FixedPageInPage" exception.
if (documentPage.Visual is FixedPage fixedPage)
{
var containerVisual = new ContainerVisual();
foreach (object child in fixedPage.Children)
{
var childClone = (UIElement)child.GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(child, null);
FieldInfo parentField = childClone.GetType().GetField("_parent", BindingFlags.Instance | BindingFlags.NonPublic);
if (parentField != null)
{
parentField.SetValue(childClone, null);
containerVisual.Children.Add(childClone);
}
}
return new DocumentPage(containerVisual, documentPage.Size, documentPage.BleedBox, documentPage.ContentBox);
}
return documentPage;
}
}
''' <summary>
''' Print a specific range of pages within an XPS document.
''' </summary>
''' <param name="xpsFilePath">Path to source XPS file</param>
''' <returns>Whether the document printed</returns>
Public Shared Function PrintDocumentPageRange(xpsFilePath As String) As Boolean
' Create the print dialog object and set options.
Dim printDialog As New PrintDialog With {
.UserPageRangeEnabled = True
}
' Display the dialog. This returns true if the user presses the Print button.
Dim isPrinted As Boolean? = printDialog.ShowDialog()
If isPrinted <> True Then Return False
' Print a specific page range within the document.
Try
' Open the selected document.
Dim xpsDocument As New XpsDocument(xpsFilePath, FileAccess.Read)
' Get a fixed document sequence for the selected document.
Dim fixedDocSeq As FixedDocumentSequence = xpsDocument.GetFixedDocumentSequence()
' Create a paginator for all pages in the selected document.
Dim docPaginator As DocumentPaginator = fixedDocSeq.DocumentPaginator
' Check whether a page range was specified in the print dialog.
If printDialog.PageRangeSelection = PageRangeSelection.UserPages Then
' Create a document paginator for the specified range of pages.
docPaginator = New DocPaginator(fixedDocSeq.DocumentPaginator, printDialog.PageRange)
End If
' Print to a new file.
printDialog.PrintDocument(docPaginator, $"Printing {Path.GetFileName(xpsFilePath)}")
Return True
Catch e As Exception
MessageBox.Show(e.Message)
Return False
End Try
End Function
' Extend the abstract DocumentPaginator class to support page range printing.
' This class is based on the following online resources:
' https://www.thomasclaudiushuber.com/2009/11/24/wpf-printing-how-to-print-a-pagerange-with-wpfs-printdialog-
' that-means-the-user-can-select-specific-pages-and-only-these-pages-are-printed/
' https://social.msdn.microsoft.com/Forums/vstudio/en-US/9180e260-0791-4f2d-962d-abcb22ba8d09/how-to-print-
' multiple-page-ranges-with-wpf-printdialog
' https://social.msdn.microsoft.com/Forums/en-US/841e804b-9130-4476-8709-0d2854c11582/exception-quotfixedpage-
' cannot-contain-another-fixedpagequot-when-printing-to-the-xps-document?forum=wpf
Public Class DocPaginator
Inherits DocumentPaginator
Private ReadOnly _documentPaginator As DocumentPaginator
Private ReadOnly _startPageIndex As Integer
Private ReadOnly _endPageIndex As Integer
Private ReadOnly _pageCount As Integer
Public Sub New(documentPaginator As DocumentPaginator, pageRange As PageRange)
' Set document paginator.
_documentPaginator = documentPaginator
' Set page indices.
_startPageIndex = pageRange.PageFrom - 1
_endPageIndex = pageRange.PageTo - 1
' Validate And set page count.
If _startPageIndex >= 0 AndAlso
_endPageIndex >= 0 AndAlso
_startPageIndex <= _documentPaginator.PageCount - 1 AndAlso
_endPageIndex <= _documentPaginator.PageCount - 1 AndAlso
_startPageIndex <= _endPageIndex Then
_pageCount = _endPageIndex - _startPageIndex + 1
End If
End Sub
Public Overrides ReadOnly Property IsPageCountValid As Boolean
Get
Return True
End Get
End Property
Public Overrides ReadOnly Property PageCount As Integer
Get
Return _pageCount
End Get
End Property
Public Overrides ReadOnly Property Source As IDocumentPaginatorSource
Get
Return _documentPaginator.Source
End Get
End Property
Public Overrides Property PageSize As Size
Get
Return _documentPaginator.PageSize
End Get
Set(value As Size)
_documentPaginator.PageSize = value
End Set
End Property
Public Overrides Function GetPage(pageNumber As Integer) As DocumentPage
Dim documentPage As DocumentPage = _documentPaginator.GetPage(_startPageIndex + pageNumber)
' Workaround for "FixedPageInPage" exception.
If documentPage.Visual.GetType() Is GetType(FixedPage) Then
Dim fixedPage As FixedPage = documentPage.Visual
Dim containerVisual = New ContainerVisual()
For Each child As Object In fixedPage.Children
Dim childClone = CType(child.[GetType]().GetMethod("MemberwiseClone", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(child, Nothing), UIElement)
Dim parentField As FieldInfo = childClone.[GetType]().GetField("_parent", BindingFlags.Instance Or BindingFlags.NonPublic)
If parentField IsNot Nothing Then
parentField.SetValue(childClone, Nothing)
containerVisual.Children.Add(childClone)
End If
Next
Return New DocumentPage(containerVisual, documentPage.Size, documentPage.BleedBox, documentPage.ContentBox)
End If
Return documentPage
End Function
End Class
Napiwek
Mimo że można użyć PrintDocument metody do drukowania bez otwierania okna dialogowego drukowania, ze względów wydajności lepiej użyć AddJob metody lub jednej z wielu Write metod i WriteAsync metody XpsDocumentWriter. Aby uzyskać więcej informacji na ten temat, zobacz Jak wydrukować plik XPS i Omówienie dokumentów drukowania.
Zobacz też
.NET Desktop feedback