Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475

使用 WebView2 封装一个生成 PDF 的 WPF 控件

最近在迁移项目到 .net6,发现项目中用的 PDF 库不支持 .net6,于是想着换一个库。结果找了一大圈,发现不是版本不支持,就是收费。
嗐!还能咋办,只能自己搞一个 PDF 生成控件咯。

环境准备 WPF + WebView2 + Vue

WebView2

  • WebView2.CoreWebView2.PrintToPdfAsync 可以将 html 文件生成 pdf。
  • CEF 也有类似的 API,Evergreen WebView2 会自动更新,而且不需要将库打包到程序中,所以就用它了。
  • WebView2 需要先安装到本机,下载链接。

Vue

  • 直接操作 Dom 不够方便,Vue 用法跟 WPF 的绑定方式又很相似,使用 vue 来定义 pdf 的 Html 的模板,可以让不会 h5 的同事也能轻松写模板文件,所以这里用 Vue 来操作 Dom 和数据绑定。

Prism

  • WPF 项目常用的框架,我这里用来注册预览 PDF 的弹窗,以及给弹窗传参。

以打印一个表格为例

1. 定义要生成 PDF 的表格

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

c#`// BuyBookView.xaml
“1”
Margin=“24,0”
AutoGenerateColumns=“False”
FontSize=“16”
IsReadOnly=“True”
ItemsSource="{Binding Books}"
TextBlock.TextAlignment=“Center”>

“*”
Binding="{Binding Title}"
Header=“书名”
HeaderStyle="{StaticResource CenterGridHeaderStyle}" />
“100”
Binding="{Binding Author}"
Header=“作者”
HeaderStyle="{StaticResource CenterGridHeaderStyle}" />
“100”
Binding="{Binding Price}"
Header=“价格”
HeaderStyle="{StaticResource CenterGridHeaderStyle}" />

// BuyBookViewModel
public BuyBookViewModel(IDialogService dialogService)
{
Title = “鸭霸的购书目录”;
Books = new List
{
new()
{
Title = “JavaScript权威指南 原书第7版”,
Author = “巨佬1”,
Price = 90.3
},
new()
{
Title = “深入浅出node.js”,
Author = “巨佬2”,
Price = 57.8
},
new()
{
Title = “编码:隐匿在计算机软硬件背后的语言”,
Author = “巨佬3”,
Price = 89.00
}
};
}`

2. 定义预览 PDF 的弹窗

  • 在 xaml 中引入 WebView2
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

c#`// PrintPdfView.xml

xmlns:wpf=“clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf”

“24”>

“Auto” />

“webView2” />

“1”>
“save”
HorizontalAlignment=“Right”
Content=“保存” />`

  • 在 viewmodel 中定义弹窗接收的参数以及弹窗的属性
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

c#`// PrintPdfViewModel.cs
public class PrintPdfViewModel : BindableBase, IDialogAware
{
private string _template;
///
/// PDF 的 html 模板
///
public string Template
{
get => _template;
set => SetProperty(ref _template, value);
}

private ExpandoObject _data;
///
/// 传递给 pdf 的数据
///
public ExpandoObject Data
{
get => _data;
set => SetProperty(ref _data, value);
}

public void OnDialogOpened(IDialogParameters parameters)
{
// 弹窗接收 template 和 data 两个参数
parameters.TryGetValue(“template”, out _template);
parameters.TryGetValue(“data”, out _data);
}

public string Title => “预览 PDF”;
}`

3. 定义 WebView2 生成 PDF 的逻辑和 pdf 的模板文件

  • 使用 vue 来定义 pdf 模板的逻辑,和调用 WebView2.CoreWebView2.PrintToPdfAsync 来生成 PDF。
  • 因为客户端经常运行在内网或无网环境,所以这里就不用 cdn 引入 vuejs,而是直接将 vuejs 嵌入到客户端的资源文件中。
  • 调用 WebView2.CoreWebView2.PostWebMessageAsJson 从 WPF 向 WebView2 发送数据。
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

c#`// PrintPdfViewModel.xaml.cs
///
/// 配置 WebView2,加载 vuejs,加载 pdf 模板,传递数据到 html 中
///
///
private async Task Load()
{
await webView2.EnsureCoreWebView2Async();
webView2.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false; // 禁止右键菜单

var assembly = Assembly.GetExecutingAssembly();
var resourceName = “PrintPdf.Views.vue.global.js”;

using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream != null)
{
using var reader = new StreamReader(stream);
var vue = await reader.ReadToEndAsync();
await webView2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(vue); // 加载 vuejs
}

