Printing in WPF with XPS/PrintVisual

Feb 15, 2014 at 7:10 PM
I am trying to print an OxyPlot chart in WPF.

I have made a UserControl containing the charts and a few other controls, and it looks perfectly well in the xaml designer.

When i try to print it via XPS and PrintVisual the charts do not show up on the print (the rest of the controls do).

Have any of you had any experience printing OxyPlot's from WPF, and how did you do it ??
Coordinator
Feb 16, 2014 at 1:34 PM
Did you try the OxyPlot.Xps library? I have not checked this recently, but it should be possible to create xps and print from the XpsExporter class
Mar 15, 2014 at 11:28 AM
Edited Mar 15, 2014 at 11:29 AM
I found a solution. I had to call UpdateLayout() before doing the actual printing.

So. If you have a UserControl (mine is called DefaultPrintControl) with some OxyPlot's and some other stuff on them, you can print it like this:
private void ButtonPrint_OnClick(object sender, RoutedEventArgs e)
        {
            var dialog = new PrintDialog();
            if (dialog.ShowDialog() != true)
            { return; }

            var dpc = new DefaultPrintControl();

            dpc.Measure(new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight));
            dpc.Arrange(new Rect(new Point(0, 0), dpc.DesiredSize));
            dpc.UpdateLayout();

            dialog.PrintVisual(dpc, "some description of the print job");
        }
Jul 7, 2014 at 2:39 PM
Hi,

I also try to print graph as same way. But I couldn't it even if I call UpdateLayout().
When I create instance of user control on memory empty page is printed out.
But I throw showing visual object to PrintVisual() it's no problem.

Should I set any special configuration to user control(XAML/code behind)?
In my case, user control is very simple as following.
<UserControl
    x:Class="Reports.TestView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d" 
    xmlns:oxy="http://oxyplot.codeplex.com"
    d:DesignHeight="800" d:DesignWidth="600"
    >

    <Grid>
        <oxy:Plot>
            <oxy:Plot.Axes>
                <oxy:LinearAxis Position="Left" Minimum="0" Maximum="100"/>
                <oxy:TimeSpanAxis Position="Bottom" Minimum="0" Maximum="86400" StringFormat="hh:mm"/>
            </oxy:Plot.Axes>
            <oxy:Plot.Series>
                <oxy:LineSeries ItemsSource="{Binding Path=DataList}" DataFieldX="Time" DataFieldY="Value" Color="Red"/>
            </oxy:Plot.Series>
        </oxy:Plot>
    </Grid>
</UserControl>
Jul 8, 2014 at 8:38 AM
If you are using the latest version of OxyPlot it wont work. I updated to the latest version some time ago, and the above code stopped working.

I downgraded to version "2014.1.231.1" and it works with that version, so they must have changed something in the underlying rendering code....
Jul 8, 2014 at 2:08 PM
Thank you for your great information!
When I try to use 2014.1.231.1 from NuGet it works fine.

I checked changing point roughly. Cause is probably in InvalidatePlot() (Plot.cs or PlotView.cs).
From following version of source code, it has not rendered if it's not receive Loaded event.

revision : 824 / change set : ffbabf441bcea4e2871c8c86fc56dbe910b3f87f [ffbabf441bce]

This modification is for performance issue.

So... I added uncool code as following it seems be working on latest version of OxyPlot.
"graph" is name of Plot object (<oxy:Plot x:Name="graph">)
    dpc.Measure(new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight));
    dpc.Arrange(new Rect(new Point(0, 0), dpc.DesiredSize));
    dpc.graph.RaiseEvent(new System.Windows.RoutedEventArgs(OxyPlot.Wpf.PlotView.LoadedEvent));   
    dpc.UpdateLayout();
or
    dpc.Measure(new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight));
    dpc.Arrange(new Rect(new Point(0, 0), dpc.DesiredSize));
    dpc.graph.IsRendering = true;
    dpc.graph.InvalidatePlot(true);
    dpc.graph.IsRendering = false;
    dpc.UpdateLayout();
Of course this is not correct way... But currently it may be only way.
It should be modified or extended for our case.
Jul 9, 2014 at 11:37 AM
Thanks GuruK. Your hack works :-)
Coordinator
Jul 10, 2014 at 11:17 AM
Have you seen the XpsExporter in the OxyPlot.Xps package? Can this be used? Let us know if there are bugs!
Jul 10, 2014 at 11:52 AM
I looked at the XpsExporter some time ago, but couldn't really use it. It prints the actual OxyPlot - but what i need is much more complex.

What I (and GuruK apparently) need is more complex prints with both OxyPlots and other controls, such as textboxes, images, etc... So we make a UserControl with all the stuff we need to print out, and print it with the above code.

This worked fine until the latest update of the OxyPlot rendering code :-(

OxyPlot is the only control i have come across that can not be printed properly with this method. This could be a bug in OxyPlot(?) When you call Measure, Arrange & UpdateLayout on a control it is supposed to render - OxyPlot doesn't.
Coordinator
Jul 10, 2014 at 12:03 PM
Thanks for the explanation, now I understand. This should be corrected, I guess this also applies when rendering a UserControl to a bitmap?
I have added https://oxyplot.codeplex.com/workitem/10231