今画面に映りきらなくてスクロールしなくては見れない部分も2枚目以降に印刷をしたい。
DataGrid
のまま?印刷する方針ということでいいんですかね?
下記のソースコードでアプリケーションの画面の印刷を試しましたが今描画できている範囲1枚分の印刷しかできなく、画面サイズを縮小などをするとそもそも印刷物も縮小されてしまっています。
横が収まるように、わざとScaleTransform
をしているのではないのですか?
xamlがわかりませんが、Canvas
にでも置かない限りWindow
より大きくなりません。
VisualTree
を切ったうえで、Measure
・Arrange
する必要があります。
.NET7です^^
xml
1<Window
2 x:Class="Q46pp5pq6ad51mb.MainWindow"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 Width="800"
6 Height="450">
7 <DockPanel x:Name="panel">
8 <Button
9 Click="Print_Clicked"
10 Content="Print"
11 DockPanel.Dock="Bottom" />
12 <DataGrid x:Name="dgList" />
13 </DockPanel>
14</Window>
cs
1using System;
2using System.Collections.Generic;
3using System.Data;
4using System.Linq;
5using System.Printing;
6using System.Windows;
7using System.Windows.Controls;
8using System.Windows.Media;
9using System.Windows.Xps;
10
11namespace Q46pp5pq6ad51mb;
12
13public partial class MainWindow : Window
14{
15 public MainWindow()
16 {
17 InitializeComponent();
18
19 var table = new DataTable(); // DataTableを使った深い意味はない(ダミーデータを作るのが楽ってだけ)
20 var columns = Enumerable.Range(1, 6)
21 .Select(x => new DataColumn($"Column{x}"))
22 .ToArray();
23 table.Columns.AddRange(columns);
24
25 for (var i = 1; i <= 100; i++)
26 {
27 var row = Enumerable.Range(1, table.Columns.Count)
28 .Select(x => $"Row{i}, Column{x}")
29 .ToArray();
30 table.Rows.Add(row);
31 }
32
33 dgList.ItemsSource = table.AsDataView();
34 }
35
36 private void Print_Clicked(object sender, RoutedEventArgs e)
37 {
38 var printDialog = new PrintDialog();
39 if (printDialog.ShowDialog() != true) return;
40
41 var dataGrid = dgList;
42 panel.Children.Remove(dataGrid); // VisualTree切断
43
44 var cc = new ContentControl // なんでもいいのだがPaddingがつけれるので
45 {
46 Padding = new Thickness(30),
47 Content = dataGrid,
48 };
49
50 var pageSize = new Size(printDialog.PrintableAreaHeight, printDialog.PrintableAreaWidth); // Landscape
51 cc.Measure(pageSize);
52 cc.Arrange(new Rect(pageSize));
53
54 //printDialog.PrintVisual(dataGrid, Title);
55
56 var printTicket = printDialog.PrintTicket;
57 printTicket.PageOrientation = PageOrientation.Landscape;
58 printDialog.PrintTicket = printTicket;
59
60
61 var writer = PrintQueue.CreateXpsDocumentWriter(printDialog.PrintQueue);
62 var doc = (VisualsToXpsDocument)writer.CreateVisualsCollator();
63 var sv = dataGrid.Descendants<ScrollViewer>().First();
64 sv.ScrollToTop();
65
66 doc.Write(dataGrid);
67 while (sv.VerticalOffset < sv.ScrollableHeight)
68 {
69 sv.PageDown();
70 dataGrid.UpdateLayout();
71 doc.Write(dataGrid);
72 };
73 doc.EndBatchWrite();
74
75
76 cc.Content = null;
77 panel.Children.Add(dataGrid); // VisualTree復帰
78 }
79}
80
81
82// [VisualTreeの子孫要素を取得する - xin9le.net](https://blog.xin9le.net/entry/2013/10/29/222336)
83public static class DependencyObjectExtensions
84{
85 public static IEnumerable<DependencyObject> Children(this DependencyObject obj)
86 {
87 if (obj == null) throw new ArgumentNullException(nameof(obj));
88 var count = VisualTreeHelper.GetChildrenCount(obj);
89 if (count == 0) yield break;
90 for (var i = 0; i < count; i++)
91 {
92 var child = VisualTreeHelper.GetChild(obj, i);
93 if (child != null) yield return child;
94 }
95 }
96 public static IEnumerable<DependencyObject> Descendants(this DependencyObject obj)
97 {
98 if (obj == null) throw new ArgumentNullException(nameof(obj));
99 foreach (var child in obj.Children())
100 {
101 yield return child;
102 foreach (var grandChild in child.Descendants())
103 yield return grandChild;
104 }
105 }
106 public static IEnumerable<T> Children<T>(this DependencyObject obj) where T : DependencyObject => obj.Children().OfType<T>();
107 public static IEnumerable<T> Descendants<T>(this DependencyObject obj) where T : DependencyObject => obj.Descendants().OfType<T>();
108}
VisualsToXpsDocument クラス (System.Windows.Xps) | Microsoft Learn
VisualTreeの子孫要素を取得する - xin9le.net
注意点
- 仮想プリンタで試したので何か根本的に間違っているかも^^;
VisualTree
を切る都合上いったん消えてしまう(VisualBrush
かなんかでダミーを出しておく?)
- 最後のページに行がダブる
実際のところ皆さんどうしてるんですかね?
- プロ(ギョーミーなアプリ)は有償コンポーネント
- アマ(趣味のアプリ)はファイルに出して「Excelでも何でも好きに印刷してくれ」
って感じでしょうか(私はアマなうえ、印刷したいと思ったこともないです^^;