混合编程须知
前端JS能调用Foxtable的所有内置功能,但并不是所有的功能都适合用前端JS代码实现,首先是编写起来不如用Foxtable原生代码方便,其次性能差距也很明显。
此外通过第三方库实现的功能,例如专业报表、PDFCreator、WordCreator等等,暂时无法通过前端JS代码来实现。
所以一般采用混合编程的方式,相对简单的或对性能要求不高的可以直接用JS代码实现,反之则用Foxtable原生代码实现。
由于WebViewer运行在独立的进程中,所以混合编程必须遵循一个原则:
当前端js代码调用Foxtable原生代码时,包括运行WebViewer的事件代码时,都不可长时间阻塞进程,否则系统很快会崩溃
这就导致一个问题,Foxtable端的原生代码免不了使用对话框和模式窗口,也免不了出现耗时很长的运算,而这些都会阻塞进程的,所以需要做一些特别的处理。
使用窗口
如果要在前端js脚本(包括WebViewer本身的事件代码)中打开使用Foxtable的窗口,不能用Open方法打开。
窗口必须用OpenAsync方法打开,例如:
ft.Forms["窗口1"].OpenAsync();
如果要在WebViewer的事件或任何通过js调用的Foxtable生代码中使用窗口,同样必须用OpenAsync打开:
Forms("窗口1").OpenAsync()
注意以用OpenAsync方法打开的模式窗口,并不会阻塞进程,后续代码会继续正常执行。
如果后面的代码必须等模式窗口关闭才能执行,请加上Await:
Await
Forms("窗口1").OpenAsync()
使用对话框
Foxtable内置了6个对话框,这些对话框都是模式窗口。
前端脚本可以直接使用Foxtable的对话框,前面在《使用对话框》这一章进行了详细的介绍,参考:关于对话框
如果要在前端js脚本调用的原生代码(包括WebViewer本身的事件代码)中使用这些对话框,请使用这些对话框的异步类,分别为:
MessageBoxA
FontDialgA
ColorDialogA
OpenFileDialogA
SaveFileDialogA
FolderBrowserDialogA
异步对话框的名称就是原名称的后面加上一个字母"A"。
使用异步对话框同样必须加上Await,例如:
If
Await
MessageBoxA.Show("Foxtable很强大,你同意吗?"
,
"提示",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes
Then
Await
MessageBoxA.Show("很开心,谢谢您的认同!")
Else
Await
MessageBoxA.Show("看来我们还需要努力")
End
If
再例如:
Dim
dlg
As
New
OpenFileDialogA()
dlg.Filter =
"Excel文件|*.xls|Word文件|*.doc|Access文件|*.mdb"
If
Await
dlg.ShowDialog = DialogResult.Ok
Then
MessageBoxA.Show("你选择的是:"
& dlg.FileName,
"提示")
End
If
关于异步对话框的更多内容,请参考:异步对话框
使用异步函数
既然不能阻塞进程,那么前端脚本调用Foxtable的自定义函数时,如果函数比较耗时,必须采用异步方式执行,也就是用ExecueAsync(注意不要和以前的AsyncExecute混淆了)方法执行自定义函数。
异步函数中如果要使用到对话框,则必须使用异步对话框,请参考:异步对话框
异步函数中如果使用到窗口,则必须用OpenAsync方法打开,请参考:异步函数与窗口
异步函数中如果涉及到其他UI,或者需要写入数据,必须回到UI线程同步执行,请参考:插入同步代码
使用常规按钮封装
因为异步函数默认是在独立的线程中运行,所以我个人更倾向于使用常规按钮封装代码。
我们知道按钮有个PerformClick方法,可以用于模拟单击这个按钮,参考:PerformClick
在前端脚本中可以通过下面的js代码模拟单击某个常规按钮:
ft.Forms["窗口名"].Controls["按钮名"].PerformClick();
按钮代码本身就是在UI线程同步执行的,所以按道理在使用窗口、对话框和写入数据方面是没有任何顾忌的,但不要忘记一个原则:不能长时间阻塞进程。
所以按钮代码中的对话框,必须用异步对话框。
所以按钮代码打开模式窗口的时候,必须用OpenAsync打开。
所以按钮代码如果相当耗时,那么应该将耗时的部分提取出来,封装成一个函数异步执行。
此外建议将第一行设置为:
Await Task.Delay(0)
这行代码的作用是将控制权临时释放给调用者,也就是WebViewer,能大幅减少因为长时间阻塞进程而导致系统崩溃的概率。
代码封装方式示例
我们在文件"CaseStudy\WebViewer\调用Foxtable对象.Table"提供了几个例子,用于演示混合开发时三种典型的代码封装方式。
这几个例子(窗口)完成的任务是完全相同的,通过HTML页面输入数据条件,由Foxtable负责筛选出数据并生成PDF文件:
1、窗口"用函数生成PDF"将所有代码封装在一个异步函数中。
2、窗口"用按钮生成PDF"将所有代码封装在一个常规按钮中,这个例子也演示了如何通过Var变量在前端和Foxtable之间传递数据,参考:用按钮代替函数
3、窗口"用按钮和函数生成PDF"将生成PDF的代码封装一个异步函数中,将保存PDF的代码放在一个常规按钮中:
'''Async
Dim
pdc
As
PDFCreator =
Await
Functions.ExecuteAsync("CreatePDFAsync2")
'用异步函数生成PDF
If
pdc
IsNot
Nothing
Then
'生成完成后保存PDF文件,注意用的是异步对话框
Dim
dlg
As
New
SaveFileDialogA()
dlg.Filter =
"PDF文件|*.pdf"
If
Await
dlg.ShowDialog() = DialogResult.OK
Then
pdc.Save(dlg.FileName)
'保存文件
Process.Start(dlg.FileName)
'打开文件
End
If
End
If
重要提示:
异步编程是这样的,你不遵循规范,也不见得会出问题,但是今天不出问题,明天可能出问题,这台电脑没问题,换台电脑可能有问题,所以还是尽可能遵循规范的好。