Introduction
I have an application with a MainWindow (MVVM) consisting of a TabViewer
with 5 Tabs. Each Tab contains a ScrollViewer
, a Grid
and several UserControls
(MVC) within the Grid
.
Xaml of my MainWindow:
<Window x:Class="CharacterSheetGenerator.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ctrl="clr-namespace:CharacterSheetGenerator.Control"
xmlns:help="clr-namespace:CharacterSheetGenerator.Helpers"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
Title="MainWindow" Height="1600" Width="1320" Loaded="Window_Loaded">
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button Name="SaveButton" Command="{Binding LoadCommand}" Width="40" Height="30">
<Image Source="/images/LoadButtonPicture.png"/>
</Button>
<Button Name="LoadButton" Command="{Binding SaveCommand}" Width="40" Height="30">
<Image Source="/images/SaveButtonpicture.png" />
</Button>
<!-- Print Button currently in xaml.cs of my MainWindow -->
<Button Name="Print Button" Click="Button3_Click" Width="40" Height="30">
<Image Source="/images/PrintButtonPicture.png"/>
</Button>
</StackPanel>
<TabControl Grid.Row="1">
<TabItem Width="75" Height="20" Header="Übersicht">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" >
<i:Interaction.Behaviors>
<help:BubbleScrollEvent />
</i:Interaction.Behaviors>
<!-- Grid I'd like to print -->
<Grid Name="Übersicht">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="180"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<StackPanel>
<TextBlock FontSize="34" FontWeight="Bold" Text="Heldendokument"/>
<TextBlock FontSize="20" Text="Persönliche Daten" TextAlignment="Center"/>
</StackPanel>
<ctrl:CharacterAttributes VerticalAlignment="Top" AttributeList="{Binding Attributes, Mode=TwoWay}"/>
</StackPanel>
<Grid Grid.Row="2">
<StackPanel>
<ctrl:CharacterOverview VerticalAlignment="Top" CharacterInformation="{Binding CharacterInformation}" StatusValues="{Binding StatusValues, Mode=TwoWay}" Traits="{Binding Traits, Mode=TwoWay}" Expirience="{Binding Expirience}" TraitClickCommand="{Binding OpenTraitViewCommand}"/>
</StackPanel>
</Grid>
</Grid>
</Grid>
</ScrollViewer>
</TabItem>
<TabItem Width="75" Height="20" Header="Fertigkeiten">
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<i:Interaction.Behaviors>
<help:BubbleScrollEvent />
</i:Interaction.Behaviors>
<!-- Second Grid I'd like to print -->
<Grid Name="Fertigkeiten">
<!-- [...] -->
</TabItem>
<!-- [...] -->
Example of a my first Tab:
I've marked each of my UserControls with a few red borders.
Problem
The cyan dottet line represents the area, that would be printet on a DinA4 page, if I simply use PrintDialog.PrintVisual(Übersicht, "Printing Übersicht")
I've implemented the code from this answer and modified it in order to print all and not just one Tabs, but I've encountered a few problems.
Modified Code:
//I tried to create an array and iterate through it
System.Windows.FrameworkElement[] elements = { Übersicht as System.Windows.FrameworkElement, Fertigkeiten as System.Windows.FrameworkElement, Kampf as System.Windows.FrameworkElement,
Zauber as System.Windows.FrameworkElement, Inventar as System.Windows.FrameworkElement,};
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
foreach (FrameworkElement e in elements)
{
//store original scale
Transform originalScale = e.LayoutTransform;
//get selected printer capabilities
System.Printing.PrintCapabilities capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
//get scale of the print wrt to screen of WPF visual
double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / 1281, capabilities.PageImageableArea.ExtentHeight /
1800); // I had to change ActualWidth and Height to static Values, as Grids in Tabs, which haven't been opened at least once since the start of the application had no actual size
//Transform the Visual to scale
e.LayoutTransform = new ScaleTransform(scale, scale);
//get the size of the printer page
System.Windows.Size sz = new System.Windows.Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
//update the layout of the visual to the printer page size.
e.Measure(sz);
e.Arrange(new System.Windows.Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
//now print the visual to printer to fit on the one page.
printDialog.PrintVisual(e, "My Print");
//apply the original transform.
e.LayoutTransform = originalScale;
}
}
Now there are a few issues with this:
All
UserControls
which haven't been loaded since the lauch of the application will be emtpy (My second Page has a DataGrid. The rows are still there, but all the values are missing)If a Tab has been opened, but isn't the current open one, the UserControls have their data, but aren't resized accordingly (same problem with the cyan dottet lines)
let me show you a Example of my second Tab: (these are scanned DinA4 Pages)
First issue: (you can see the UserControl with the colored Boxes still works, because it has already been loaded on the first page)
Second Issue:
Still missing some code? Go to my GitHub and clone the project to try it for yourself.
Questions:
- What causes this arguably weird behavior, how can I solve it?
- Is there another way but printDialog.PrintVisual() to print my Pages?