トップ回答者
印刷の(現在)ページ指定方法について

質問
-
.NET Framework4.0のC#(WPF)でFixedDocumentを使用して、現在ページを印刷させたいです。(全ページ印刷はできています)
独自印刷設定ダイアログを使用する場合、各種設定後、その値をPrintDialogクラスの各プロパティに設定することになると思います。
現在ページの指定は、PageRangeSelectionプロパティにメンバUserPagesを、PageRangeプロパティに現在ページをセットする必要が
あると思いますが、4.5のメンバCurrentPageのように簡単に指定する方法はないでしょうか?(現在ページの管理をプログラムでせず対応する方法)
また、一般的な話になりますが、プリンタ種類(XPSや、PDF、一般的なプリンタなど)によって、ページの指定方法は実装してやる必要があるものなのでしょうか?
よろしくお願いします。
- 編集済み tenpu 2014年5月13日 4:57
回答
-
独自印刷設定ダイアログを使用する場合、各種設定後、その値をPrintDialogクラスの各プロパティに設定することになると思います。
独自の設定ダイアログがあるならば、PrintDialogに設定せずともPrintTicketとXpsDocumentWriterで印刷は行えます。
現在ページの指定は、PageRangeSelectionプロパティにメンバUserPagesを、PageRangeプロパティに現在ページをセットする必要があると思いますが、4.5のメンバCurrentPageのように簡単に指定する方法はないでしょうか?(現在ページの管理をプログラムでせず対応する方法)
DocumentViewerで表示しているFixedDocumentのCurrentPageという意味であれば、DocumentViewerにMasterPageNumberというプロパティがあるので、それをPageRangeに使えばいいです。
また、一般的な話になりますが、プリンタ種類(XPSや、PDF、一般的なプリンタなど)によって、ページの指定方法は実装してやる必要があるものなのでしょうか?
設定できるプロパティはプリンタごとに違ったりします。たとえば両面印刷ができるできないとか。(PrintCapabilities参照)
実際にプリンタの対応状況は実行環境によって異なるので、考慮して設定してやる必要があります。
ですが、PrintDialogをつかうなら、PrintTicketに設定してくれるので、わざわざ実装する必要はありません。using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Xps.Packaging; using System.Printing; namespace WpfApplication1 { public partial class MainWindow : Window { private FixedDocument fixedDocument; private DocumentViewer viewer; public MainWindow() { InitializeComponent(); Button button = new Button(); button.Content = "Print"; DockPanel.SetDock(button, Dock.Top); button.Click += Button_Click; viewer = new DocumentViewer(); DockPanel dock = new DockPanel(); dock.Children.Add(button); dock.Children.Add(viewer); this.Content = dock; var document = new XpsDocument(@"C:\sample.xps", System.IO.FileAccess.Read); var sequence = document.GetFixedDocumentSequence(); fixedDocument =sequence.References[0].GetDocument(false); viewer.Document = sequence; } private void Button_Click(object sender, RoutedEventArgs e) { PrintTicket ticket = GetPrintTicketFromPrinter(); var que = LocalPrintServer.GetDefaultPrintQueue(); System.Windows.Xps.XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(que); int currentPage = viewer.MasterPageNumber; FixedDocument fixRangeDocument = CreateRangeDocument(fixedDocument, new PageRange(currentPage, currentPage)); writer.Write(fixRangeDocument.DocumentPaginator, ticket); } /// <summary>FixedDocumentから指定範囲を抽出したFixedDocumentを作る</summary> private FixedDocument CreateRangeDocument(FixedDocument sourceDocument, PageRange range) { return GetRangeDocument(sourceDocument, Enumerable.Range(range.PageFrom-1,range.PageFrom - range.PageTo +1)); } /// <summary>FixedDocumentから指定ページを抽出したFixedDocumentを作る</summary> private FixedDocument GetRangeDocument(FixedDocument sourceDocument,IEnumerable<int> pageIndexies) { PrintDialog dlg = new PrintDialog(); dlg.ShowDialog(); var x=pageIndexies.ToArray(); FixedDocument docNew = new System.Windows.Documents.FixedDocument(); System.Windows.Markup.IAddChild pages = (System.Windows.Markup.IAddChild)docNew; foreach(int pageIndex in pageIndexies) { PageContent pageContent; pageContent = new System.Windows.Documents.PageContent(); pageContent.BeginInit(); var page = this.fixedDocument.Pages[pageIndex]; ((System.Windows.Markup.IUriContext)pageContent).BaseUri = ((System.Windows.Markup.IUriContext)page).BaseUri; pageContent.Source = page.Source; ; pageContent.EndInit(); pages.AddChild(pageContent); } return docNew; } //http://msdn.microsoft.com/ja-jp/library/vstudio/ms573295%28v=vs.100%29.aspxより private PrintTicket GetPrintTicketFromPrinter() { PrintQueue printQueue = null; LocalPrintServer localPrintServer = new LocalPrintServer(); PrintQueueCollection localPrinterCollection = localPrintServer.GetPrintQueues(); System.Collections.IEnumerator localPrinterEnumerator = localPrinterCollection.GetEnumerator(); if (localPrinterEnumerator.MoveNext()) { printQueue = (PrintQueue)localPrinterEnumerator.Current; } else { return null; } PrintTicket printTicket = printQueue.DefaultPrintTicket; PrintCapabilities printCapabilites = printQueue.GetPrintCapabilities(); //if (printCapabilites.CollationCapability.Contains(Collation.Collated)) //{ // printTicket.Collation = Collation.Collated; //} //if (printCapabilites.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge)) //{ // printTicket.Duplexing = Duplexing.TwoSidedLongEdge; //} //if (printCapabilites.StaplingCapability.Contains(Stapling.StapleDualLeft)) //{ // printTicket.Stapling = Stapling.StapleDualLeft; //} return printTicket; } } }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
すべての返信
-
独自印刷設定ダイアログを使用する場合、各種設定後、その値をPrintDialogクラスの各プロパティに設定することになると思います。
独自の設定ダイアログがあるならば、PrintDialogに設定せずともPrintTicketとXpsDocumentWriterで印刷は行えます。
現在ページの指定は、PageRangeSelectionプロパティにメンバUserPagesを、PageRangeプロパティに現在ページをセットする必要があると思いますが、4.5のメンバCurrentPageのように簡単に指定する方法はないでしょうか?(現在ページの管理をプログラムでせず対応する方法)
DocumentViewerで表示しているFixedDocumentのCurrentPageという意味であれば、DocumentViewerにMasterPageNumberというプロパティがあるので、それをPageRangeに使えばいいです。
また、一般的な話になりますが、プリンタ種類(XPSや、PDF、一般的なプリンタなど)によって、ページの指定方法は実装してやる必要があるものなのでしょうか?
設定できるプロパティはプリンタごとに違ったりします。たとえば両面印刷ができるできないとか。(PrintCapabilities参照)
実際にプリンタの対応状況は実行環境によって異なるので、考慮して設定してやる必要があります。
ですが、PrintDialogをつかうなら、PrintTicketに設定してくれるので、わざわざ実装する必要はありません。using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Xps.Packaging; using System.Printing; namespace WpfApplication1 { public partial class MainWindow : Window { private FixedDocument fixedDocument; private DocumentViewer viewer; public MainWindow() { InitializeComponent(); Button button = new Button(); button.Content = "Print"; DockPanel.SetDock(button, Dock.Top); button.Click += Button_Click; viewer = new DocumentViewer(); DockPanel dock = new DockPanel(); dock.Children.Add(button); dock.Children.Add(viewer); this.Content = dock; var document = new XpsDocument(@"C:\sample.xps", System.IO.FileAccess.Read); var sequence = document.GetFixedDocumentSequence(); fixedDocument =sequence.References[0].GetDocument(false); viewer.Document = sequence; } private void Button_Click(object sender, RoutedEventArgs e) { PrintTicket ticket = GetPrintTicketFromPrinter(); var que = LocalPrintServer.GetDefaultPrintQueue(); System.Windows.Xps.XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(que); int currentPage = viewer.MasterPageNumber; FixedDocument fixRangeDocument = CreateRangeDocument(fixedDocument, new PageRange(currentPage, currentPage)); writer.Write(fixRangeDocument.DocumentPaginator, ticket); } /// <summary>FixedDocumentから指定範囲を抽出したFixedDocumentを作る</summary> private FixedDocument CreateRangeDocument(FixedDocument sourceDocument, PageRange range) { return GetRangeDocument(sourceDocument, Enumerable.Range(range.PageFrom-1,range.PageFrom - range.PageTo +1)); } /// <summary>FixedDocumentから指定ページを抽出したFixedDocumentを作る</summary> private FixedDocument GetRangeDocument(FixedDocument sourceDocument,IEnumerable<int> pageIndexies) { PrintDialog dlg = new PrintDialog(); dlg.ShowDialog(); var x=pageIndexies.ToArray(); FixedDocument docNew = new System.Windows.Documents.FixedDocument(); System.Windows.Markup.IAddChild pages = (System.Windows.Markup.IAddChild)docNew; foreach(int pageIndex in pageIndexies) { PageContent pageContent; pageContent = new System.Windows.Documents.PageContent(); pageContent.BeginInit(); var page = this.fixedDocument.Pages[pageIndex]; ((System.Windows.Markup.IUriContext)pageContent).BaseUri = ((System.Windows.Markup.IUriContext)page).BaseUri; pageContent.Source = page.Source; ; pageContent.EndInit(); pages.AddChild(pageContent); } return docNew; } //http://msdn.microsoft.com/ja-jp/library/vstudio/ms573295%28v=vs.100%29.aspxより private PrintTicket GetPrintTicketFromPrinter() { PrintQueue printQueue = null; LocalPrintServer localPrintServer = new LocalPrintServer(); PrintQueueCollection localPrinterCollection = localPrintServer.GetPrintQueues(); System.Collections.IEnumerator localPrinterEnumerator = localPrinterCollection.GetEnumerator(); if (localPrinterEnumerator.MoveNext()) { printQueue = (PrintQueue)localPrinterEnumerator.Current; } else { return null; } PrintTicket printTicket = printQueue.DefaultPrintTicket; PrintCapabilities printCapabilites = printQueue.GetPrintCapabilities(); //if (printCapabilites.CollationCapability.Contains(Collation.Collated)) //{ // printTicket.Collation = Collation.Collated; //} //if (printCapabilites.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge)) //{ // printTicket.Duplexing = Duplexing.TwoSidedLongEdge; //} //if (printCapabilites.StaplingCapability.Contains(Stapling.StapleDualLeft)) //{ // printTicket.Stapling = Stapling.StapleDualLeft; //} return printTicket; } } }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
フォーラム オペレーターの星 睦美です。
gekka さん、いつも回答ありがとうございます。
tenpu さん、参考になる回答だと思いますので今回は私から[回答としてマーク] させていただきました。
(もし疑問な点がありましたら、[回答としてのマークの解除]をして返信できます。)
投稿者からの[回答としてマーク] が回答者のはげみになりますので、次回役立つ回答がありましたらtenpu さんから[回答としてマーク] いただけると嬉しいです。
では、これからもMSDN フォーラムをよろしくお願いします。
フォーラム オペレーター 星 睦美 - MSDN Community Support
-
また、一般的な話になりますが、プリンタ種類(XPSや、PDF、一般的なプリンタなど)によって、ページの指定方法は実装してやる必要があるものなのでしょうか?
質問の内容からして、ここで言う「ページの指定方法」は、「ページ番号の指定方法」のことだと思います。
プリンタは、それぞれのドキュメント データのどこからが1ページ目で、どこからが2ページ目かわかりません。つまり、word 文書の「1ページ目」を表す符号と、Excel 文書の「1ページ目」を表す符号は異なっていると考えられます。なので、ドキュメント データを認識出るもの、つまりアプリケーションが「ページ」という概念を与えてやらなければならないと思いますが、いかがでしょうか。Jitta@わんくま同盟