故事的开端是这样的,小白是一个程序员,他确实也是一个小白,目前还在程序员发展的道路上,兢兢业业的小心求学。

有一天,小白接到一个任务,完成一个Winform程序,附加一个功能就是可以读IC卡。

小白终于有机会一展身手了!!不免内心兴奋。

再联系了IC卡厂家,拿到开发SDK后,小白不久就碰到了以下难题:

1、厂家的读卡器是通过API给定的事件ReadCard()驱动的,而读卡器在ReadCard事件驱动以后,可以在往后的3s以内侦测是否有IC卡片在附近:

(1)3s内,有IC卡在设备附近,立即读卡,返回读卡状态。

(2)3s内如果没有IC卡在设备附近,则读卡器等待3s后返回“-3”表示无卡。

2、小白在程序中,对读卡器获取的值需要做进一步处理,如Winform登录。

小白是这样构想实现他的程序的:

1、设定一个定时器。定时器定时的驱动读卡设备进行读卡。

2、获取读卡结果以后,在对界面上的内容进行更新。

小白按照这样的思路写了这样的代码

private void FormLogin_Load(object sender, EventArgs e)
{
TimerCallback readerDelegate = new TimerCallback(CardReaderDoing);//设定托管
var task2 = System.Threading.Tasks.Task.Factory.StartNew(new Action(() =>
{
try
{
int initCOM = InitCardThird();
if (0 == initCOM)
{
// 读卡器读卡流程为3s,这里设置3.5s读卡一次
readerTimer = new System.Threading.Timer(readerDelegate, null, 1000, 3500);
}
else
{
string err = "打开串口异常" + initCOM.ToString();
InvokeHelper.Set(label_tips, "Visible", true);
InvokeHelper.Set(label_tips, "Text", err);
InvokeHelper.Set(label_tips, "ForeColor", Color.Red);
}
}
catch (Exception ex)
{
string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";
string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆栈信息:{1}", ex.Message, ex.StackTrace);
log.Error(str);
}
}));
}

接下来是定时事件中小白的处理方法:

private void CardReaderDoing(object stateinfo)
{
try
{
int retCode = obj.ReadCard();
Thread.Sleep(1000);
if (1 == retCode)
{
//刷卡成功beep
obj.Extsys_BeepOK();
readerTimer.Change(-1, -1);
string studentCode = obj.GetCardNo();
string userName = obj.GetName(); UserInfo.StudentCode = studentCode;
UserInfo.StudentName = userName; UserInfo.AuthToken = CommonHelper.WebMethod.GetAutherizeToken(BaseConfigInfoProvider.ConfigInfo.LeoAppDomain, UserInfo.StudentCode);
bool getAuthErrored = CheckObj.CheckErrored(UserInfo.AuthToken);
if (getAuthErrored)
{
string err = CheckObj.CheckAndReturn(UserInfo.AuthToken, "CH"); //DialogResult dr = AutoClosedMessageBox.Show(err, "系统提示", 20, 15);
AutoClosedMessageBox amb = new AutoClosedMessageBox();
DialogResult dr = amb.Show(err, "系统提示", 20, 15);
if (dr == DialogResult.OK || dr == DialogResult.Cancel)
{
//amb.Dispose();
/*用户验证错误后,5s后启动读卡器*/
readerTimer.Change(5000, 3500);
InvokeHelper.Set(label_ReadNO, "Text", "请刷学生卡");
}
}
/*用户验证成功*/
else
{
InvokeHelper.Set(label_ReadNO, "Text", studentCode);
/*设置最近预约*/
GetCurrentSession();
InvokeHelper.Set(this, "Visible", false);
//显示主窗体
FormMain frm = new FormMain();
DialogResult dr = frm.ShowDialog(); InvokeHelper.Set(this, "Visible", true);
InvokeHelper.Set(label_ReadNO, "Text", "请刷卡");
readerTimer.Change(1000, 3500);
}
}
else if (-3 != retCode)
{
obj.Extsys_BeepERR();
string err = CommonHelper.ErrorDefinition.GetErrMsgByCode(retCode);
string err_brief = "Code:" + retCode.ToString();
InvokeHelper.Set(label_ReadNO, "Text", err);
InvokeHelper.Set(label_tips, "Text", err_brief); if (readerTimer != null)
{
readerTimer.Dispose();
}
}
else
{
//-3,no card
}
}
catch (Exception ex)
{
string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";
string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆栈信息:{1}", ex.Message, ex.StackTrace);
log.Error(str);
}
}

小白发现了大问题!!

由于读卡事件来自与第三方SDK,obj.ReadCard()每次调用,如果在无卡状态下,需要等待3s才能返回读卡状态。因此再此出导致了界面阻塞,在运行起来的时候,界面假死了!!

