厚积薄发,丰富的公用类库积累,助你高效进行系统开发(14)---Winform开发的常用类库(终结篇,CHM文档放送)
俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。
本篇的公用类库的介绍主题是程序开发中常用到的一些辅助类,在帮助文档中归类到其他目录下面,本篇主要介绍在Winform开发用,常用到的一些类库,包括Windows服务操作、DOS操作、串口操作、POS打印操作以及一些参加的界面控件的辅助类。
本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(13)--- 各种常用的辅助类2
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(12)--- 网络相关操作辅助类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(11)---各种线程相关操作类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(10)---各种线程同步的集合类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(9)----各种常用辅助类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(8)----非对称加密、BASE64加密、MD5等常用加密处理
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(7)-----声音播放、硬件信息、键盘模拟及钩子、鼠标模拟及钩子等设备相关
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(6)----全屏截图、图标获取、图片打印、页面预览截屏、图片复杂操作等
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)----CSV、Excel、INI文件、独立存储等文件相关
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(3)----数据库相关操作
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(2)----常用操作
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(1)----开篇总结
至此,整个厚积薄发的类库整理也落下帷幕,整个过程历时一年多,整理优化近两百多个类库,帮助说明近两百个。本篇作为本系列的终结篇,贴出最终的
CHM帮助文档
,以及最有的
类库DLL
,如果需要进一步了解整个类库的信息,可以随时联系我。
http://www.iqidi.com/download/commonshelp.rar
最新公用类库DLL+XML注释文件下载地址是:
https://files.cnblogs.com/wuhuacong/WHC.OrderWater.Commons.rar
整个帮助类库的CHM文件概况如下所示。
1、 Window服务辅助类WinServiceHelper,包括安装、卸载、启动、停止、重新启动、判断服务是否存在等操作。
本辅助类主要是用来方便实现Window服务的各种操作,包括安装、卸载、启动、停止、重新启动、判断服务是否存在等操作。 Window服务适用于个各种定时服务,或者数据同步的操作中。
1)辅助类提供的方法接口如下所示:
///安装Windows服务/// </summary> /// <param name="serviceName">服务名称</param> /// <param name="serviceFileName">服务文件路径</param> /// <returns></returns> public static bool InstallService(string serviceName, stringserviceFileName)/// <summary> ///卸载Windows服务/// </summary> /// <param name="serviceName">服务名称</param> /// <param name="serviceFileName">服务文件路径</param> public static bool UnInstallService(string serviceName, stringserviceFileName)/// <summary> ///另外一种安装、卸载Windows服务的方法/// </summary> /// <param name="install">安装还是卸载,true为安装,false为卸载</param> /// <param name="serviceFileName"></param> public static void InstallService2(bool install, stringserviceFileName)/// <summary> ///判断window服务是否存在/// </summary> /// <param name="serviceName">window服务名称</param> /// <returns></returns> public static bool ServiceIsExisted(stringserviceName)/// <summary> ///等待某种预期的状态(如运行,停止等)/// </summary> /// <param name="serviceName">window服务名称</param> /// <param name="status">预期的状态</param> /// <param name="second">如果获取不到预期的状态,则等待多少秒</param> /// <returns></returns> public static bool WaitForStatus(string serviceName, ServiceControllerStatus status, intsecond)/// <summary> ///启动window服务/// </summary> /// <param name="serviceName"></param> public static bool StartService(stringserviceName)/// <summary> ///停止服务/// </summary> /// <param name="serviseName"></param> /// <returns></returns> public static bool StopService(stringserviseName)/// <summary> ///修改服务的启动项 2为自动,3为手动/// </summary> /// <param name="startType"></param> /// <param name="serviceName"></param> /// <returns></returns> public static bool ChangeServiceStartType(int startType, stringserviceName)/// <summary> ///获取服务启动类型 2为自动 3为手动 4 为禁用/// </summary> /// <param name="serviceName"></param> /// <returns></returns> public static string GetServiceStartType(stringserviceName)/// <summary> ///验证服务是否启动/// </summary> /// <returns></returns> public static bool ServiceIsRunning(string serviceName)
2)辅助类的使用例子代码如下所示
private voidCheckServcieStatus()
{string serviceName = this.txtServiceName.Text;bool exist =WinServiceHelper.ServiceIsExisted(serviceName);if(exist)
{#region 获取转换状态 string startType =WinServiceHelper.GetServiceStartType(serviceName);string startTypeStatus = "";if (startType == "2")
{
startTypeStatus= "自动";
}else if (startType == "3")
{
startTypeStatus= "手动";
}else if (startType == "4")
{
startTypeStatus= "禁用";
}#endregion bool running =WinServiceHelper.ServiceIsRunning(serviceName);this.txtServiceStatus.Text = string.Format("启动类型:{0} 状态:{1}", startTypeStatus, running ? "正在运行" : "已停止");this.txtServiceStatus.BackColor = Color.FromArgb(255, 255, 192);this.btnStartService.Enabled = !running;this.btnStopService.Enabled =running;this.btnReset.Enabled = true;this.btnInstallService.Enabled = false;this.btnUnInstallService.Enabled = true;
}else{this.txtServiceStatus.BackColor =Color.Red;this.txtServiceStatus.Text = string.Format("{0} 服务不存在", serviceName);this.btnStartService.Enabled = false;this.btnStopService.Enabled = false;this.btnReset.Enabled = false;this.btnInstallService.Enabled = true;this.btnUnInstallService.Enabled = false;
}
}
以上代码摘自我的《
Winform开发框架之通用定时服务管理
》
2、DOS操作封装辅助类 DosHelper。
本辅助类主要是用来方便实现DOS操作。DOS操作在自定义安装数据库脚本、运行特殊命令、后台注册控件、操作Windows Service等方面都有用到。在另一个辅助类SqlScriptHelper,就是采用运行DOS命令方式进行Sql脚本的数据库安装。
1)辅助类提供的方法接口如下所示
/// <summary> ///后台执行DOS文件/// </summary> /// <param name="fileName">文件名(包含路径)</param> /// <param name="argument">运行参数</param> /// <param name="hidden">是否隐藏窗口</param> public static void RunDos(string fileName, string argument, boolhidden)/// <summary> ///运行指定DOS命令行/// </summary> /// <param name="fileName">命令</param> /// <param name="argument">命令行参数</param> /// <param name="hidden">是否隐藏窗口</param> /// <param name="confirm">写入命令行的确认信息</param> /// <returns></returns> public static string ExecuteCMD(string fileName, string argument, bool hidden, stringconfirm)/// <summary> ///同步方式执行DOS命令/// </summary> /// <param name="command">DOS命令</param> public static void ExecuteCommandSync(objectcommand)/// <summary> ///异步方式执行DOS命令/// </summary> /// <param name="command">DOS命令字符串</param> public static void ExecuteCommandAsync(string command)
2)辅助类的使用例子代码如下所示
private void btnInstallService_Click(objectsender, EventArgs e)
{if(CheckInput())
{
DosHelper.RunDos(servicefile,"-i", false);
WinServiceHelper.WaitForStatus(this.txtServiceName.Text, ServiceControllerStatus.Running, 10);
CheckServcieStatus();
}
}private void btnUnInstallService_Click(objectsender, EventArgs e)
{if(CheckInput())
{
DosHelper.RunDos(servicefile,"-u", false);
Thread.Sleep(1000);
CheckServcieStatus();
}
以上代码摘自我的《
Winform开发框架之通用定时服务管理
》
3、串口开发辅助类 SerialPortUtil
一般人可能开发C#相关的项目很多年,不一定会接触到串口的开发,了解熟悉对硬件串口的开发,串口也不再是什么神秘的东西,利用SerailPort组件,对串口的各种操作也非常的方便,由于本人总是喜欢把一些常用的东西封装成可供重复利用的类库,因此,在阅百家代码,项目积累总结的基础上,提炼总结优化,把对串口的操作封装成一个公用的类库,应付日常的串口编程开发,也算是工作的一个阶段性总结吧。
5)奇偶校验 Parity
ErrorReceived:错误处理事件
SerialPort类的方法主要包括:
Open();Close();Read();Write()、DiscardInBuffer()、DiscardOutBuffer()等
从上面的测试例子图中,我们可以看到,一般对串口的操作,需要提供串口号、波特率、数据位、停止位、奇偶校验的参数,用来构造一个串口操作类,以便实现具体的串口操作,而这些参数有的是系统内置的枚举参数,我们可以通过遍历枚举对象来绑定下来列表(如停止位、奇偶校验);但有些参数却不是系统内置的枚举类型,例如波特率、数据位等,而且对这些参数操作也是串口开发经常用到的,因此,第一步,我对这些参数的绑定做了一个简单的封装。
1)辅助类的接口代码如下所示。
/// <summary> ///串口开发辅助类/// </summary> public classSerialPortUtil
{/// <summary> ///接收事件是否有效 false表示有效/// </summary> public bool ReceiveEventFlag = false;/// <summary> ///结束符比特/// </summary> public byte EndByte = 0x23;//string End = "#"; /// <summary> ///完整协议的记录处理事件/// </summary> public eventDataReceivedEventHandler DataReceived;/// <summary> ///严重错误事件处理/// </summary> public eventSerialErrorReceivedEventHandler Error;/// <summary> ///串口号/// </summary> public stringPortName/// <summary> ///波特率/// </summary> publicSerialPortBaudRates BaudRate/// <summary> ///奇偶校验位/// </summary> publicParity Parity/// <summary> ///数据位/// </summary> publicSerialPortDatabits DataBits/// <summary> ///停止位/// </summary> publicStopBits StopBits#endregion #region 构造函数 /// <summary> ///参数构造函数(使用枚举参数构造)/// </summary> /// <param name="baud">波特率</param> /// <param name="par">奇偶校验位</param> /// <param name="sBits">停止位</param> /// <param name="dBits">数据位</param> /// <param name="name">串口号</param> public SerialPortUtil(stringname, SerialPortBaudRates baud, Parity par, SerialPortDatabits dBits, StopBits sBits)/// <summary> ///参数构造函数(使用字符串参数构造)/// </summary> /// <param name="baud">波特率</param> /// <param name="par">奇偶校验位</param> /// <param name="sBits">停止位</param> /// <param name="dBits">数据位</param> /// <param name="name">串口号</param> public SerialPortUtil(string name, string baud, string par, string dBits, stringsBits)/// <summary> ///默认构造函数/// </summary> publicSerialPortUtil()#endregion /// <summary> ///端口是否已经打开/// </summary> public boolIsOpen/// <summary> ///打开端口/// </summary> /// <returns></returns> public voidOpenPort()/// <summary> ///关闭端口/// </summary> public voidClosePort()/// <summary> ///丢弃来自串行驱动程序的接收和发送缓冲区的数据/// </summary> public voidDiscardBuffer()#region 数据写入操作 /// <summary> ///写入数据/// </summary> /// <param name="msg"></param> public void WriteData(stringmsg)/// <summary> ///写入数据/// </summary> /// <param name="msg">写入端口的字节数组</param> public void WriteData(byte[] msg)/// <summary> ///写入数据/// </summary> /// <param name="msg">包含要写入端口的字节数组</param> /// <param name="offset">参数从0字节开始的字节偏移量</param> /// <param name="count">要写入的字节数</param> public void WriteData(byte[] msg, int offset, intcount)/// <summary> ///发送串口命令/// </summary> /// <param name="SendData">发送数据</param> /// <param name="ReceiveData">接收数据</param> /// <param name="Overtime">重复次数</param> /// <returns></returns> public int SendCommand(byte[] SendData, ref byte[] ReceiveData, intOvertime)#endregion #region 常用的列表数据获取和绑定操作 /// <summary> ///封装获取串口号列表/// </summary> /// <returns></returns> public static string[] GetPortNames()/// <summary> ///设置串口号/// </summary> /// <param name="obj"></param> public static voidSetPortNameValues(ComboBox obj)/// <summary> ///设置波特率/// </summary> public static voidSetBauRateValues(ComboBox obj)/// <summary> ///设置数据位/// </summary> public static voidSetDataBitsValues(ComboBox obj)/// <summary> ///设置校验位列表/// </summary> public static voidSetParityValues(ComboBox obj)/// <summary> ///设置停止位/// </summary> public static voidSetStopBitValues(ComboBox obj)#endregion /// <summary> ///检查端口名称是否存在/// </summary> /// <param name="port_name"></param> /// <returns></returns> public static bool Exists(stringport_name)/// <summary> ///格式化端口相关属性/// </summary> /// <param name="port"></param> /// <returns></returns> public static stringFormat(SerialPort port)
}
2)辅助类的使用代码如下所示。
绑定相应的数据源(包括端口、波特率、数据位、校验位等等)代码如下所示,这样我们在窗体界面代码中,绑定相关参数的数据源就很方便了,如下所示。
private void Form1_Load(objectsender, EventArgs e)
{
BindData();
}private voidBindData()
{//绑定端口号 SerialPortUtil.SetPortNameValues(txtPort);
txtPort.SelectedIndex= 0;//波特率 SerialPortUtil.SetBauRateValues(txtBaudRate);
txtBaudRate.SelectedText= "57600";//数据位 SerialPortUtil.SetDataBitsValues(txtDataBits);this.txtDataBits.SelectedText = "8";//校验位 SerialPortUtil.SetParityValues(txtParity);this.txtParity.SelectedIndex = 0;//停止位 SerialPortUtil.SetStopBitValues(txtStopBit);this.txtStopBit.SelectedIndex = 1;this.btnSend.Enabled =isOpened;
}
辅助类实现连接特定的窗口并处理数据的操作代码如下所示。
private void btnConnect_Click(objectsender, EventArgs e)
{try{if (serial == null)
{try{string portname = this.txtPort.Text;
SerialPortBaudRates rate= (SerialPortBaudRates)Enum.Parse(typeof(SerialPortBaudRates), this.txtBaudRate.Text);//int.Parse(this.txtBaudRate.Text); SerialPortDatabits databit = (SerialPortDatabits)int.Parse(this.txtDataBits.Text);
Parity party= (Parity)Enum.Parse(typeof(Parity), this.txtParity.Text);
StopBits stopbit= (StopBits)Enum.Parse(typeof(StopBits), this.txtStopBit.Text);//使用枚举参数构造//serial = new SerialPortUtil(portname, rate, party, databit, stopbit);//使用字符串参数构造 serial = new SerialPortUtil(portname, this.txtBaudRate.Text, this.txtParity.Text, this.txtDataBits.Text, this.txtStopBit.Text);
serial.DataReceived+= newDataReceivedEventHandler(serial_DataReceived);
}catch(Exception ex)
{
MessageBox.Show(ex.Message);
serial= null;return;
}
}if (!isOpened)
{
serial.OpenPort();
btnConnect.Text= "断开";
}else{
serial.ClosePort();
serial= null;
btnConnect.Text= "连接";
}
isOpened= !isOpened;this.btnSend.Enabled =isOpened;this.lblTips.Text = isOpened ? "已连接" : "未连接";
}catch(Exception ex)
{this.lblTips.Text =ex.Message;
MessageBox.Show(ex.Message);
}
}
4、POS打印机操作
本小节包括两个POS打印类,USB接口方式的POS小票打印的打印预览管理界面 FrmPosPrintPreview和基于并口接口方式的打印辅助类POSPrinter。
基于USB接口方式的POS小票打印该操作。很多基本上采用了GP5860这种POS打印机进行小票打印了。
执行打印预览,USB接口方式的小票可以实现效果的预览,如果是并口的只有直接输出,没有预览效果。
1)USB的POS打印的辅助类FrmPosPrintPreview提供了几个常用的参数进行配置,代码如下所示。
/// <summary> ///POS小票打印的打印预览管理界面/// </summary> public partial classFrmPosPrintPreview : Form
{/// <summary> ///设置待打印的内容/// </summary> public string PrintString = "";/// <summary> ///指定默认的小票打印机名称,用作快速POS打印/// </summary> public string PrinterName = "GP-5860III";/// <summary> ///POS打印机的边距,默认为2/// </summary> public int POSPageMargin = 2;/// <summary> ///POS打印机默认横向还是纵向,默认设置为纵向(false)/// </summary> public bool Landscape = false;
2)并口的POS打印辅助类POSPrinter提供了两个构造函数和一个打印操作,代码如下。
/// <summary> ///并口POS打印机操作辅助类/// </summary> public classPOSPrinter
{/// <summary> ///默认构造函数,打印并口名称为LPT1/// </summary> publicPOSPrinter()/// <summary> ///以指定的并口打印名称构造函数/// </summary> /// <param name="prnPort">打印并口名称,如LPT1</param> public POSPrinter(stringprnPort)/// <summary> ///打印内容/// </summary> /// <param name="str">待打印的字符串</param> /// <returns></returns> public string PrintLine(string str)
3)辅助类的使用例子代码如下所示
private void btnPosPrint_Click(objectsender, EventArgs e)
{if (this.lvwDetail.Items.Count == 0)
{
MessageUtil.ShowTips("没有消费记录");return;
}
StringBuilder sb= newStringBuilder();
sb.AppendFormat("{0}\r\n\r\n", Portal.gc.gAppUnit);
sb.AppendFormat("客房消费\r\n");
sb.AppendFormat("结账单号:{0}\r\n", this.lblCheckOutNo.Text);
sb.AppendFormat("客户姓名:{0}\r\n", this.txtName.Text);
sb.AppendFormat("结账客房:{0}\r\n", RoomInfo.RoomNo);
sb.AppendFormat("打印时间:{0}\r\n\r\n", DateTime.Now);
sb.AppendFormat("项目 单价 数量 金额\r\n");for (int i = 0; i < lvwDetail.Items.Count; i++)
{
ListViewItem item=lvwDetail.Items[i];string itemName = item.SubItems[1].Text;if (itemName.Contains("买断消费"))
{
itemName= "买断消费";
}
sb.AppendFormat("{0}", itemName);
sb.AppendFormat("{0}", item.SubItems[2].Text);
sb.AppendFormat("{0}", item.SubItems[6].Text);
sb.AppendFormat("{0}\r\n", item.SubItems[7].Text);
}
sb.AppendFormat("\r\n\r");
sb.AppendFormat("总 金 额:{0}\r\n", Convert.ToDecimal(this.lblConsume.Tag).ToString("C2"));
sb.AppendFormat("实收金额:{0}\r\n", Convert.ToDecimal(this.txtAmount.Text).ToString("C2"));
sb.AppendFormat("实收大写:{0}\r\n", RMBUtil.CmycurD(this.txtAmount.Text));
sb.AppendFormat("现 金:{0}\r\n", Convert.ToDecimal(this.txtPay.Text).ToString("C2"));
sb.AppendFormat("找 零:{0}\r\n", Convert.ToDecimal(this.lblChange.Text).ToString("C2"));
sb.AppendFormat("\r\n\r");
Portal.gc.PosPrint(sb.ToString());
}
/// <summary> ///提供通用的POS打印函数/// </summary> public void PosPrint(stringprintString)
{bool useUSB =SystemConfig.Default.IsUSBPOSPrinter;if (!useUSB)
{if (MessageUtil.ShowYesNoAndTips("您是否确定进行POS打印?") ==DialogResult.No)
{return;
}
POSPrinter print= newPOSPrinter(SystemConfig.Default.PosPrintPort);string error =print.PrintLine(printString);if (error != "")
{
MessageUtil.ShowError(error);
}
}else{
FrmPosPrintPreview dlg= newFrmPosPrintPreview();
printString= "\r\n\r\n\r\n\r\n" +printString;
printString+= string.Format("\r\n签单金额:\r\n");
printString+= string.Format("\r\n签单单位:\r\n");
printString+= string.Format("\r\n签 单 人:\r\n");
dlg.PrintString=printString;
dlg.ShowDialog();
}
}
5、玻璃效果图片按钮控件 VistaButton
本辅助类主要是用来方便实现美观的图片按钮,类似玻璃效果的那种,图片放上去可以带有动态阴影效果。 这个是一个Vista样式的控件,其代码是在Codeproject上有的:
http://www.codeproject.com/KB/buttons/VistaButton.aspx
通过改变其颜色,就可以实现不同的效果,而且鼠标靠近或者离开都有特殊的效果,比较酷。例如我加上颜色图片后,得到的效果如下所示:
使用说明:
在VS工具箱里面添加该共用类库的程序集应用,然后添加VistaButton控件的使用即可。
可以在窗体的可视化设计界面中,编辑控件的背景色等图片效果,实现更多美妙的特效。
该控件属于界面控件,直接拖动到界面即可使用。
6、TreeView的包装类,实现树的DragDrop拖拉的操作的辅助类 TreeViewDrager
1)辅助类提供的方法接口如下所示:
public classTreeViewDrager
{/// <summary> ///设置拖动树的时候,显示的图片,显示其中第一个/// </summary> publicImageList TreeImageList/// <summary> ///默认构造函数/// </summary> publicTreeViewDrager()/// <summary> ///参数构造函数,设置操作的TreeView/// </summary> /// <param name="treeView"></param> publicTreeViewDrager(TreeView treeView)/// <summary> ///处理拖动节点后的事件/// </summary> public eventProcessDragNodeEventHandler ProcessDragNode;
}
2)辅助类的使用例子代码如下所示
private voidInit()
{
TreeViewDrager treeViewDrager= new TreeViewDrager(this.treeView1);
treeViewDrager.TreeImageList= this.imageList1;//不设置这个也可以,只是拖动的时候没图标。 treeViewDrager.ProcessDragNode += newProcessDragNodeEventHandler(treeViewDrager_ProcessDragNode);
}private bool treeViewDrager_ProcessDragNode(TreeNode from, TreeNode to)
{//这里根据from/to两个节点记录的信息去进行数据库持久化的工作。//根据持久化的结果决定节点是否会最终实现拖动操作。 return true;
}
实际上,我们需要处理拖动后的事件,一般来说,我们需要调整他们的父目录就可以了,如我的通用字典管理模块,就是利用这个控件实现拖动效果。
publicFrmDictionary()
{
InitializeComponent();
TreeViewDrager drager= new TreeViewDrager(this.treeView1);
drager.TreeImageList= this.imageList1;
drager.ProcessDragNode+= newProcessDragNodeEventHandler(drager_ProcessDragNode);
}booldrager_ProcessDragNode(TreeNode dragNode, TreeNode dropNode)
{if (dragNode != null && dragNode.Text == "数据字典管理")return false;if (dropNode != null && dropNode.Tag != null)
{string dropTypeId =dropNode.Tag.ToString();string dragTypeId =dragNode.Tag.ToString();//MessageUtil.ShowTips(string.Format("dropTypeId:{0} dragTypeId:{1}", dropTypeId, drageTypeId)); try{
DictTypeInfo dragTypeInfo= BLLFactory<DictType>.Instance.FindByID(dragTypeId);if (dragTypeInfo != null)
{
dragTypeInfo.PID=dropTypeId;
BLLFactory<DictType>.Instance.Update(dragTypeInfo, dragTypeInfo.ID);
}
}catch(Exception ex)
{
LogHelper.Error(ex);
MessageUtil.ShowError(ex.Message);return false;
}
}return true;
}