var vm = (PrintPdfViewModel)DataContext;

webView2.CoreWebView2.NavigateToString(vm.Template); // 加载 pdf 模板

webView2.CoreWebView2.NavigationCompleted += (sender, args) =>
{
var json = JsonSerializer.Serialize(vm.Data);
webView2.CoreWebView2.PostWebMessageAsJson(json); // 将数据传递到 html 中
};
}`

  • 点击保存时,选择路径并生成 PDF 文件。
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

c#`// PrintPdfViewModel.xaml.cs
save.Click += async (sender, args) =>
{
var saveFileDialog = new SaveFileDialog
{
Filter = “txt files (.pdf)|.pdf”,
RestoreDirectory = true,
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
FileName = $“test.pdf”
};
var result = saveFileDialog.ShowDialog();

if (result != true)
return;

var printSetting = webView2.CoreWebView2.Environment.CreatePrintSettings();
printSetting.ShouldPrintBackgrounds = true;

var saveResult = await webView2.CoreWebView2.PrintToPdfAsync($"{saveFileDialog.FileName}", printSetting);
};`

  • 定义 pdf 的打印模板,并且使用 Vue 来实现绑定功能,调用 webview.addEventListener 来监听 WPF 传递给 WebView2 的数据。
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

html`

... head>

{{title}} h3> div>

序号th> 书名th> 作者th> 价格th> tr> thead>
{{i+1}}th> {{item.Title}}td> {{item.Author}}td> {{item.Price}}td> tr> tbody> table> div> div> body>
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

c#`// BuyBookView.xaml
“{Binding ShowPrintViewCommand}” Content="预览 PDF1 " />

// BuyBookViewModel
ShowPrintViewCommand = new DelegateCommand(() =>
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = $“PrintPdf.ViewModels.test_print.html”;

using var stream = assembly.GetManifestResourceStream(resourceName); // 加载模板
if (stream == null) return;
using var reader = new StreamReader(stream);
var t = reader.ReadToEnd();
dynamic d = new ExpandoObject(); // 转换数据
d.title = Title;
d.books = Books;

var p = new DialogParameters
{
{“template”, t},
{“data”, d}
};
dialogService.ShowDialog(nameof(PrintPdfView), p, null);
});`

4. 效果

5. 优化一下

现在功能已经差不多了,但是 html 模板需要写的 js 太多,而且这是一个 WPF 控件,所以应该封装一下,最好用起来跟 wpf 一样才更好。
既然都用 vue 了,那就用 vue 封装一下组件。

  • vue 封装一下表格控件,并且暴露出属性 itemSource 和 columns
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

javascript// controls.js const DataGrid = { props: ["itemsSource", "columns"], template:

|
{{column.Header}}

{{item[column.Binding]}}
|

} const DocumentHeader = { props: ["title"], template:

{{title}}

};

  • 将 controls.js 注入到 WebView2 中
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

c#`var assembly = Assembly.GetExecutingAssembly();
var controlsFile = “PrintPdf.Views.controls.js”;

using var controlsStream = assembly.GetManifestResourceStream(controlsFile);

using var controlsReader = new StreamReader(controlsStream);
var controls = await controlsReader.ReadToEndAsync();
await webView2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(controls);`

  • 现在 html 模板中的 data-grid 组件就跟 WPF 的 DataGrid 控件很相似了
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

html`

... head>

document-header> data-grid> div> body>

