WPF Printing with PrintDialog.PrintDocument Method

When using PrintDialog.PrintDocument for printing in WPF, you need to prepare a FlowDocument for layout. FlowDocuments cannot be dispalyed directly in designers, so you typically design them in a UserControl or Window, then copy the XAML into the FlowDocument.

To populate the FlowDocument with data, pre-define named TextBlock eelments within the document. At runtime, iterate through your data source properties, locate the corresponding TextBlock by namme, and assign values accordingly.

1. FlowDocument Example

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              FontFamily="SimSun">
    <FlowDocument.Resources>
        <Style x:Key="BorderLineStyle" TargetType="{x:Type Line}">
            <Setter Property="Stroke" Value="Black"/>
            <Setter Property="StrokeThickness" Value="1"/>
        </Style>
    </FlowDocument.Resources>

    <Paragraph>
        <Border>
            <Canvas Name="PrintCanvas" Width="200" Height="100" Background="White">
                <Line Style="{StaticResource BorderLineStyle}" X1="3" Y1="3" X2="194" Y2="3"/>
                <Line Style="{StaticResource BorderLineStyle}" X1="194" Y1="3" X2="194" Y2="96"/>
                <Line Style="{StaticResource BorderLineStyle}" X1="3" Y1="96" X2="194" Y2="96"/>
                <Line Style="{StaticResource BorderLineStyle}" X1="3" Y1="3" X2="3" Y2="96"/>

                <Grid Canvas.Left="5" Canvas.Top="5" Width="190" Height="90">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="1*"/>
                        <RowDefinition Height="1*"/>
                        <RowDefinition Height="1*"/>
                        <RowDefinition Height="1*"/>
                        <RowDefinition Height="2"/>
                    </Grid.RowDefinitions>
                    <TextBlock Grid.Row="0" Text="123456有限公司"
                       TextAlignment="Center" FontSize="14"
                       HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
                    <StackPanel Grid.Row="1" Orientation="Horizontal">
                        <TextBlock Text="商品批号:" FontSize="12" Margin="5,0,0,0"
                           HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
                        <Line Style="{StaticResource BorderLineStyle}" X1="-5" Y1="21" X2="113" Y2="21"/>
                    </StackPanel>
                    <StackPanel Grid.Row="2" Orientation="Horizontal">
                        <TextBlock Text="物料编号 :" FontSize="12" Margin="5,0,0,0"
                           HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
                        <Line Style="{StaticResource BorderLineStyle}" X1="-5" Y1="21" X2="113" Y2="21"/>
                    </StackPanel>
                    <StackPanel Grid.Row="3" Orientation="Horizontal">
                        <TextBlock Text="订 单 号 :" FontSize="12" Margin="5,0,0,0"
                           HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
                        <Line Style="{StaticResource BorderLineStyle}" X1="-5" Y1="21" X2="113" Y2="21"/>
                    </StackPanel>
                </Grid>

                <TextBlock Name="BatchNumber" Canvas.Left="75" Canvas.Top="34" FontSize="12" Text="商品批号"/>
                <TextBlock Name="MaterialNumber" Canvas.Left="75" Canvas.Top="56" FontSize="12" Text="物料编号"/>
                <TextBlock Name="OrderNumber" Canvas.Left="75" Canvas.Top="78" FontSize="12" Text="订单号"/>
            </Canvas>
        </Border>
    </Paragraph>
</FlowDocument>

2. Print Data Model

public class PrintDataModel
{
    public string BatchNumber { get; set; }
    public string OrderNumber { get; set; }
    public string MaterialNumber { get; set; }
}

3. Document Renderer

public interface IDocumentFiller
{
    void Fill(FlowDocument document, object data);
}

public class FlowDocumentFiller : IDocumentFiller
{
    public void Fill(FlowDocument document, object data)
    {
        var printData = data as PrintDataModel;
        if (printData == null)
        {
            throw new ArgumentException("Invalid data type. Expected PrintDataModel.");
        }

        var modelType = typeof(PrintDataModel);
        var properties = modelType.GetProperties();

        foreach (var prop in properties)
        {
            if (document.FindName(prop.Name) is TextBlock targetBlock)
            {
                var value = prop.GetValue(printData);
                targetBlock.Text = value?.ToString() ?? string.Empty;
            }
        }
    }
}

4. Printing Implementation

public void ExecutePrint(FlowDocument document, object data, string printerName, int copies)
{
    var filler = new FlowDocumentFiller();
    filler.Fill(document, data);
    SendToPrinter(document, printerName, "Print Job", copies);
}

public static void SendToPrinter(FlowDocument document, string printerName, string jobDescription, int copies)
{
    var printServer = new LocalPrintServer();
    var queue = printServer.GetPrintQueue(printerName);

    if (queue.IsInError)
    {
        throw new Exception("Printer is in error state.");
    }

    var dialog = new PrintDialog
    {
        PrintQueue = queue,
        PrintTicket = { CopyCount = copies }
    };

    var width = (int)Math.Ceiling(dialog.PrintableAreaWidth);
    var height = (int)Math.Ceiling(dialog.PrintableAreaHeight);
    dialog.PrintTicket.PageMediaSize = new PageMediaSize(width, height);

    var paper = GetPaperDimensions(printerName);
    var marginX = (int)Math.Ceiling((paper.Width - width) / 2f);
    var marginY = (int)Math.Ceiling((paper.Height - height) / 2f);
    document.PagePadding = new Thickness(marginX, marginY, marginX, marginY);

    var paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
    dialog.PrintDocument(paginator, jobDescription);
}

Tags: WPF PrintDialog PrintDocument FlowDocument Printing

Posted on Mon, 01 Jun 2026 17:12:36 +0000 by it2051229