智能卡水表管理系统主要是用于纯净水水卡的充值消费管理。因此,这涉及到以下问题需要解决。
第一,软件保护问题,及如何防止其他人盗用软件。
第二,IC卡相关操作函数引入问题,即如何调用IC卡等硬件设备的相关操作函数。
第三,文档处理问题,即在VS自有功能基础上,如何实现更高的文件导出,打印等功能。即DEVEXPRESS插件的使用。
第四,如何生成软件问题。
第五,数据库打包生成或动态生成问题。
第六,
winform复杂编程注意点。
1,主要确认是否分层,若分层,注意各层之间的逻辑关系。
2,主要静态类及静态方法的使用。
3,注意命名空间在管理变量,函数等方面的应用。
4,硬盘操作问题:
4.1 首先建立一个CIM管理类:ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");Win32_NetworkAdapterConfiguration是WMI中的一个Win32类
4.2 首先建立一个 ManagementObject 类,ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"c:\"");
4.3 然后根据 ManagementObject 类的 VolumeSerialNumber 属性得到序列号:string hdInfo = disk.Properties["VolumeSerialNumber"].Value.ToString();
4.4 //获得CPU的序列号
string strCpu = null;
ManagementClass myCpu = new ManagementClass("win32_Processor");
ManagementObjectCollection myCpuConnection = myCpu.GetInstances();
foreach (ManagementObject myObject in myCpuConnection)
{
strCpu = myObject.Properties["Processorid"].Value.ToString();//异常:System.NullReferenceException: 未将对象引用设置到对象的实例
break;
}
return strCpu;
4.5 确认注册号码是否存在。
5.SetForegroundWindow函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
C#形式声明
[DllImport("user32")]
static extern int SetForegroundWindow(IntPtr hwnd);
6.FindWindow函数返回与指定字符创相匹配的窗口类名或窗口名的最顶层窗口的窗口句柄。这个函数不会查找子窗口。
函数原型:
HWND FindWindow
(
LPCTSTR lpClassName,
LPCTSTR lpWindowName
);
参数表:
lpClassName
指向一个以null结尾的、用来指定类名的字符串或一个可以确定类名字符串的原子。如果这个参数是一个原子,那么它必须是一个在调用此函数前已经通过GlobalAddAtom函数创建好的全局原子。这个原子(一个16bit的值),必须被放置在lpClassName的低位字节中,lpClassName的高位字节置零。
lpWindowName
指向一个以null结尾的、用来指定窗口名(即窗口标题)的字符串。如果此参数为NULL,则匹配所有窗口名。
返回值:
如果函数执行成功,则返回值是拥有指定窗口类名或窗口名的窗口的句柄。
如果函数执行失败,则返回值为 NULL 。可以通过调用GetLastError函数获得更加详细的错误信息。
7.ToString("X2") 为C#中的字符串格式控制符
X为 十六进制
2为 每次都是两位数
比如 0x0A ,若没有2,就只会输出0xA
假设有两个数10和26,正常情况十六进制显示0xA、0x1A,这样看起来不整齐,为了好看,可以指定"X2",这样显示出来就是:0x0A、0x1A。
返回值
Type: System.Diagnostics.Process[]类型 Process 的数组,表示本地计算机上运行的所有进程资源。
9.string fileSource = System.Environment.CurrentDirectory + @"\\IntelligentCardWaterMeter.db"; 获取或设置当前目录的完整限定路径。
10.
10.1System.Text.Encoding.ASCII.GetBytes(str1);将单个字符的字符串转化成ASCII码字符串。
byte[] array = System.Text.Encoding.ASCII.GetBytes(str2);
10.2 System.Text.Encoding.Default.GetString(utf8bytes2);
这里意思是继续以默认格式保存UTF8编码的字符串,尽管你看到的是乱码:"娴嬭瘯" 但他却是UTF8格式编码的,传递给支持UTF8的库或者dll时,才能被正确的解码。
11.在重新创建一个解决方案时,由于需要重用代码,故选择了复制模块,但遗憾的是部分代码不能实用,故只能重新命名解决方案后进行更改。即需要了解重用代码的技巧。
12,文本框中的换行为“\r\n".
13,switch中人语句块记得用{}包围,同时记得BREAK的作用。
14.部分IC卡由于对扇区需要加密,故只能一次读取一个扇区,且在读取前需要认证。且每次认证失败,则需要重新连接操作。
15.细节基本点,
即16进制表示时以0x开头。
将十进制Ml转换16进制形式转换为字符串时为ml.ToString("X8")。
将Ml以10进制形式转换为字符串时为ml.ToString()。
将16进制的字符串转换为16进制时,为Convert.ToInt32(strtxt, 16);。
//十进制转二进制
Console.WriteLine(Convert.ToString(69, 2));
//十进制转八进制
Console.WriteLine(Convert.ToString(69, 8));
//十进制转十六进制
Console.WriteLine(Convert.ToString(69, 16));
//二进制转十进制
Console.WriteLine(Convert.ToInt32(”100111101〃, 2));
//八进制转十进制
Console.WriteLine(Convert.ToInt32(”76〃, 8));
//十六进制转十进制
Console.WriteLine(Convert.ToInt32(”FF”, 16));
16.可以用以下两种方法初始化一个随机数发生器;
函数是这样用,比如100至999的随机数
Random ran=new Random();
int RandKey=ran.Next(100,999);
17.读卡器有一个初始化串口的函数,重复实用时会出错,可以重启系统,或这重新插拔设备即可。这与普通的U盘等类似。由于设备本身的预设功能,故暂时不能改变。
18.对于COMBOX控件,若需要显示其关联的内容时,需要使用其TEXT属性。
19.在编程过程中,具体功能实现时,若出现错误,需要提示。但在编写专门供调用的函数时,只需要用返回值表示结果即可,不然会出现重复提示。
20. 无法获取本地变量或参数的值 原因可能是它已经被优化掉而在此指令指针中不可用,改怎么处理。
把using()去掉试试吧。一般都是这个问题。在你需要用的时候,datatable已经被释放掉了
不要在using里使用return,把它放到外面去
也有可能是在项目属性的生成选项卡中勾选了“优化代码”。
21.在使用不同的VS版本或计算机位数不同时,软件运行时会提示有些DLL文件加载错误,此时需要调整项目属性中的优化代码选项,或目标平台X86,X64等。
22.注意在绑定datagridview的datasource属性时,其datapropertyname是绑定的数据源的名称,以便一一对应,并显示。
而COMBOX的selectedindexchange事件可以及时调整dgv的数据源并显示。
23.在winform中需要有一个主程序,故在设置登录界面时,需要在主程序中判断那个是主程序。
24.对于TAB键跳转问题,即如果需要实现ENTER键或其他键的跳转,需要在程序中进行相关的逻辑实现,一般比较常用的代码如下,即在控件已经绑定的KEYPRESS的事件中,判断敲击键是否为某个键,若是,则进行TAB跳转。
if (e.KeyChar == (char)Keys.Enter)
SendKeys.Send("{tab}");
25.EXCEL操作总结。
一般正确的连接字符串为:string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source={0};" + "Extended Properties='Excel 8.0;HDR=NO;IMEX=1';", strExcelFileName);//此连接可以操作.xls与.xlsx文件 (支持Excel2003 和 Excel2007 的连接字符串).
25.1Provider版本不同,可以操作的EXCEL版本也不同,有时会提示找不到可安装的ISAM,因为新版本不能兼容旧版本了,此时进行安装ISAM及调整注册表都没用。
25.2Extended Properties也会影响到EXCEL版本选择。
25.3老的版本有时不能操作XLSX等文件的,即仅能操作XLS文件。
//string strConn = "Provider=Microsoft.Jet.OleDb.4.0;" + "data source=" + Server.MapPath("ExcelFiles/MyExcelFile.xls") + ";Extended Properties='Excel 8.0; HDR=Yes; IMEX=1'";//此连接只能操作Excel2007之前(.xls)文件
string strConn = "Provider=Microsoft.Ace.OleDb.12.0;" +"data source=" + Server.MapPath("ExcelFiles/Mydata2007.xlsx") + ";Extended Properties='Excel 12.0; HDR=Yes; IMEX=1'";//此连接可以操作.xls与.xlsx文件 (支持Excel2003 和 Excel2007 的连接字符串)//备注: "HDR=yes;"是说Excel文件的第一行是列名而不是数据,"HDR=No;"正好与前面的相反。
// "IMEX=1 "如果列中的数据类型不一致,使用"IMEX=1"可必免数据类型冲突。
25.4Microsoft.ACE.OLEDB.12.0需要下载相应组件,且是不能再x64上使用的,你要强制把你的web application编译成x86再发布到Win08 x64上,记得在Application pool上设置Enable 32bit Application = true。
25.5GetOleDbSchemaTable取到的表的信息还包括excel的命名区域;具体应用相对较复杂。
26.求:在一个项目中,要实现一个控件选择功能,如果一个个的去判断,代码会十分难看,由于控件名有规律,是否可以根据控件直接找到对应的控件对象?
实现:利用反射
可用于WPF:
- object o = this.GetType().GetField(name, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase).GetValue(this);
- return ((Control)o);
object o = this.GetType().GetField(name, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase).GetValue(this);
return ((Control)o);
可用于Winform:
- private void button2_Click(object sender, EventArgs e)
- {
- ((Button)(this.Controls.Find("button1", false)[0])).Text = "123";
- }
private void button2_Click(object sender, EventArgs e)
{
((Button)(this.Controls.Find("button1", false)[0])).Text = "123";
}
WPF类似于Controls.Find:
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- ((Button)this.FindName("Button1")).Content = "123";
- }
private void Button_Click(object sender, RoutedEventArgs e)
{
((Button)this.FindName("Button1")).Content = "123";
}
26.dgv.SelectedRows[0].Selected = false;//禁止被选中,这一行代码要放在绑定数据后面,不然会报错!;属性里selection mode改为full row select,一次选一行
27.超级用户的设置。 在设置用户角色的时候,往往需要设置超级用户,已达到数据库异常时可以登录系统进行操作。同时,这也从一定角度说明了软件系统与数据库分离设计的思想。即软件的运行应建立在数据库为空的基础上。
28.IC设置自动寻卡功能时,设置一定的时间事件即可。
29.IC卡操作时经常死机,此时往往是由于射频模块异常造成的,可以通过设置射频模块复位操作,从而达到减少异常死机的概率。
30.
using
System.Threading;
// 在想要停顿的地方加上以下语句
Thread.Sleep(1000);
// 停顿1000毫秒
31. Timer控件的主要属性:
Enable:Timer控件是否启用
Interval:事件的运行间隔时间
Timer控件的事件:
timer_Tick:事件间隔时进行的操作
32.波特率的设置,在设置密钥管理的相关功能时,因为两个软件的波特率设置不一致,导致相互操作困难,但在开发时没有异常,即可能在连接串口时,出现一些差错,导致暂时能正常运行,但禁不住多次测试。因此,波特率等基本参数需要一致。
另外,注意系统中在向数据库查询数据时,若非本软件建立的卡,往往出现异常。
33.MESSAGEBOX的自动关闭功能。
WinForm 下我们可以调用MessageBox.Show 来显示一个消息对话框,提示用户确认等操作。在有些应用中我们需要通过程序来自动关闭这个消息对话框而不是由用户点击确认按钮来关闭。然而.Net framework 没有为我们提供自动关闭MessageBox 的方法,要实现这个功能,我们需要使用Window API 来完成。
另外,由于MESSAGEBOX一般以模态的形式出现,故动态发送ENTER键似乎无效。
34.对于发布后的WINFORM程序,再次在DEBUG模式下运行时,提示加载某个模块版本等问题。经分析,主要是因为模块的某个版本与平台冲突,故将平台更改为86版本了。
另外,若不能调试,可以尝试First thing you could try is to turn on Project -> Properties -> Debug -> Enable Debuggers -> Enable unmanaged code debugging
36.WINFORM打包程序注意事项如下:
36.1 注意语言选择简体中文,避免中文字符异常。
36.2 注意添加NET框架。
36.3 添加主输出文件及相应插件,且注意设置已添加第三方控件的属性。
36.4 在添加快捷方式时注意添加相应的图标文件。
36.5 注意最后Realse设置中的设置为Extract from setup.exe,同时注意设置解决方案中的配置设置。
36.6 最后注意可以只设置重新生成配置的项目文件即可生成安装文件。
36.7 注意在全部操作前设置需要打包项目的属性中发布内容的路径为打包文件夹。
36.8 对于打包时快捷方式的设置,需要同时设置其所对应的路径,否则无法引用相应的数据库等文件。
36.9 对于打包后的权限问题,即一般安装在C盘,而C盘要求权限较高。此时可以设置Application Manifest中的权限要求。