Winform程序
故事的开端是这样的,小白是一个程序员,他确实也是一个小白,目前还在程序员发展的道路上,兢兢业业的小心求学。
有一天,小白接到一个任务,完成一个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程序的更多相关文章
- winform开发 总结1>winform程序使用线程的必要性,以及正确的使用方式
winform程序中使用线程的必要性: 单线程操作在执行耗时任务时会造成界面假死,带来非常差劲的用户体验,有时候甚至会影响到正常的业务执行,使用多线程做相关操作实属不得已之举. 那么在编写程序之前必须 ...
- 记一次WinForm程序中主进程打开子进程并传递参数的操作过程(进程间传递参数)
目标:想在WinForm程序之间传递参数.以便子进程作出相应的处理. 一种错误的方法 父进程的主程序: ProcessStartInfo psi = new ProcessStartInfo(); p ...
- 用winform程序来了解委托和事件
一.浅谈委托 如果有个过winform 和webform 程序开发的小伙伴一定有个这样的感觉吧,点击Button直接就执行了那个方法,到此他是怎么实现了的呢,大家有考虑过没有? 回到正题,什么是委托呢 ...
- 基于DevExpress的Winform程序安装包的制作
在我们做系统开发的时候,都会面临一个安装包制作的问题,如何把我们做好的系统,通过安装包工具整合成一个安装包给客户进行安装.安装包的优势就是一步步安装就可以了,不用复制一大堆文件给客户,还怕缺少那个文件 ...
- 在Winform程序中设置管理员权限及为用户组添加写入权限
在我们一些Winform程序中,往往需要具有一些特殊的权限才能操作系统文件,我们可以设置运行程序具有管理员权限或者设置运行程序的目录具有写入的权限,如果是在操作系统里面,我们可以设置运行程序以管理员身 ...
- 吉特仓库管理系统(开源)-如何在网页端启动WinForm 程序
在逛淘宝或者使用QQ相关的产品的时候,比如淘宝我要联系店家点击旺旺图标的时候能够自动启动阿里旺旺进行聊天.之前很奇怪为什么网页端能够自动启动客户端程序,最近在开发吉特仓储管理系统的时候也遇到一个类似的 ...
- 【转】C#中WinForm程序退出方法技巧总结
C#中WinForm程序退出方法技巧总结 一.关闭窗体 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.Ex ...
- 黄聪:C#Winform程序如何发布并自动升级(图解)
有不少朋友问到C#Winform程序怎么样配置升级,怎么样打包,怎么样发布的,在这里我解释一下打包和发布关于打包的大家可以看我的文章C# winform程序怎么打包成安装项目(图解)其实打包是打包,发 ...
- WinForm程序全局捕捉异常处理办法
如何全局捕捉Winform程序异常呢,当然是从程序启动入口的Program类下的Main()方法定义了,下面看下这个类怎么写的吧 static class Program { static strin ...
- 【转】C#Winform程序如何发布并自动升级(图解)
有不少朋友问到C#Winform程序怎么样配置升级,怎么样打包,怎么样发布的,在这里我解释一下打包和发布关于打包的大家可以看我的文章C# winform程序怎么打包成安装项目(图解)其实打包是打包,发 ...
随机推荐
- Cocos2d-xvision3.0加载失败,和,Vs2012环境搭建
1.安装好VS2012,下载Cocos2d-x3.0 双击击win32 sln运行VS2012 如果加载失败点击程序运行,输入devenv.exe /resetuserdata 回车,然后再进入VS, ...
- asp.net动态加载ascx用户控件
原文:asp.net动态加载ascx用户控件 在主aspx/ascx文件中,将目标ascx1,ascx2控件拖拉到其页面中,然后删除,目的是要生成:Register 代码,然后在主文件中定义DIV或T ...
- 泛型委托及委托中所涉及到匿名方法、Lambda表达式
泛型委托及委托中所涉及到匿名方法.Lambda表达式 引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到 ...
- 在地图中使用Java
Map以按键/数值对的形式存储数据,和数组很类似,在数组中存在的索引,它们本身也是对象. Map的接口 Map---实现Map Map.Entry--Map的内部类 ...
- WimMaker 2.0 (2013.10) WIM制作工具
WimMaker 2.0 (2013.10) WIM制作工具 可用于制作PE启动内核的Wim文件 说明: 因本软件使用.NET2.0制作,故主要用于制作WIM映像不用于备份还原系统(虽可用,但不专业, ...
- Premiere Pro CC问题集,不断更新
1.Premiere Pro CC不好用? 是的.原因如下: 1.1 Adobe公司不注重用户体验,不注重工作流程,导致这款软件的用户体验很差,设计也很烂.对比Adobe公司当年用户体验最好的软件 F ...
- JQUERY简写案例
源代码: <script ttype="text/javascript"> $(function(){ $(".btn").eq(0).click( ...
- /bin/bash^M: bad interpreter: No such file or directory
<今天遇到的问题, 网上有非常多类似的文章, 个人记录下来, 加深记忆, 已经明确的就绕路吧.> 运行一个脚本full_build.sh 时, 一直是提示我: -bash: ./f ...
- 12个很少被人知道的CSS事实
之前没有认真的研究过,padding-bottom的值如果是百分比,那么它的实际值是根据父类的宽度来调整的.我还以为是根据这个元素的本身的宽度来定义呢?汗..padding-top/padding-l ...
- 深入分析ENode的内部实现流程和关键地方的幂等设计
ENode 2.0 - 深入分析ENode的内部实现流程和关键地方的幂等设计 前言 ENode架构图 ENode框架内部实现流程分析 Command的幂等处理 Domain Event持久化时的并发冲 ...