function generate(data) {
Vue.createApp({
data() {
return {
title,columns,books
} = data;

},
components: {
DataGrid,
DocumentHeader
}
}).mount(’#app’);
}

script>
html>`

最后

觉得对你有帮助点个推荐或者留言交流一下呗!

源码 https://github.com/yijidao/blog/tree/master/WPF/PrintPdf

使用 WebView2 封装一个生成 PDF 的 WPF 控件相关推荐

  1. Qt 封装一个简单的LED(指示灯)控件

    Qt 封装一个简单的LED(指示灯)控件 1,效果~ 所以 这个简单的LED类可以自定义大小~ 可以点亮或熄灭,也可以闪烁

  2. 使用amaze ui的分页样式封装一个通用的JS分页控件

    作为一名码农,天天百度.偶尔谷歌,所有代码全靠copy,用第三方插件,偶尔也想着造造轮子,毕竟自己的骨肉总归比较亲. 今天有点空闲时间,想起我们公司之前套的页面的分页插件上还有bug,而写那个分页插件 ...

  3. react封装一个类似安卓的toast控件message

    项目中经常会用到类似安卓的toast的控件.封装一个这样的组件是每个项目必须的事情. import React from 'react'; import ReactDOM from 'react-do ...

  4. WPF控件开发之自定义控件(3)

    创建 UserControl 如前所述,在 WPF 中创建控件的最简单方法是从 UserControl 派生.下面的示例演示用于定义 NumericUpDownUserControl 的 用户界面 ( ...

  5. [转] 使用模板自定义 WPF 控件

      [转] 使用模板自定义 WPF 控件                                                                                 ...

  6. wpf控件设计时支持(3)

    wpf设计时调试 编辑模型 装饰器 1.wpf设计时调试 为了更好的了解wpf设计时框架,那么调试则非常重要,通过以下配置可以调试控件的设计时代码 (1)将启动项目配置成外部的visual studi ...

  7. Panuon.UI.Silver – 开源C# WPF控件库

    Panuon.UI.Silver – 开源C# WPF控件库 Dotnet9 • 2019年12月13日 22:55 • WPF • 阅读 12145 时间如流水,只能流去不流回! 点赞再看,养成习惯 ...

  8. 《Dotnet9》系列-开源C# WPF控件库2《Panuon.UI.Silver》强力推荐

    国内优秀的WPF开源控件库,Panuon.UI的优化版本.一个漂亮的.使用样式与附加属性的WPF UI控件库,值得向大家推荐使用与学习. 今天站长(Dotnet9,站长网址:https://dotne ...

  9. 第一章:初识WPF,XAML,WPF控件

    前言 总目录 本章主要介绍WPF与XAML,以及WPF的控件的基本使用,让大家先初步认识WPF. 关于WPF的官方资料:官方WPF文档1 .官方WPF文档2.官方WPF文档3.官方WPF文档4 一.W ...

  10. WPF控件开发之自定义控件(1)

    Windows Presentation Foundation (WPF) 控件模型的扩展性极大减少了创建新控件的需要.但在某些情况下,仍可能需要创建自定义控件.本主题讨论可最大限度减少在 Windo ...

最新文章

  1. vb matlab 比较,【笔记】VB.NET和MATLAB读取二进制文件(中文+数值)之比较
  2. TCP/IP详解--学习笔记(7)-广播和多播,IGMP协议
  3. 计算机中,文本文件和二进制文件的区别
  4. mariadb mysql 5.6_MySQL / MariaDB 5.5 升级到 MySQL 5.6
  5. 使用基于列表的表单控件
  6. FAILOVER详细步骤
  7. android 距离感应器控制屏幕熄灭_书房大变身!有格调的屏幕挂灯,加了它桌面秒变神仙颜值...
  8. Win7 便签设置字体方法
  9. C++在windows下获得运行主机的硬件信息:CPU序列号、MAC地址、硬盘序列号、主板序列号
  10. MySQL练习题 (练习表+题目+答案)
  11. 高德地图自定义主题地图,盖住中国红色边境线
  12. 天力卓越消息服务器是什么意思,开票版药易通出现RPC服务器不可用是什么问 – 手机爱问...
  13. SCC(三):HEVC IBC
  14. 斯坦福的《机器学习》课程上线了
  15. [编程题]:n头牛中选择满足所有m种特性的牛(百度2021)
  16. 小ck活动机器人包包_你一定要入手的小ck包
  17. 数量乘以单价的公式计算机,“excel公式大全详解“单价乘以数量 然后累加的公式 EXCEL...
  18. 基于Node.js的图书管理系统
  19. 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一1.8 侧光拍摄增强轮廓感
  20. 大数据导论习题_2020智慧树答案 大数据概论 最新知到章节测试答案

热门文章

  1. Ascii完整码表(256个)
  2. 【平面设计学习】Ai使用心得-扁平化制作
  3. c语言关键字及其含义,C语言关键字解析
  4. android随机摇号代码,抽奖摇号系统随机性算法介绍
  5. RAIM: A Reverse Auction-based Incentive Mechanism for Mobile Data Offloading through Opportunistic
  6. cad细等线体不显示_cad字体cass cass如何修改字体
  7. 学习信号与系统的看过来~~
  8. ryujinx模拟器linux安装教学,switch模拟器Ryujinx
  9. 工作流集成表单的过程
  10. java技术可行性分析_Java可行性分析