首页 > 技术文章 > 在WPF中使用PrintDialog.PrintDocument方法进行打印

xhubobo 原文

使用PrintDialog.PrintDocument方法进行打印需要提前布局流文档,流文档不能直接在编辑器中显示,可以考虑在用户控件或者窗口中进行布局后,将代码拷贝进流文档中。

对流文档进行数据赋值时,可以考虑在流文档中预定义TextBlock文本,对其进行命名。之后在渲染时,通过遍历源数据中的属性名,在流文档中查找相应的TextBlock文本,找到后对其进行赋值。

打印参数设置等思路可以参考:TSC TTP-244Pro标签打印机打印步骤小结

1、流文档示例

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

    <Paragraph>
        <Border>
            <Canvas Name="MainCanvas" Width="200" Height="100" Background="White">
                <Line Style="{StaticResource LineStyle}" X1="3" Y1="3" X2="194" Y2="3"/>
                <Line Style="{StaticResource LineStyle}" X1="194" Y1="3" X2="194" Y2="96"/>
                <Line Style="{StaticResource LineStyle}" X1="3" Y1="96" X2="194" Y2="96"/>
                <Line Style="{StaticResource LineStyle}" 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 LineStyle}" 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 LineStyle}" 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 LineStyle}" 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、打印实体类

public class PrintModel
{
    /// <summary>
    /// 批号
    /// </summary>
    public string BatchNumber { get; set; }

    /// <summary>
    /// 订单号
    /// </summary>
    public string OrderNumber { get; set; }

    /// <summary>
    /// 物料代码
    /// </summary>
    public string MaterialNumber { get; set; }
}

3、渲染类

public interface IDocumentRenderer
{
    void Render(FlowDocument doc, object data);
}

public class CommonDocumentRenderer : IDocumentRenderer
{
    public void Render(FlowDocument doc, object data)
    {
        var model = data as PrintModel;
        if (model == null)
        {
            throw new ArgumentException("data is not PrintModel");
        }

        var type = typeof(PrintModel);
        var properties = type.GetProperties();
        foreach (var property in properties)
        {
            //文本赋值
            if (doc.FindName(property.Name) is TextBlock textBlock)
            {
                textBlock.Text = property.GetValue(model)?.ToString();
            }
        }
    }
}

4、打印代码示例

public void Print(FlowDocument document, object data, string printer, int copyCount)
{
    var renderer = new CommonDocumentRenderer();
    renderer.Render(document, data);
    Print(document, printer, entity.Description, copyCount);
}

/// <summary>
/// 打印
/// </summary>
/// <param name="document">流文档</param>
/// <param name="printer">打印机名称</param>
/// <param name="description">打印描述</param>
/// <param name="copyCount">打印个数</param>
public static void Print(FlowDocument document, string printer, string description, int copyCount)
{
    var localPrintServer = new LocalPrintServer();
    var printQueue = localPrintServer.GetPrintQueue(printer);
    if (printQueue.IsInError)
    {
        throw new Exception("打印机处于错误状态");
    }

    var printDialog = new PrintDialog
    {
        PrintQueue = printQueue, //打印队列
        PrintTicket = {CopyCount = copyCount} //打印个数
    };

    //设置纸张大小
    var pageWidth = (int) Math.Ceiling(printDialog.PrintableAreaWidth); //小标签:114
    var pageHeight = (int) Math.Ceiling(printDialog.PrintableAreaHeight); //小标签:227
    printDialog.PrintTicket.PageMediaSize = new PageMediaSize(pageWidth, pageHeight);

    //设置纸张边距
    var paperSize = GetPaperSize(printer); //小标签:118*246
    var offsetX = (int) Math.Ceiling((paperSize.Width - pageWidth) / 2f);
    var offsetY = (int) Math.Ceiling((paperSize.Height - pageHeight) / 2f);
    document.PagePadding = new Thickness(offsetX, offsetY, offsetX, offsetY);

    //打印
    var paginator = ((IDocumentPaginatorSource) document).DocumentPaginator;
    printDialog.PrintDocument(paginator, description);
}

推荐阅读