Anzeigen eines Druckdialogfelds (WPF .NET)
Möchten Sie aus Ihrer Anwendung drucken? Sie können die PrintDialog Klasse verwenden, um ein standardmäßiges Microsoft Windows-Druckdialogfeld zu öffnen. Gehen Sie dazu wie folgt vor:
Anmerkung
Das System.Windows.Controls.PrintDialog Steuerelement, das für WPF verwendet und hier erläutert wird, sollte nicht mit der System.Windows.Forms.PrintDialog Komponente von Windows Forms verwechselt werden.
Die PrintDialog Klasse bietet ein einzelnes Steuerelement für die Druckkonfiguration und die Übermittlung von Druckaufträgen. Das Steuerelement ist einfach zu verwenden und kann mithilfe von XAML-Markup oder Code instanziiert werden. In den folgenden Beispielen wird mithilfe von Code eine PrintDialog
Instanz erstellt und angezeigt.
Sie können das Dialogfeld "Drucken" verwenden, um Druckoptionen zu konfigurieren, z. B.:
- Drucken Sie nur einen bestimmten Seitenbereich.
- Wählen Sie auf Ihrem Computer installierte Drucker aus. Sie können die Option Microsoft XPS Document Writer verwenden, um diese Dokumenttypen zu erstellen:
- XML Paper Specification (XPS)
- Open XML Paper Specification (OpenXPS)
Drucken des gesamten Dokuments
In diesem Beispiel werden alle Seiten eines XPS-Dokuments gedruckt. Standardmäßig lautet der Code wie folgt:
- Öffnen Eines Druckdialogfensters, in dem der Benutzer aufgefordert wird, einen Drucker auszuwählen und einen Druckauftrag zu starten.
- Instanziieren Sie ein XpsDocument-Objekt mit dem Inhalt des XPS-Dokuments.
- Verwenden Sie das
XpsDocument
-Objekt, um ein DocumentPaginator-Objekt zu generieren, das alle Seiten des XPS-Dokuments enthält. - Rufen Sie die PrintDocument-Methode auf, und übergeben Sie das
DocumentPaginator
-Objekt, um alle Seiten an den angegebenen Drucker zu senden.
/// <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
Drucken eines Seitenbereichs
Manchmal möchten Sie nur einen bestimmten Seitenbereich in einem XPS-Dokument drucken. Dazu erweitern wir die abstrakte DocumentPaginator Klasse, um Unterstützung für Seitenbereiche hinzuzufügen. Standardmäßig lautet der Code wie folgt:
- Öffnen Sie ein Druckdialogfenster, in dem der Benutzer aufgefordert wird, einen Drucker auszuwählen, einen Seitenbereich anzugeben und einen Druckauftrag zu starten.
- Instanziieren Sie ein XpsDocument-Objekt mit dem Inhalt des XPS-Dokuments.
- Verwenden Sie das
XpsDocument
-Objekt, um ein Standardobjekt DocumentPaginator zu generieren, das alle Seiten des XPS-Dokuments enthält. - Erstellen Sie eine Instanz einer erweiterten
DocumentPaginator
-Klasse, die Seitenbereiche unterstützt, indem Sie das vordefinierteDocumentPaginator
-Objekt und die vom PrintDialogzurückgegebene PageRange-Struktur übergeben. - Rufen Sie die PrintDocument-Methode auf und übergeben Sie eine Instanz der erweiterten
DocumentPaginator
-Klasse, um den angegebenen Seitenbereich an den angegebenen Drucker zu senden.
/// <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
Trinkgeld
Obwohl Sie die PrintDocument-Methode zum Drucken verwenden können, ohne das Druckdialogfeld zu öffnen, ist es aus Leistungsgründen besser, die AddJob-Methode oder eine der vielen Write und WriteAsync Methoden der XpsDocumentWriterzu verwenden. Weitere Informationen hierzu finden Sie unter Drucken einer XPS-Datei und Übersicht über das Drucken von Dokumenten.
Siehe auch
.NET Desktop feedback