【WPF】学习笔记(二)——依旧是一个电子签名板

这篇博客呢,主要谈谈在实现电子签名功能中踩过的几个坑:1.System.BadImageFormatException异常;2.无法加载DLL“###.dll”,: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E);3.wpf获取控件句柄。

如果你想了解如何在wpf中使用InkCanvas实现一个类似于签名板(涂鸦板系列)的功能,请参考我的上一篇博客

再扯点题外话,写这篇博客的很大一部分原因是InkCanvas版本的签名板被否决了。究其原因呢,是这个签名板将用于触摸屏上的用户签名,而InkCanvas版本在触摸屏上手写签名的体验可以用糟糕来形容。所以呢,最终采用了另一个解决方案:调用一个C++的dll(这个dll是公司提供的,而且有WinForm版的Demo,我只需要正确的“搬砖”就好了),通过电子签名笔来完成签名。

闲话扯完了,现在我们来聊聊那几个问题:

1.System.BadImageFormatException异常

【WPF】学习笔记(二)——依旧是一个电子签名板

这个异常是我在尝试编译WinForm版Demo的时候触发的,网上搜索了一下,在一篇博客中找到了原因——目标程序的目标平台与某一依赖项的目标编译平台不一致。于是我将相关工程的目标平台都更改为x86,问题就解决了。下方提供一个修改目标平台的示例:

【WPF】学习笔记(二)——依旧是一个电子签名板

【WPF】学习笔记(二)——依旧是一个电子签名板

大致修改过程:在工程上右键 => 属性 => 编译 => 目标平台

2.无法加载DLL“###.dll”,: 找不到指定的模块

隐约记得很久以前遇上过这个问题,但忘了具体怎么处理的了。所以上网搜索了一下,关于这个问题的帖子不少,但都大同小异……大体上都说将dll手动拷贝到项目文件夹中bin目录下;将dll拷贝到system32目录下;还有一个感觉看起来十分高大上的解决方法,个人就没什么兴趣看了。拜托!在我的记忆中,这不应该是件很麻烦的事情啊,而且现在的VS这么强大,还需要手动去搞这种事情??最终决定自己摸索,也终于找到了解决方法。

【WPF】学习笔记(二)——依旧是一个电子签名板

【WPF】学习笔记(二)——依旧是一个电子签名板

相信到这里各位都看出问题了吧——dll的Copy to Output Directory(复制到输出目录)这一项默认选的是永不复制!!搞骚,吓得我赶紧修改成Copy if newer(如果更新就会重新复制一份到输出目录,如果你想选始终复制Copy always我也不拦着),然后这个问题就没有然后了。当然,有可能我遇上的问题比较简单,这个解决方案可能对某些情况不适用,各位可以在博客下方留言,我们一起讨论。

3. wpf获取控件句柄

由于在调用C++的dll完成签名板功能时,需要把签名板的句柄作为参数传递过去,所以我在此把这个地方拿出来谈一谈。

网上关于wpf获取控件句柄的帖子也不少,但恕我直言,大都是在扯淡~

比如说下方截图:

【WPF】学习笔记(二)——依旧是一个电子签名板

容我先按照这个方法测试一票:

【WPF】学习笔记(二)——依旧是一个电子签名板

我们发现,这两个方法拿到的句柄一毛一样……

听老司机说,wpf的控件是画出来的,不会为每个控件分配句柄,所以通过这个方法拿到的所谓的控件的句柄,实际上是整个窗体的句柄。而我们的需求是要切切实实的拿到对应控件的句柄,所以,就只能想办法借助winform了。

接下来,我们来看看具体步骤:

1)添加两个引用(System.Windows.Forms 和 WindowsFormsIntegration)

【WPF】学习笔记(二)——依旧是一个电子签名板

【WPF】学习笔记(二)——依旧是一个电子签名板

为了相对快速找到这两个库,我搜索了关键字“windows”

2)XAML

A.引入命名空间

xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

B.控件调用

<wfi:WindowsFormsHost Width="500" Height="240" Background="White">
<wf:Panel x:Name="panelSignature"/>
</wfi:WindowsFormsHost>

C.说明

a.有细心的童鞋会发现,WindowsFormHost的前方不必使用WindowsFormsIntegration对应的名称(我给的名称是wfi,各位请随意)进行限制,XAML中只导入System.Windows.Forms的命名空间也是可以的,但为了更清楚WindowsFormHost的来历(在哪个程序集的哪个命名空间下),我比较推荐将命名空间导入的写法。

b.可能有童鞋在添加引用之后就着手于Xaml的编码工作,然后发现VS不能正确的进行智能提示。我建议添加引用后Build(编译)一下,以便让编译器知道已经导入了新的dll,而后智能提示就可以正常运作了。

3)逻辑代码

var hwnd = panelSignature.Handle;

WinForm这边获取控件的句柄是很简单的,就这么一行代码就可以了。看看效果:

【WPF】学习笔记(二)——依旧是一个电子签名板

嗯~不一样,不一样就对了O(∩_∩)O

4.扯淡时间

完成签名板这个任务花了两天时间,第一天写出了InkCanvas版本,第二天完成了目前公司采用的这个版本。先来张测试截图:

【WPF】学习笔记(二)——依旧是一个电子签名板

有童鞋可能会问:怎么不写“测试”二字,亦或是“Hello World”……我表示当时完成这个功能的时候相当激动,颤抖的手握着电子签字笔就写下这么一行,然后截图发给心目中的女神了……那天晚上离开公司的时候大雨瓢泼,我的心头却晴空万里(●'◡'●)

最后祝各位劳动节快乐,相信每一份努力都不会被辜负!!

上一篇:Windows server 2008 R2 多用户远程桌面配置详解(超过两个用户)


下一篇:Qt软件打包与发布(windeployqt工具)