经过一点点的业余加班努力,终于实现了客户端跨平台完全体。客户端可以调用打印,调用打印预览,调用打印生成PDF,调用Excel导出。windows下可以驱动模板设计器等。除了摄像头调用部分和监听程序接口部分全部实现。摄像头和监听接口目前还涉及不到linux运行。普通用户正常使用的功能是完事了。主要难度在打印预览实现上。
老winform预览,是打开winform界面做展示预览的,预览逻辑还不少,完全要做界面和服务分离。
//如果是预览
if (printFlag == "PrintPreviewOld" || printFlag == "PrintPreview")
{
PrintPreview.Document = pdDocument;
PrintPreview.ShowPrinterSettingsBeforePrint = false;
PrintPreview.ShowPrinterSettingsButton = true;
PrintPreview.ShowPageSettingsButton = true;
PrintPreview.PrintPreviewControl.Zoom = 1;
PrintPreview.WindowState = FormWindowState.Maximized;
PrintPreview.ShowDialog();
//确定打印
if (PrintPreview.printDialogResult == DialogResult.Yes)
{
PrinterSettings setting = pdDocument.PrinterSettings;
pdDocument = new PrintDocument();
pdDocument.PrinterSettings = setting;
iRow = 0;
startPage = 0;
//订阅BeginPrint事件
pdDocument.BeginPrint += new PrintEventHandler(pdDocument_BeginPrint);
//定义打印内容
pdDocument.PrintPage += new PrintPageEventHandler(OnPrintPage);
//訂閱EndPrint事件,释放资源
pdDocument.EndPrint += new PrintEventHandler(pdDocument_EndPrint);
//打印
PrintProxy();
string state = GetPrintState();
if (state != "")
{
if (shouldShowErr)
{
FrmInfo frminfo = new FrmInfo();
frminfo.Info = "打印机处于错误状态";
frminfo.CoderInfo = state;
frminfo.ShowDialog();
WriteLog(state);
}
else
{
errInfo += state;
WriteLog(errInfo);
}
return;
}
}
//确定打印
else if (PrintPreview.printDialogResult == DialogResult.OK)
{
//pdDocument = new PrintDocument();
iRow = 0;
startPage = 0;
int curPage = 0;
//当前页开始
int preStart = 0;
pintPoints.Clear();
//循环绘制每行数据
for (int i = iRow; i < namesTable.Rows.Count; i++)
{
if (PrintPreview.CurPage >= 0)
{
if (curPage == PrintPreview.CurPage + 1)
{
break;
}
}
//取出当前行数据
DataRow dr = namesTable.Rows[i];
//打印类型
string PrintType = dr["PrintType"].ToString();
//换页
if (PrintType == "PAGE" || (i == (namesTable.Rows.Count - 1)))
{
if (curPage < PrintPreview.CurPage)
{
iRow = i + 1;
}
else
{
endRow = i + 1;
}
curPage++;
//打印奇数页
if (PrintPreview.CurPage == -1)
{
if (curPage % 2 != 0)
{
if (PrintPreview.RangeStart > 0 && PrintPreview.RangeEnd > 0)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Add(new Point(preStart, i));
}
}
else
{
pintPoints.Add(new Point(preStart, i));
}
}
}
//打印偶数页
else if (PrintPreview.CurPage == -2)
{
if (curPage % 2 == 0)
{
if (PrintPreview.RangeStart > 0 && PrintPreview.RangeEnd > 0)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Add(new Point(preStart, i));
}
}
else
{
pintPoints.Add(new Point(preStart, i));
}
}
}
//打印偶数页逆序
else if (PrintPreview.CurPage == -3)
{
if (curPage % 2 == 0)
{
if (PrintPreview.RangeStart > 0 && PrintPreview.RangeEnd > 0)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Insert(0, new Point(preStart, i));
}
}
else
{
pintPoints.Insert(0, new Point(preStart, i));
}
}
}
//范围打印
else if (PrintPreview.CurPage == -4)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Add(new Point(preStart, i));
}
}
//当前页开始位置
preStart = i + 1;
}
}
//订阅BeginPrint事件
pdDocument.BeginPrint += new PrintEventHandler(pdDocument_BeginPrint);
//定义打印内容
pdDocument.PrintPage += new PrintPageEventHandler(OnPrintPage);
//訂閱EndPrint事件,释放资源
pdDocument.EndPrint += new PrintEventHandler(pdDocument_EndPrint);
//打印
PrintProxy();
string state = GetPrintState();
if (state != "")
{
if (shouldShowErr)
{
FrmInfo frminfo = new FrmInfo();
frminfo.Info = "打印机处于错误状态";
frminfo.CoderInfo = state;
frminfo.ShowDialog();
WriteLog(state);
}
else
{
errInfo += state;
WriteLog(errInfo);
}
return;
}
}
}
先抽取界面数据共性,用来在UI和服务传输数据,需要展示预览界面时候服务端给UI发消息,UI展示界面,把用户选择组装消息发回给服务端。在用户确认之前服务端处于线程等待状态。
///
/// 打印预览返回实体
///
public class PrintPreViewRetDto
{
///
/// 选择结果
///
public string printDialogResult
{
get;
set;
}
///
/// 当前页
///
public int CurPage
{
get;
set;
}
///
/// 范围开始
///
public int RangeStart
{
get;
set;
}
///
/// 范围结束
///
public int RangeEnd
{
get;
set;
}
}
对接UI层实现,打印抽象接口
///
/// 操作打印的接口外壳
///
public interface IOperPrintShell
{
///
/// 显示运用程序信息
///
///
///
void ShowAppInfo(string info, string coderInfo);
///
/// 显示弹窗消息
///
///
///
void ShowMsgInfo(string info,string title="");
///
/// 保存文件对话框
///
///
///
string SaveFileDialog(string Filter);
///
/// 选择文件夹对话框
///
///
///
string SaveDirDialog(string Title);
///
/// 显示打印预览
///
/// 图片Base64串JSON文件
///
PrintPreViewRetDto ShowPrintPreview(string imageJsonName);
}
打印界面接口实现
using DHCLabtrakReportPrint;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LISClientMsgDeal
{
///
/// 操作打印的壳
///
public class OperPrintShell : DHCLabtrakReportPrint.IOperPrintShell
{
///
/// 显示消息框
///
/// 标题
/// 消息
/// 按钮名称
///
public string ShowMsgDialog(string title, string msg, string buttonNames)
{
if (MessageServer.UIOper != null)
{
return MessageServer.UIOper.ShowMsgDialog(title, msg, buttonNames);
}
Console.WriteLine(title+":"+ msg);
return "0";
}
///
/// 从多个文件选一个弹窗
///
/// 用|分割的多个名称
///
public string SelectFileDialog(string selectStr)
{
if (MessageServer.UIOper != null)
{
return MessageServer.UIOper.ShowSelectTmpFileDialog(selectStr);
}
Console.WriteLine("没有UI,默认选择第一个:");
string path = selectStr.Split('|')[0];
return path;
}
///
/// 保存文件对话框
///
///
///
public string SaveFileDialog(string Filter)
{
if(MessageServer.UIOper != null)
{
return MessageServer.UIOper.ShowSaveFileDialog("保存文件","", Filter);
}
Console.WriteLine("请输入要保存的路径:");
string path = Console.ReadLine();
return path;
}
///
/// 显示App信息
///
///
///
public void ShowAppInfo(string info, string coderInfo)
{
string head = DateTime.Now.ToString("hh:mm:ss") + "#";
Console.WriteLine(head + info);
Console.WriteLine(head + coderInfo);
}
///
/// 显示消息
///
///
///
public void ShowMsgInfo(string info, string title = "")
{
if (MessageServer.UIOper != null)
{
MessageServer.UIOper.ShowMsgDialog(title, info, "确定");
}
string head = DateTime.Now.ToString("hh:mm:ss") + "#" + title;
Console.WriteLine(head + info);
}
///
/// 选择文件夹对话框
///
///
///
public string SaveDirDialog(string Title)
{
if (MessageServer.UIOper != null)
{
return MessageServer.UIOper.ShowSaveDirDialog("选择要保存的路径","");
}
Console.WriteLine("请输入要保存的路径:");
string path = Console.ReadLine();
return path;
}
///
/// 显示打印预览
///
/// 图片Base64串JSON文件
///
public PrintPreViewRetDto ShowPrintPreview(string imageJsonName)
{
if (MessageServer.UIOper != null)
{
return MessageServer.UIOper.ShowPrintPreview(imageJsonName);
}
string head = DateTime.Now.ToString("hh:mm:ss") + "#" + imageJsonName;
Console.WriteLine(head);
PrintPreViewRetDto ret = new PrintPreViewRetDto();
ret.printDialogResult = "Yes";
ret.CurPage = 0;
ret.RangeStart = -1;
ret.RangeEnd = -1;
return ret;
}
}
}
和electron的UI交互层
using DHCLabtrakReportPrint;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LISClientMsgDeal
{
public class UIOperElectron : IUIOperInterface
{
///
/// 连接,通过该连接和UI通信
///
public LIS.IWebSocketConnection Socket
{
get;
set;
}
///
/// 消息ID
///
private static int id = 0;
///
/// 显示消息框
///
/// 标题
/// 消息
/// 按钮名称
///
public string ShowMsgDialog(string title,string msg,string buttonNames)
{
if(buttonNames=="")
{
buttonNames = "确定|取消";
}
UIMsgDto dto = new UIMsgDto();
dto.Type = "MsgDialog";
dto.NeedRet = true;
dto.Paras = new List<string>();
dto.Paras.Add(title);
dto.Paras.Add(msg);
dto.Paras.Add(buttonNames);
//会阻塞等待返回
UIMsgDto ret = SenMsgAndWait(dto);
if (ret != null)
{
if (ret.RetParas != null && ret.RetParas.Count > 0)
{
return ret.RetParas[0];
}
}
return "";
}
///
/// 显示选择文件对话框
///
///
///
public string ShowSelectTmpFileDialog(string selectStr)
{
UIMsgDto dto = new UIMsgDto();
dto.Type = "SelectTmpFileDialog";
dto.NeedRet = true;
dto.Paras = new List<string>();
dto.Paras.Add(selectStr);
//会阻塞等待返回
UIMsgDto ret = SenMsgAndWait(dto);
if (ret != null)
{
if (ret.RetParas != null && ret.RetParas.Count > 0)
{
return ret.RetParas[0];
}
}
return "";
}
///
/// 显示保存文件对话框
///
/// 对话框标题
/// 默认路径
/// 筛选:"Image Files (*.jpg;*.png)|*.jpg;*.png"
/// 没选择就返回空,选择了就返回路径
public string ShowSaveFileDialog(string title, string defaultPath, string filter)
{
UIMsgDto dto = new UIMsgDto();
dto.Type = "SaveFileDialog";
dto.NeedRet = true;
dto.Paras = new List<string>();
dto.Paras.Add(title);
dto.Paras.Add(defaultPath);
dto.Paras.Add(filter);
//会阻塞等待返回
UIMsgDto ret = SenMsgAndWait(dto);
if(ret!=null)
{
if(ret.RetParas!=null&& ret.RetParas.Count>0)
{
return ret.RetParas[0];
}
}
return "";
}
///
/// 显示选择文件夹对话框
///
/// 对话框标题
/// 默认路径
/// 没选择就返回空,选择了就返回路径
public string ShowSaveDirDialog(string title, string defaultPath)
{
UIMsgDto dto = new UIMsgDto();
dto.Type = "SaveDirDialog";
dto.NeedRet = true;
dto.Paras = new List<string>();
dto.Paras.Add(title);
dto.Paras.Add(defaultPath);
//会阻塞等待返回
UIMsgDto ret = SenMsgAndWait(dto);
if (ret != null)
{
if (ret.RetParas != null && ret.RetParas.Count > 0)
{
return ret.RetParas[0];
}
}
return "";
}
///
/// 显示打印预览
///
/// 图片Base64串JSON文件
///
public PrintPreViewRetDto ShowPrintPreview(string imageJsonName)
{
UIMsgDto dto = new UIMsgDto();
dto.Type = "PrintPreView";
dto.NeedRet = true;
dto.Paras = new List<string>();
dto.Paras.Add(imageJsonName);
PrintPreViewRetDto retDto = new PrintPreViewRetDto();
//会阻塞等待返回
UIMsgDto ret = SenMsgAndWait(dto);
if (ret != null)
{
if (ret.RetParas != null && ret.RetParas.Count > 0)
{
retDto.printDialogResult = ret.RetParas[0];
retDto.CurPage = Convert.ToInt32(ret.RetParas[1]);
if(ret.RetParas[2]!="")
{
retDto.RangeStart = Convert.ToInt32(ret.RetParas[2]);
}
if(ret.RetParas[3]!="")
{
retDto.RangeEnd = Convert.ToInt32(ret.RetParas[3]);
}
return retDto;
}
}
retDto.printDialogResult = "Yes";
retDto.CurPage = 0;
retDto.RangeStart = -1;
retDto.RangeEnd = -1;
return retDto;
}
///
/// 发送消息并且等待返回值
///
/// 消息实体
/// 返回结果
private UIMsgDto SenMsgAndWait(UIMsgDto dto)
{
dto.MsgID = id.ToString();
id++;
string msgStr = JsonConvert.SerializeObject(dto);
if(Socket!=null)
{
Socket.Send(msgStr);
if(dto.NeedRet==true)
{
//注册等待
UIMessageDeal.WaitReg(Socket.ConnectionInfo.Id.ToString(), dto);
int waiteNum = 0;
while (true)
{
UIMsgDto ret=UIMessageDeal.GetUIMsgRet(dto.MsgID);
if(ret!=null)
{
return ret;
}
else
{
System.Threading.Thread.Sleep(200);
}
waiteNum++;
if(waiteNum>40000)
{
break;
}
}
}
}
return null;
}
}
}
界面electron对接层JS,处理服务发来的界面展示消息
//处理服务端后台的消息
function DealMsgServer(data) {
//保存文件对话框
if (data.Type == "SaveFileDialog") {
var filters = [];
if (data.Paras[2] != "") {
var arr = data.Paras[2].split('|');
for (var i = 0; i < arr.length; i += 2) {
var one = { name: arr[i], extensions: [arr[i + 1].split(".")[1]] };
filters.push(one);
}
}
dialog.showSaveDialog({
title: data.Paras[0],
defaultPath: data.Paras[1],
filters: filters
}).then(result => {
data.RetParas = [];
data.RetParas.push(result.filePath);
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}).catch(err => {
console.log(err)
});
}
//选择路径对话框
else if (data.Type == "SaveDirDialog") {
dialog.showOpenDialog(mainWindow, {
properties: ['openDirectory']
}).then(result => {
data.RetParas = result.filePaths;
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}).catch(err => {
console.log(err)
});
}
//选择模板文件对话框,多选一
else if (data.Type == "SelectTmpFileDialog") {
var path = data.Paras[0];
var pathArr = path.split('|');
var buttons = [];
for (var i = 0; i < pathArr.length; i++) {
var oneArr = pathArr[i].split("/");
buttons.push(oneArr[oneArr.length-1]);
}
var choice = dialog.showMessageBoxSync(mainWindow, {
type: "info",
buttons: buttons,
title: "选择模板对话框",
message: "请选择要使用的导出模板",
defaultId: -1,
cancelId: -1
});
//执行菜单逻辑
if (choice >= 0) {
data.RetParas = [];
data.RetParas.push(pathArr[choice]);
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}
else {
data.RetParas = [];
data.RetParas.push("");
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}
}
//选择模板文件对话框,多选一
else if (data.Type == "MsgDialog") {
var title = data.Paras[0];
var msg = data.Paras[1];
var buttonStr = data.Paras[2];
var nameArr = buttonStr.split('|');
var buttons = [];
for (var i = 0; i < nameArr.length; i++) {
buttons.push(nameArr[i]);
}
var choice = dialog.showMessageBoxSync(mainWindow, {
type: "info",
buttons: buttons,
title: title,
message: msg,
defaultId: -1,
cancelId: -1
});
data.RetParas = [];
data.RetParas.push(choice);
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}
//打印预览对话框
else if (data.Type == "PrintPreView") {
var JSONPath = data.Paras[0];
//创建新的窗口
var printViewWindow = new BrowserWindow({
skipTaskbar: false,
icon: __dirname + dirSplit + 'lis.ico',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
//最大化
printViewWindow.maximize();
printViewWindow.loadFile('main/form/frmPrintView.html', { search: "Json=" + "http://127.0.0.1:8085/UI/" + JSONPath +"&MsgID="+data.MsgID });
}
}
主进程打开预览界面后接收渲染进程消息
//接收渲染进程消息
ipcMain.on('printview', (event, msgData) => {
console.log(msgData);
if (msgData.Type == "PrintPreView") {
console.log("UI->S", "uimsg#" + JSON.stringify(msgData));
ws.send("uimsg#" + JSON.stringify(msgData));
}
});
预览界面,把用户选择通过消息发送给主进程,主进程再发送给服务端的websockt让服务端接着执行逻辑
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>打印预览</title>
<script type="text/javascript">
const ipcRenderer = require('electron').ipcRenderer;
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script src="../../resource/common/js/lis-commonHISUI.js" type="text/javascript"></script>
<style type="text/css">
.ar {
text-align: right;
padding-right: 8px;
}
.ar6 {
text-align: right;
padding-right: 6px;
}
.al {
text-align: left;
padding-right: 10px;
}
.sp {
display: inline-block;
width: 15px;
}
.sp4 {
display: inline-block;
width: 4px;
}
.sp6 {
display: inline-block;
width: 6px;
}
.sp10 {
display: inline-block;
width: 10px;
}
.sp20 {
display: inline-block;
width: 20px;
}
</style>
<script type="text/javascript">
//得到传入的Json路径
var Json = requestUrlParam(location.href, "Json").replace("#", "");
var MsgID = requestUrlParam(location.href, "MsgID").replace("#", "");
//document.write('');
var Align = requestUrlParam(location.href, "Align").replace("#", "");
$(function () {
if (Align == "Left") {
$("#divOper").css("margin", "0 0 0 0");
$("#divMian").css("margin", "0 0 0 0");
}
var CurPage = 0;
var printDialogResult = "";
var RangeStart = "";
var RangeEnd = "";
//默认第一页
$("#txtCurPage").val("1");
//打印当前页
$("#btnPrintCur").click(function () {
printDialogResult = "Ok";
SendMsg();
});
//打印全部
$("#btnPrintAll").click(function () {
printDialogResult = "Yes";
SendMsg();
});
//关闭
$("#btnClose").click(function () {
printDialogResult = "Cancel";
});
//打印奇数页
$("#btnPrintOdd").click(function () {
printDialogResult = "OK";
CurPage = -1;
SendMsg();
});
//打印偶数页
$("#btnPrintEven").click(function () {
printDialogResult = "OK";
CurPage = -2;
SendMsg();
});
//偶逆序
$("#btnPrintEvenRevert").click(function () {
printDialogResult = "OK";
CurPage = -3;
SendMsg();
});
//范围打印
$("#btnPrintRange").click(function () {
printDialogResult = "OK";
RangeStart = $("#txtRangeStart").val();
RangeEnd = $("#txtRangeEnd").val();
SendMsg();
});
//上一页
$("#btnPrev").click(function () {
CurPage--;
if (CurPage < 0) {
CurPage = 0;
}
$("#txtCurPage").val(CurPage+1);
DrawPage();
});
//下一页
$("#btnNext").click(function () {
CurPage++;
if (CurPage == MaxPageIndex) {
CurPage = MaxPageIndex - 1;
}
$("#txtCurPage").val(CurPage+1);
DrawPage();
});
if (Json == "") {
$("#spPage").html("没按要求传入Json!");
return;
}
var imgStr = '';
$.ajax({
type: "get",
dataType: "json", //text, json, xml
cache: false, //
async: false, //为true时,异步,不等待后台返回值,为false时强制等待;-asir
url: Json,
success: function (imageArr) {
for (var i = 0; i < imageArr.length; i++) {
if (i > 0) {
imgStr += '第' + (i + 1) + '页+ "data:image/png;base64," + imageArr[i] + '" alt="报告" style="margin-bottom:10px;"/>';
}
else {
imgStr += '+ "data:image/png;base64," + imageArr[i] + '" alt="报告" style="margin-bottom:10px;"/>';
}
}
$("#spPage").html("当前报告共(" + imageArr.length + ")页");
$("#divMian").html(imgStr);
}
});
//组装消息
function SendMsg() {
var msg = {};
msg.CurPage = CurPage;
msg.printDialogResult = printDialogResult;
msg.RangeStart = RangeStart;
msg.RangeEnd = RangeEnd;
msg.MsgID = MsgID;
msg.Type = "PrintPreView";
msg.NeedRet = true;
msg.Paras = "";
msg.RetParas = [printDialogResult, CurPage, RangeStart, RangeEnd];
ipcRenderer.send('printview', msg);
window.close();
}
//绘制当前页
function DrawPage() {
$("#divMian").html('+ "data:image/png;base64," + imageArr[CurPage] + '" alt="报告" style="margin-bottom:10px;"/>');
}
});
</script>
</head>
<body>
<div id="divOper" style="margin:auto auto;width: 100%;background-color:#F5F5F5; text-align: center; padding: 5px;">
<a id="btnPrintCur" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">打印当前页</a>
<a id="btnPrintAll" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">打印全部</a>
<a id="btnClose" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">关闭</a>
<a id="btnPrintOdd" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">打印奇数页</a>
<a id="btnPrintEven" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">打印偶数页</a>
<a id="btnPrintEvenRevert" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">偶逆序</a>
<input id="txtRangeStart" type="text" style="width:30px" class="hisui-validatebox" />
-
<input id="txtRangeEnd" type="text" style="width:30px" class="hisui-validatebox" />
<a id="btnPrintRange" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">范围打印</a>
<span id="spPage" style="font-weight: bold; color: #ff5252; font-size: 14px;"></span>
<input id="txtCurPage" type="text" style="width:30px" class="hisui-validatebox" />
<a id="btnPrev" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">上一页</a>
<a id="btnNext" href="#" class="hisui-linkbutton" data-options="iconCls:'icon-print',plain:true" style="margin-left:10px;">下一页</a>
<span style="font-weight: bold; color: #AAAAAA; font-size: 14px;float:right;margin-right:10px;">打印预览</span>
</div>
<div id="divMian" style="margin: auto auto; width: 850px; background-color: #DDDDDD; text-align: center; padding-top: 10px;"></div>
</body>
</html>
原来winform打印预览代码调整,原来的打印预览弹窗改为PrintPreViewRetDto PrintPreview = Shell.ShowPrintPreview(jsonFile);驱动electron的ui。
//如果是预览
if (printFlag == "PrintPreviewOld" || printFlag == "PrintPreview")
{
//得到打印预览的图片JSON
string jsonFile=GetImageJsonFile();
//显示打印预览
PrintPreViewRetDto PrintPreview = Shell.ShowPrintPreview(jsonFile);
//确定打印
if (PrintPreview.printDialogResult == "Yes")
{
PrinterSettings setting = pdDocument.PrinterSettings;
pdDocument = new PrintDocument();
pdDocument.PrinterSettings = setting;
iRow = 0;
startPage = 0;
//订阅BeginPrint事件
pdDocument.BeginPrint += new PrintEventHandler(pdDocument_BeginPrint);
//定义打印内容
pdDocument.PrintPage += new PrintPageEventHandler(OnPrintPage);
//訂閱EndPrint事件,释放资源
pdDocument.EndPrint += new PrintEventHandler(pdDocument_EndPrint);
//打印
PrintProxy();
}
//确定打印
else if (PrintPreview.printDialogResult == "Ok")
{
//pdDocument = new PrintDocument();
iRow = 0;
startPage = 0;
int curPage = 0;
//当前页开始
int preStart = 0;
pintPoints.Clear();
//循环绘制每行数据
for (int i = iRow; i < namesTable.Rows.Count; i++)
{
if (PrintPreview.CurPage >= 0)
{
if (curPage == PrintPreview.CurPage + 1)
{
break;
}
}
//取出当前行数据
DataRow dr = namesTable.Rows[i];
//打印类型
string PrintType = dr["PrintType"].ToString();
//换页
if (PrintType == "PAGE" || (i == (namesTable.Rows.Count - 1)))
{
if (curPage < PrintPreview.CurPage)
{
iRow = i + 1;
}
else
{
endRow = i + 1;
}
curPage++;
//打印奇数页
if (PrintPreview.CurPage == -1)
{
if (curPage % 2 != 0)
{
if (PrintPreview.RangeStart > 0 && PrintPreview.RangeEnd > 0)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Add(new Point(preStart, i));
}
}
else
{
pintPoints.Add(new Point(preStart, i));
}
}
}
//打印偶数页
else if (PrintPreview.CurPage == -2)
{
if (curPage % 2 == 0)
{
if (PrintPreview.RangeStart > 0 && PrintPreview.RangeEnd > 0)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Add(new Point(preStart, i));
}
}
else
{
pintPoints.Add(new Point(preStart, i));
}
}
}
//打印偶数页逆序
else if (PrintPreview.CurPage == -3)
{
if (curPage % 2 == 0)
{
if (PrintPreview.RangeStart > 0 && PrintPreview.RangeEnd > 0)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Insert(0, new Point(preStart, i));
}
}
else
{
pintPoints.Insert(0, new Point(preStart, i));
}
}
}
//范围打印
else if (PrintPreview.CurPage == -4)
{
if (curPage >= PrintPreview.RangeStart && curPage <= PrintPreview.RangeEnd)
{
pintPoints.Add(new Point(preStart, i));
}
}
//当前页开始位置
preStart = i + 1;
}
}
//订阅BeginPrint事件
pdDocument.BeginPrint += new PrintEventHandler(pdDocument_BeginPrint);
//定义打印内容
pdDocument.PrintPage += new PrintPageEventHandler(OnPrintPage);
//訂閱EndPrint事件,释放资源
pdDocument.EndPrint += new PrintEventHandler(pdDocument_EndPrint);
//打印
PrintProxy();
}
}
Excel导出从多个模板选一个对接,需要弹窗展示多个模板名称让用户选择用的模板。通过string fullName = MessageServer.shell.SelectFileDialog(tempExcelPath);驱动UI
驱动地方,
//导出Excel
else if (((inputStrArr[0] == "Export") || (inputStrArr[0] == "ExportFast")) && inputStrArr.Length > 2)
{
string tempExcelPath = inputStrArr[6];
//快速导出Excel标识
if (inputStrArr[0] == "ExportFast")
{
ExportUtil.IsExportFast = true;
}
//选模板的模式
if (tempExcelPath.Contains("|"))
{
//选择模板
string fullName = MessageServer.shell.SelectFileDialog(tempExcelPath);
if (fullName != "")
{
inputStrArr[6] = fullName;
RealExport(inputStrArr);
}
}
else
{
RealExport(inputStrArr);
}
}
发消息给UI层
///
/// 从多个文件选一个弹窗
///
/// 用|分割的多个名称
///
public string SelectFileDialog(string selectStr)
{
if (MessageServer.UIOper != null)
{
return MessageServer.UIOper.ShowSelectTmpFileDialog(selectStr);
}
Console.WriteLine("没有UI,默认选择第一个:");
string path = selectStr.Split('|')[0];
return path;
}
electron交互层,这里把组装的UI消息推送给界面端,界面收到消息做响应
///
/// 显示选择文件对话框
///
///
///
public string ShowSelectTmpFileDialog(string selectStr)
{
UIMsgDto dto = new UIMsgDto();
dto.Type = "SelectTmpFileDialog";
dto.NeedRet = true;
dto.Paras = new List<string>();
dto.Paras.Add(selectStr);
//会阻塞等待返回
UIMsgDto ret = SenMsgAndWait(dto);
if (ret != null)
{
if (ret.RetParas != null && ret.RetParas.Count > 0)
{
return ret.RetParas[0];
}
}
return "";
}
js处理,处理选择模板类型消息,展示模板选择弹窗,把选择结果发送给服务端。
//选择模板文件对话框,多选一
else if (data.Type == "SelectTmpFileDialog") {
var path = data.Paras[0];
var pathArr = path.split('|');
var buttons = [];
for (var i = 0; i < pathArr.length; i++) {
var oneArr = pathArr[i].split("/");
buttons.push(oneArr[oneArr.length-1]);
}
var choice = dialog.showMessageBoxSync(mainWindow, {
type: "info",
buttons: buttons,
title: "选择模板对话框",
message: "请选择要使用的导出模板",
defaultId: -1,
cancelId: -1
});
//执行菜单逻辑
if (choice >= 0) {
data.RetParas = [];
data.RetParas.push(pathArr[choice]);
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}
else {
data.RetParas = [];
data.RetParas.push("");
console.log("UI->S", "uimsg#" + JSON.stringify(data));
ws.send("uimsg#" + JSON.stringify(data));
}
}
通过前后端精密的配合解决DotNetCore没跨平台ui的问题。同时实现CS界面和后端解耦合
完美,哈哈,多平台可用,centos录屏不好弄,弹窗风格没windows好,总算实现了完全跨平台了