【发布时间】:2018-10-11 11:30:56
【问题描述】:
基本上,我正在开发的程序是一个 C# 控制台应用程序,它通过套接字侦听请求。建立连接后,它会调用并显示一个名为 frmPdfViewer 的 Windows 窗体。
在frmPdfViewer中,有一个名为Sign的ToolStripMenuItem。当它被点击时,它应该会显示一个签名弹出窗口供用户签名。
现在我的问题是当我单击 SignToolStripMenuItem 时,表单冻结并且不显示签名弹出窗口。没有抛出错误或异常,它只是冻结。但是当我在点击Sign后尝试隐藏frmPdfViewer时,会出现签名弹出窗口。
为什么会有这样的行为?
这里是套接字代码的 sn-p(在 ProcReq() 方法中是调用表单的地方):
var wsURI = ConfigurationManager.AppSettings["wsURI"];
var id = ConfigurationManager.AppSettings["id"];
var ns = ConfigurationManager.AppSettings["namespace"];
var type = ConfigurationManager.AppSettings["type"];
var socket = IO.Socket(wsURI + "/" + ns);
socket.On(Socket.EVENT_CONNECT, () =>
{
// Construct Push Message for Device Registration
JObject reg = MessageFactory.CreateRegistrationMessage(id,
"RR_" + id, type);
socket.Emit("peripheral/registration", JsonConvert.SerializeObject(reg));
socket.On(ns + "/RR_" + id, (reqMsg) =>
{
JObject req = reqMsg as JObject;
JObject reqHeader = (JObject)req["header"];
RespPayload respPayload = TabletTerminal.GetInstance().ProcReq(req);
JObject resp = new JObject();
resp.Add("header", reqHeader);
resp.Add("payload", JObject.FromObject(respPayload));
var jsonResp = JsonConvert.SerializeObject(resp);
socket.Emit(ns + "/RR_" + id, jsonResp);
});
})
这里是 ProcReq 方法的 sn-p(这是表单将被调用的地方):
public SignatureRespPayload ProcReq(JObject req)
{
SignatureRespPayload signatureRespPayload = new SignatureRespPayload();
JObject reqPayload = req.GetValue("payload") as JObject;
string name = (string)reqPayload["name"];
string reason = (string)reqPayload["reason"];
string pdfPath = (string)reqPayload["pdfPath"];
frmPdfViewer pdfViewer = new frmPdfViewer(name, reason, pdfPath);
pdfViewer.ShowDialog();
signatureRespPayload.returnValue = pdfViewer.returnValue;
if (signatureRespPayload.returnValue)
{
signatureRespPayload.signedPdfPath = pdfViewer.signedPdfPath;
}
else
{
signatureRespPayload.errorMessage = pdfViewer.errorMessage;
}
pdfViewer.Dispose();
return signatureRespPayload;
}
这里是frmPdfViewer中标志点击事件的代码sn-p:
(注意:我用的是第三方SDK,叫Wacom Signature SDK,只能查看他们方法的接口,不能查看实现。显示签名弹窗的方法是捕获())
try
{
SigCtl sigCtl = new SigCtl();
sigCtl.Licence = Properties.Settings.Default.License;
DynamicCapture dc = new DynamicCaptureClass();
DynamicCaptureResult res = dc.Capture(sigCtl, name, reason, null, null);
if (res == DynamicCaptureResult.DynCaptOK)
{
SigObj sigObj = (SigObj)sigCtl.Signature;
String filename = System.IO.Path.GetTempFileName();
sigObj.RenderBitmap(filename, 400, 200, "image/png", 0.5f, 0xff0000, 0xffffff, 10.0f, 10.0f, RBFlags.RenderOutputFilename | RBFlags.RenderColor32BPP | RBFlags.RenderEncodeData | RBFlags.RenderBackgroundTransparent);
string newFile = InsertSignatureImageToPdf(filename);
loadPdf(newFile, false);
}
}
catch (Exception ex)
{
Console.Write(ex.StackTrace);
MessageBox.Show(ex.Message);
}
注意:当我在 Capture() 方法前下断点,然后继续运行程序时,也会出现签名弹窗。
【问题讨论】:
-
在方法上设置断点,并在断点后使用“调试”>“Windows”>“线程”。水晶球说你看到代码在工作线程而不是主线程上运行。很多很多问题,Z 顺序问题和冻结的外观只是其中的一小部分。使用 BeginInvoke 确保您在 UI 线程上创建表单。
-
您可以在
ShowDialog()中以所有者身份传递当前表单 -
@HansPassant 我明白了。我创建了一个名为 CaptureSignature() 的新方法,并将签名点击事件代码移到了那里。之后我将
Invoke(new MethodInvoker(CaptureSignature));放在了标志点击事件中,但它仍然不起作用。我之前没有真正使用过 Invoke(),你能告诉我在这种情况下如何正确使用它吗? -
您需要使用肯定是在主线程上创建的表单的 BeginInvoke() 方法。通常是您的主窗口。如果您迫切希望获得正确的对象引用,那么 Application.OpenForms[0].BeginInvoke(...) 往往会有所帮助。
-
@HansPassant 我的主窗口是控制台应用程序。那么你是说我应该在显示表单后使用该代码(即 pdfViewer.ShowDialog();)?
标签: c# .net winforms sockets console-application