Monday, June 25, 2012

Printing Visuals using WPF PrintDialog

Printing is quite simpler in WPF. In this post, I will explain how to print elements using PrintDialog class of WPF.

WPF provides PrintDialog class which allows you to do printing from WPF application. PrintDialog class is available in System.Window.Controls namespace. PrintDialog provides various methods related to print and print related settings. PrintDialog provides PrintVisual and PrintDocument methods for printing. In this post I will demonstrated how to use PrintVisual method.

In WPF, Framework Elements are directly or indirectly derived from Visual class. You can read more about WPF class hierarchy here. You can print any element which derives from Visual class using PrintVisual method of PrintDialog class.

Let’s have a look on sample below.

XAML

<Window x:Class="WpfApplication1.PrintVisualDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Print Visual Demo" Height="350" Width="300">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="0.9*" />
        <RowDefinition Height="0.2*"/>
    </Grid.RowDefinitions>
    <StackPanel Name="printPanel"
                Grid.Row="0"
                Margin="5">
        <Label Content="Sweet Baby"
            HorizontalAlignment="Center"
            FontSize="40"
            FontFamily="Calibri">
            <Label.Foreground>
                <LinearGradientBrush Opacity="1" 
                     StartPoint="0,0.5" EndPoint="1,0.5">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="Blue" Offset="0" />
                        <GradientStop Color="Red" Offset="0.5" />
                        <GradientStop Color="Green" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Label.Foreground>
        </Label>
        <Image Source="D:\Temp\baby.jpg"
                Height="150"
                Width="200">
        </Image>
    </StackPanel>
    <Button Content="Print"
                Grid.Row="1" Margin="5"
                Height="40" Width="150"
                HorizontalAlignment="Center"
                VerticalAlignment="Center" Click="Button_Click" />
</Grid>
</Window>

Code -
private void Button_Click(object sender, RoutedEventArgs e)
{
    PrintDialog pd = new PrintDialog();
    if (pd.ShowDialog() != true) return;
    pd.PrintVisual(printPanel, "Printing StackPanel...");
}

Output –






As per the example, When you click on Print button it will open print dialog. Select correct printer and hit print button, in my case I have selected PDF Creator printer which will generate PDF file. 


In code, I have just created an instance of PrintDailog class and called its ShowDialog method. And last I have called PrintVisual method from PrintDialog instance and passed Visual object which I wanted to print with descriptions. In above example I have passed StackPanel as Visual object which contains Text (Sweet Baby) and Image.

Instead of creating controls in XAML, you can dynamically create those through code and similarly print using PrintVisual method. See below code snippet.

private void Button_Click(object sender, RoutedEventArgs e)
{
    StackPanel sp = new StackPanel();

    TextBlock tb = new TextBlock();
    tb.Text = "Sweet Baby";
    tb.FontSize = 40;

    Image img = new Image();
    img.Source =new BitmapImage(new Uri(@"d:\temp\baby.jpg"));
    img.Height = 150;
    img.Width = 200;

    sp.Children.Add(tb);
    sp.Children.Add(img);

    PrintDialog pd = new PrintDialog();
    if (pd.ShowDialog() != true) return;
    pd.PrintVisual(printPanel, "Printing StackPanel...");
}

Let’s have a look on below sample which prints Canvas and elements inside.

XAML
<Window x:Class="WpfApplication1.PrintCanvasDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Print Canvas Demo" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.9*" />
            <RowDefinition Height="0.2*"/>
        </Grid.RowDefinitions>
        <Canvas Name="printCanvas"
                Width="350" Height="280">
            <TextBlock Text="This is sample text."
                       FontSize="18"
                       FontFamily="Arial"
                       Canvas.Top="20" Canvas.Left="60"/>
            <Ellipse Height="100" Width="125"
                     Fill="LightBlue"
                     Stroke="Blue"
                     StrokeThickness="2"
                     Canvas.Right="35" Canvas.Bottom="55"/>
            <Rectangle Height="15" Width="90"
                       Fill="Orange"
                       Stroke="Red"
                       Canvas.Top="80" Canvas.Left="150" />
            <Polygon Points="140,160 80,185 50,127 130,20"
                     Stroke="Purple"
                     StrokeThickness="2"
                     Canvas.Top="90" Canvas.Left="0">
                <Polygon.Fill>
                    <SolidColorBrush Color="Blue" Opacity="0.4"/>
                </Polygon.Fill>
                <Polygon.RenderTransform>
                    <RotateTransform CenterX="0" 
                                     CenterY="250" Angle="-10" />
                </Polygon.RenderTransform>
            </Polygon>
        </Canvas>
        <Button Content="Print"
                    Grid.Row="1" Margin="5"
                    Height="40" Width="150"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center" Click="Button_Click" />
    </Grid>
</Window>

private void Button_Click(object sender, RoutedEventArgs e)
        {
            PrintDialog pd = new PrintDialog();
            if (pd.ShowDialog() != true) return;
            pd.PrintVisual(printCanvas, "Printing Canvas...");
        }




Above example demonstrates how we can print Canvas and its elements. Canvas is also derived from Visual so we can print canvas using PrintVisual method of PrintDialog class. In above example instead of StackPanel I have passed Canvas as visual object.


See Also –
Transformationsin WPF

1 comment:

  1. I've looked a long time for printing stuff. With your example I build an easy to use control by submitting the Frameworkelement to the printer. Works great, with autoscaled controls to printer and perfect quality on printout. Thanks

    ReplyDelete