日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

WPF的打印预览

發布時間:2023/12/8 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WPF的打印预览 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文基本借鑒了用WPF實現打印及打印預覽

WPF的文檔使用基本使用文檔模版Flow Document,但是單獨的Flow Document(流文檔)是沒法預覽的,你必須把它放在一個容器中才可以,流文檔的容器有FlowDocumentScrollViewer,FlowDocumentPageViewer,FlowDocumentReader,另外還有DocumentViewer,這個只支持固定流文檔(只讀)。

本次博客就決定界面使用DocumentViewer,DocumentViewer有很好的分頁功能,我們只需要生成固定文檔(XPS),然后交給它,它就能很好的將內容預覽出來。

<Table FontSize="16"><TableRowGroup><TableRow><TableCell><Paragraph>班級</Paragraph></TableCell><TableCell><Paragraph><Run Text="{Binding ClassName}"></Run></Paragraph></TableCell></TableRow></TableRowGroup> </Table>

但最大的問題來了:流文檔的Table的行數是固定的,流文檔上的對象是靜態的,所以我們只能用后臺代碼來手工改變它了,這是相當不方便的地方……我定義了這么一個接口來做這種工作。

public interface IDocumentRenderer {void Render(FlowDocument doc, Object data); }

就比如我下面需要獲取班級所有學生各門成績

<Table><Table.Columns><TableColumn Width="200"/><TableColumn Width="150"/><TableColumn Width="150"/><TableColumn Width="150"/></Table.Columns><TableRowGroup Name="Student" Background="LightGray" FontWeight="Bold"><TableRow><TableCell style="{StaticResource CellStyle}"><Paragraph>Name</Paragraph></TableCell><TableCell style="{StaticResource CellStyle}"><Paragraph>ID</Paragraph></TableCell><TableCell style="{StaticResource CellStyle}"><Paragraph>Chinese</Paragraph></TableCell><TableCell style="{StaticResource CellStyle}"><Paragraph>Math</Paragraph></TableCell></TableRow></TableRowGroup> </Table>

定義一個繼承IDocumentRenderer接口的類,實現Render方法

public class ClassDocumentRender : IDocumentRenderer {public void Render(FlowDocument doc, Object data){TableRowGroup group = doc.FindName("Student") as TableRowGroup ;Style cellStyle = doc.Resource("CellStyle") as Style;foreach(Student student in ((ClassData)data).StudentList){TableRow row = new TableRow();TableCell cell = new TableCell(new Paragraph(new Run(student.Name)));cell.Style = cellStyle;row.Cells.Add(cell);cell = new TableCell(new Paragraph(new Run(student.ID.ToString())));cell.Style = cellStyle;row.Cells.Add(cell);cell = new TableCell(new Paragraph(new Run(student.Chinese.ToString())));cell.Style = cellStyle;row.Cells.Add(cell);cell = new TableCell(new Paragraph(new Run(student.Math.ToString())));cell.Style = cellStyle;row.Cells.Add(cell);group.Rows.Add(row);}} }

先定義一個能接受流文檔與IDocumentRenderer接口的方法。這里的DataContext必須要有,因為流文檔中的數據都是以binding形式寫的,UI只是用來顯示數據的,而不是存儲數據的。

public FlowDocument LoadDocumentAndRender(string strTmplName, Object data, IDocumentRenderer renderer = null) {FlowDocument doc = (FlowDocument)Application.LoadComponent(new Uri(strTmplName, UriKind.RelativeOrAbsolute));doc.PagePadding = new Thickness(50);doc.DataContext = data;if (renderer != null){renderer.Render(doc, data);}return doc; }

定義一個加載流文檔的方法

public void LoadXps(FlowDocument flowDoc) {//構造一個基于內存的xps documentMemoryStream ms = new MemoryStream();Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);Uri DocumentUri = new Uri("pack://InMemoryDocument.xps");PackageStore.RemovePackage(DocumentUri);PackageStore.AddPackage(DocumentUri, package);XpsDocument xpsDocument = new XpsDocument(package, CompressionOption.Fast, DocumentUri.AbsoluteUri);//將flow document寫入基于內存的xps document中去XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);writer.Write(((IDocumentPaginatorSource)flowDoc).DocumentPaginator);//獲取這個基于內存的xps document的fixed documentdocViewer.Document = xpsDocument.GetFixedDocumentSequence();//關閉基于內存的xps documentxpsDocument.Close(); }

這是打印預覽代碼,然后你可以從界面上DocumentView上的打印按鈕來打印

async Task ShowMyClass(MyClass myClass) {ClassReportData crd = await GetClassReportData(myClass);FlowDocument flowDoc = LoadDocumentAndRender("../Print/ClassReportDocument.xaml", crd, new ClassReportDocumentRenderer());Dispatcher.BeginInvoke(new LoadXpsMethod(LoadXps), DispatcherPriority.ApplicationIdle, flowDoc); }private async Task<ClassReportData > GetClassReportData(MyClass myClass) {ClassReportData erd = new ClassReportData ();await TaskEx.Delay(1000);return erd; }

這是多選班級打印,直接跳到微軟的打印界面,我當時其實想的是弄個隊列,然后一個一個打印,后來檢查了PrintDialog類之后發現不用了,它內部實現其實就有PrintQueue,本身內部就有個隊列來維護先后順序的,那么我們直接調用PrintDocument方法就可以了

private async void printBtn_Click(object sender, RoutedEventArgs e) {PrintDialog pDialog = new PrintDialog();pDialog.PageRangeSelection = PageRangeSelection.AllPages;// Display the dialog. This returns true if the user presses the Print button.bool? print = pDialog.ShowDialog();if (print == true){List<MyClass> result = (from a in ViewModel.ClassListwhere a.IsSelectedselect a).ToList();foreach (var result in result){ClassReportData crd = await GetClassReportData(result);FlowDocument flowDoc = LoadDocumentAndRender("../Print/ClassReportDocument.xaml", crd, new ClassReportDocumentRenderer());Dispatcher.BeginInvoke(new Action(() =>{pDialog.PrintDocument(((IDocumentPaginatorSource)flowDoc).DocumentPaginator, "打印報表");}), DispatcherPriority.ApplicationIdle);}} }

注意:上文必須使用BeginInvoke而且參數必須為DispatcherPriority.ApplicationIdle,否則binding的地方都是空白的,因為給Document的DataContext賦值的時候,Document的內容并不是馬上改變的。

總結

以上是生活随笔為你收集整理的WPF的打印预览的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。