有人告诉小白说,“你应该在 CardReaderDoing事件里,将obj.ReadCard()事件用异步的方式进行处理!比如用Task或者新开一个线程去处理。”也有人告诉小白说,“你试试委托方式呗!”,小白收到大家帮忙的建议很是开心,但是尝试完后,小白和小白的伙伴们都惊呆了!答案是:官人,不可以!!!!

  小白只能怪自己才疏学浅,于是想换个方式试试。BackgroundWork以前小白是用过的,而且可以通过异步的方式,让IO和界面UI线程分开?

  于是小白有了下面的代码:

        //初始worker
private void InitializeBackgoundWorker()
{
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
//this.backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
this.backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
} //异步过程处理读卡
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
//get result from card reader
e.Result = ReadCardResult(worker,e);
if (worker.CancellationPending)
{
e.Cancel = true;
}
}
//read card and return result
private int ReadCardResult(BackgroundWorker worker, DoWorkEventArgs e)
{
int retCode = -3;
this.BeginInvoke(new Action(() =>
{
retCode = obj.ReadCard();
})); return retCode;
}
//worker完成
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";
string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆栈信息:{1}", e.Error.Message, e.Error.StackTrace);
log.Error(str);
//MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
//do nothing
}
else
{
int retCode =(int)e.Result;
try
{
if (1 == retCode)
{
//刷卡成功beep
obj.Extsys_BeepOK();
readerTimer.Change(-1, -1);
string studentCode = obj.GetCardNo();
string userName = obj.GetName(); UserInfo.StudentCode = studentCode;
UserInfo.StudentName = userName; UserInfo.AuthToken = CommonHelper.WebMethod.GetAutherizeToken(BaseConfigInfoProvider.ConfigInfo.LeoAppDomain, UserInfo.StudentCode);
bool getAuthErrored = CheckObj.CheckErrored(UserInfo.AuthToken);
if (getAuthErrored)
{
string err = CheckObj.CheckAndReturn(UserInfo.AuthToken, "CH"); //DialogResult dr = AutoClosedMessageBox.Show(err, "系统提示", 20, 15);
AutoClosedMessageBox amb = new AutoClosedMessageBox();
DialogResult dr = amb.Show(err, "系统提示", 20, 15);
if (dr == DialogResult.OK || dr == DialogResult.Cancel)
{
//amb.Dispose();
/*用户验证错误后,5s后启动读卡器*/
readerTimer.Change(5000, 3500);
InvokeHelper.Set(label_ReadNO, "Text", "请刷学生卡");
}
}
/*用户验证成功*/
else
{
InvokeHelper.Set(label_ReadNO, "Text", studentCode);
/*设置最近预约*/
GetCurrentSession();
InvokeHelper.Set(this, "Visible", false);
//显示主窗体
FormMain frm = new FormMain();
DialogResult dr = frm.ShowDialog(); InvokeHelper.Set(this, "Visible", true);
InvokeHelper.Set(label_ReadNO, "Text", "请刷学生卡");
readerTimer.Change(1000, 3500);
}
}
else if (-3 != retCode)
{
obj.Extsys_BeepERR();
string err = CommonHelper.ErrorDefinition.GetErrMsgByCode(retCode);
string err_brief = "Code:" + retCode.ToString();
InvokeHelper.Set(label_ReadNO, "Text", err);
InvokeHelper.Set(label_tips, "Text", err_brief); if (readerTimer != null)
{
readerTimer.Dispose();
}
}
else
{
//-3,no card
}
}
catch (Exception ex)
{
string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";
string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆栈信息:{1}", ex.Message, ex.StackTrace);
log.Error(str);
}
}
}

而小白通过修改定时器里的代码是:

 private void CardReaderDoing(object stateinfo)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}

小白和他们小伙伴们再次惊呆了!!!界面启动,还是因为读卡器读卡的问题,界面假死!!

各位大哥、大姐、妹子、帅哥、老道、贫尼们,这是为虾米啊!!

小白正在为此寻找一个完美的解决方案。

各位大哥、大姐、妹子、帅哥、老道、贫尼们,你们别只是路过!小白请指教了!!

说两句吧。

Winform程序的更多相关文章

  1. winform开发 总结1>winform程序使用线程的必要性,以及正确的使用方式

    winform程序中使用线程的必要性: 单线程操作在执行耗时任务时会造成界面假死,带来非常差劲的用户体验,有时候甚至会影响到正常的业务执行,使用多线程做相关操作实属不得已之举. 那么在编写程序之前必须 ...

  2. 记一次WinForm程序中主进程打开子进程并传递参数的操作过程(进程间传递参数)

    目标:想在WinForm程序之间传递参数.以便子进程作出相应的处理. 一种错误的方法 父进程的主程序: ProcessStartInfo psi = new ProcessStartInfo(); p ...

  3. 用winform程序来了解委托和事件

    一.浅谈委托 如果有个过winform 和webform 程序开发的小伙伴一定有个这样的感觉吧,点击Button直接就执行了那个方法,到此他是怎么实现了的呢,大家有考虑过没有? 回到正题,什么是委托呢 ...

  4. 基于DevExpress的Winform程序安装包的制作

    在我们做系统开发的时候,都会面临一个安装包制作的问题,如何把我们做好的系统,通过安装包工具整合成一个安装包给客户进行安装.安装包的优势就是一步步安装就可以了,不用复制一大堆文件给客户,还怕缺少那个文件 ...

  5. 在Winform程序中设置管理员权限及为用户组添加写入权限

    在我们一些Winform程序中,往往需要具有一些特殊的权限才能操作系统文件,我们可以设置运行程序具有管理员权限或者设置运行程序的目录具有写入的权限,如果是在操作系统里面,我们可以设置运行程序以管理员身 ...

  6. 吉特仓库管理系统(开源)-如何在网页端启动WinForm 程序

    在逛淘宝或者使用QQ相关的产品的时候,比如淘宝我要联系店家点击旺旺图标的时候能够自动启动阿里旺旺进行聊天.之前很奇怪为什么网页端能够自动启动客户端程序,最近在开发吉特仓储管理系统的时候也遇到一个类似的 ...

  7. 【转】C#中WinForm程序退出方法技巧总结

    C#中WinForm程序退出方法技巧总结 一.关闭窗体 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.Ex ...

  8. 黄聪:C#Winform程序如何发布并自动升级(图解)

    有不少朋友问到C#Winform程序怎么样配置升级,怎么样打包,怎么样发布的,在这里我解释一下打包和发布关于打包的大家可以看我的文章C# winform程序怎么打包成安装项目(图解)其实打包是打包,发 ...

  9. WinForm程序全局捕捉异常处理办法

    如何全局捕捉Winform程序异常呢,当然是从程序启动入口的Program类下的Main()方法定义了,下面看下这个类怎么写的吧 static class Program { static strin ...

  10. 【转】C#Winform程序如何发布并自动升级(图解)

    有不少朋友问到C#Winform程序怎么样配置升级,怎么样打包,怎么样发布的,在这里我解释一下打包和发布关于打包的大家可以看我的文章C# winform程序怎么打包成安装项目(图解)其实打包是打包,发 ...

随机推荐

  1. SOA、REST 和六边形架构

    SOA.REST 和六边形架构 上一篇:<IDDD 实现领域驱动设计-架构之经典分层> 阅读目录: SOA-面向服务架构 REST 与 RESTful 资源(Resources) 状态(S ...

  2. .Net 2.0实例学习:WebBrowser页面与WinForm交互技巧

    原文:.Net 2.0实例学习:WebBrowser页面与WinForm交互技巧 最近看到博客园入门教学文章比较流行,自己最近又偷懒比较多,没啥心得,不妨写一篇没啥深度的入门文章吧. 话说有了WebB ...

  3. Python超级明星WEB框架Flask

    Flask简介 Flask是一个相对于Django而言轻量级的Web框架. 和Django大包大揽不同,Flask建立于一系列的开源软件包之上,这其中 最主要的是WSGI应用开发库Werkzeug和模 ...

  4. SQL点滴24—监测表的变化

    原文:SQL点滴24-监测表的变化(转载) 在网上看到一篇关于监测表中的插入,更新,删除的方法,使用触发器实现的,很有价值. 地址:http://www.dbaunion.com/u/livecoac ...

  5. 全新通用编程语言 Def 招募核心贡献者、文档作者、布道师 deflang.org

    先给出官网地址:deflang.org 一句话简介:可扩展编程语言 Def 的目标是将 C++ 的高效抽象和 Lisp 的强大表现力融为一体. 你可以通过阅读 入门教程 .源码 或 测试用例 来简要或 ...

  6. [译]Java 设计模式 之模板方法

    (文章翻译自Java Design Pattern: Template Method) 模板方法设计模式定义了归档特定操作的工作流.它允许子类去修改特定的步奏而不用改变工作流的结构. 下面的例子表示模 ...

  7. Python开发环境Wing IDE 5.0测试第八版发布

    Wing IDE是著名的Python开发工具,是Wingware公司的主要产品.从1999年起,Wingware公司便开始专注于Python开发设计.Wing IDE在十几年的发展中,不管完善.其强大 ...

  8. ASP.NET中Partial Class部分类

    原文:ASP.NET中Partial Class部分类 如果您在开发项目的公用函数库,用于公用函数库的内容越丰富越好,但这不可能一下子就写好,需要一点一点的积累,这时就可以使用Partial Clas ...

  9. java编程思想笔记(第一章)

    Alan Kay 第一个定义了面向对象的语言 1.万物皆对象 2.程序是对象的集合,他们彼此通过发送消息来调用对方. 3.每个对象都拥有由其他对象所构成的存储 4.每个对象都拥有其类型(TYpe) 5 ...

  10. Markdown 代码测试

    Mou Overview Mou, the missing Markdown editor for web developers. Syntax Strong and Emphasize strong ...