2023年2月

俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。

本篇的公用类库的介绍主题是程序开发中常用到的各种格式转换或者数据验证的辅助类,内容范围可能比较广泛,包括XML操作、序列化及反序列化操作、命令行解析,枚举对象操作,数据格式验证等等,不过都是不可多得、好用的辅助类。

本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。


厚积薄发,丰富的公用类库积累,助你高效进行系统开发(8)----非对称加密、BASE64加密、MD5等常用加密处理

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(7)-----声音播放、硬件信息、键盘模拟及钩子、鼠标模拟及钩子等设备相关

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(6)----全屏截图、图标获取、图片打印、页面预览截屏、图片复杂操作等

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)----CSV、Excel、INI文件、独立存储等文件相关

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(3)----数据库相关操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(2)----常用操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(1)----开篇总结

1、序列化、反序列化、节点等操作类辅助类 XmlHelper。

实现效果

1)本辅助类主要是用来方便实现XML序列化、反序列化、节点等操作。

2)序列化是指一个对象的实例可以被保存,保存成一个二进制串或者XML等格式字符串。反序列化这是从这些内容中还原为一个对象实例的操作。
3)要实现对象的序列化,首先要保证该对象可以序列化。而且,序列化只是将对象的属性进行有效的保存,对于对象的一些方法则无法实现序列化的。实现一个类可序列化的最简便的方法就是增加Serializable属性标记类。
4)DOM(文档对象模型)把层次中的每一个对象都称之为节点(NODE),以HTML超文本标记语言为例:整个文档的一个根就是<html>,在DOM中可以使用
document.documentElement来访问它,它就是整个节点树的根节点(ROOT)。

实现代码

1)辅助类提供的方法接口如下所示:

///

<summary>


///
构造函数

///

</summary>


///

<param name="XmlFile">
XML文件路径
</param>



public
XmlHelper(
string
XmlFile)

#region
静态方法

///

<summary>


///
二进制序列化

///

</summary>


///

<param name="path">
文件路径
</param>


///

<param name="obj">
对象实例
</param>


///

<returns></returns>



public
static
bool
Serialize(
string
path,
object
obj)

///

<summary>


///
XML序列化

///

</summary>


///

<param name="path">
文件路径
</param>


///

<param name="obj">
对象实例
</param>


///

<returns></returns>



public
static
bool
XmlSerialize(
string
path,
object
obj, Type type)

///

<summary>


///
二进制反序列化

///

</summary>


///

<param name="path">
文件路径
</param>


///

<returns></returns>



public
static
object
Deserialize(
string
path)

///

<summary>


///
XML反序列化

///

</summary>


///

<param name="path">
文件路径
</param>


///

<param name="type">
对象类型
</param>


///

<returns></returns>



public
static
object
XmlDeserialize(
string
path, Type type)

#endregion

#region
公用方法

///

<summary>


///
获取指定节点下面的XML子节点

///

</summary>


///

<param name="XmlPathNode">
XML节点
</param>


///

<returns></returns>



public
XmlNodeList Read(
string
XmlPathNode)

///

<summary>


///
读取节点属性内容

///

</summary>


///

<param name="XmlPathNode">
XML节点
</param>


///

<param name="Attrib">
节点属性
</param>


///

<returns></returns>



public
string
Read(
string
XmlPathNode,
string
Attrib)

///

<summary>


///
获取元素节点对象

///

</summary>


///

<param name="XmlPathNode">
XML节点
</param>


///

<param name="elementName">
元素节点名称
</param>


///

<returns></returns>



public
XmlElement GetElement(
string
XmlPathNode,
string
elementName)

///

<summary>


///
获取元素节点的值

///

</summary>


///

<param name="XmlPathNode">
XML节点
</param>


///

<param name="elementName">
元素节点名称
</param>


///

<returns></returns>



public
string
GetElementData(
string
XmlPathNode,
string
elementName)

///

<summary>


///
获取节点下的DataSet

///

</summary>


///

<param name="XmlPathNode">
XML节点
</param>


///

<returns></returns>



public
DataSet GetData(
string
XmlPathNode)

///

<summary>


///
替换某节点的内容

///

</summary>


///

<param name="XmlPathNode">
XML节点
</param>


///

<param name="Content">
节点内容
</param>



public
void
Replace(
string
XmlPathNode,
string
Content)

///

<summary>


///
删除节点

///

</summary>


///

<param name="Node">
节点
</param>



public
void
Delete(
string
Node)

///

<summary>


///
插入一节点和此节点的一子节点

///

</summary>


///

<param name="MainNode"></param>


///

<param name="ChildNode"></param>


///

<param name="Element"></param>


///

<param name="Content"></param>



public
void
InsertNode(
string
MainNode,
string
ChildNode,
string
Element,
string
Content)

///

<summary>


///
插入一个节点带一个属性

///

</summary>


///

<param name="MainNode">
指定的XML节点
</param>


///

<param name="Element">
元素名称
</param>


///

<param name="Attrib">
属性名称
</param>


///

<param name="AttribContent">
属性值
</param>


///

<param name="Content">
内容
</param>



public
void
InsertElement(
string
MainNode,
string
Element,
string
Attrib,
string
AttribContent,
string
Content)

///

<summary>


///
插入XML元素

///

</summary>


///

<param name="MainNode">
指定的XML节点
</param>


///

<param name="Element">
元素名称
</param>


///

<param name="Content">
内容
</param>



public
void
InsertElement(
string
MainNode,
string
Element,
string
Content)

///

<summary>


///
保存XML文档

///

</summary>

public
void
Save()

2)辅助类XmlHelper的使用例子代码如下所示

SearchInfo searchInfo =
new
SearchInfo();

searchInfo.FieldName =
"
TestFeild
"
;
searchInfo.FieldValue =
"
TestValue
"
;

string
file =
@"
C:\searchInfo.xml
"
;
XmlHelper.XmlSerialize(file, searchInfo,
typeof
(SearchInfo));

SearchInfo info2FromXml = XmlHelper.XmlDeserialize(file,
typeof
(SearchInfo))
as
SearchInfo;
Console.WriteLine(
"
{0} : {0}
"
, info2FromXml.FieldName, info2FromXml.FieldValue);

XML序列化文件如下所示,并能通过该文件反序列化到对象实例中。

3)辅助类XmlHelper操作节点的例子代码如下所示。

//
bookstore.xml文件内容

/*


<?xml version="1.0" encoding="gb2312"?>
<bookstore>
<book genre="fantasy" ISBN="2-3631-4">
<title>Oberon's Legacy</title>
<author>Corets, Eva</author>
<price>5.95</price>
</book>
</bookstore>

*/
file =
@"
c:\bookstore.xml
"
;
XmlHelper helper =
new
XmlHelper(file);
string
value = helper.Read(
"
bookstore/book
"
,
"
genre
"
);
Console.WriteLine(value);
//
fantasy


value = helper.Read(
"
bookstore/book
"
,
"
ISBN
"
);
Console.WriteLine(value);
//
2-3631-4


value = helper.GetElementData(
"
bookstore/book
"
,
"
title
"
);
Console.WriteLine(value);
//
Oberon's Legacy


XmlElement element = helper.GetElement(
"
bookstore/book
"
,
"
title
"
);
element.InnerText =
"
伍华聪
"
;

DataSet ds = helper.GetData(
"
bookstore/book
"
);

ds.WriteXml(
@"
C:\ds.xml
"
);


2、序列化和反序列化操作辅助类 Serializer。

实现效果

1)本辅助类主要是用来方便实现序列化合反序列化操作。

2)序列化是指一个对象的实例可以被保存,保存成一个二进制串或者XML等格式字符串。反序列化这是从这些内容中还原为一个对象实例的操作。
本序列化和反序列化操作,提供二进制、XML格式、Soap格式等多种方式的操作,方便对对象实例进行各种序列化操作或者对各种格式文件的反序列化操作。

实现代码

1)辅助类提供的方法接口如下所示:

#region
各种格式的序列化操作
///

<summary>


///
序列化对象到二进制字节数组

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<returns></returns>



public
static
byte
[] SerializeToBinary(
object
obj)

///

<summary>


///
序列化对象到指定的文件中

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<param name="path">
文件路径
</param>


///

<param name="mode">
文件打开方式
</param>



public
static
void
SerializeToBinary(
object
obj,
string
path, FileMode mode)

///

<summary>


///
序列号对象到文件中,创建一个新文件

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<param name="path">
文件路径
</param>



public
static
void
SerializeToBinary(
object
obj,
string
path)

///

<summary>


///
序列化对象到Soap字符串中

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<returns></returns>



public
static
string
SerializeToSoap(
object
obj)

///

<summary>


///
序列化对象到Soap字符串中,并保存到文件

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<param name="path">
文件路径
</param>


///

<param name="mode">
文件打开方式
</param>



public
static
void
SerializeToSoap(
object
obj,
string
path, FileMode mode)

///

<summary>


///
序列化对象到Soap字符串中,并保存到文件

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<param name="path">
文件路径
</param>



public
static
void
SerializeToSoap(
object
obj,
string
path)

///

<summary>


///
序列化对象到XML字符串中

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<returns></returns>



public
static
string
SerializeToXml(
object
obj)

///

<summary>


///
序列化对象到XML字符串,并保存到文件中

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<param name="path">
文件路径
</param>


///

<param name="mode">
文件打开方式
</param>



public
static
void
SerializeToXmlFile(
object
obj,
string
path, FileMode mode)

///

<summary>


///
序列化对象到XML字符串,并保存到文件中

///

</summary>


///

<param name="obj">
待序列化的对象
</param>


///

<param name="path">
文件路径
</param>



public
static
void
SerializeToXmlFile(
object
obj,
string
path)

#endregion


///

<summary>


///
从指定的文件中反序列化到具体的对象

///

</summary>


///

<param name="type">
对象的类型
</param>


///

<param name="path">
文件路径
</param>


///

<returns></returns>



public
static
object
DeserializeFromXmlFile(Type type,
string
path)

///

<summary>


///
从指定的XML字符串中反序列化到具体的对象

///

</summary>


///

<param name="type">
对象的类型
</param>


///

<param name="s">
XML字符串
</param>


///

<returns></returns>



public
static
object
DeserializeFromXml(Type type,
string
s)

///

<summary>


///
从指定的Soap协议字符串中反序列化到具体的对象

///

</summary>


///

<param name="type">
对象的类型
</param>


///

<param name="s">
Soap协议字符串
</param>


///

<returns></returns>



public
static
object
DeserializeFromSoap(Type type,
string
s)

///

<summary>


///
从指定的二进制字节数组中反序列化到具体的对象

///

</summary>


///

<param name="type">
对象的类型
</param>


///

<param name="bytes">
二进制字节数组
</param>


///

<returns></returns>



public
static
object
DeserializeFromBinary(Type type,
byte
[] bytes)

///

<summary>


///
从指定的文件总,以二进制字节数组中反序列化到具体的对象

///

</summary>


///

<param name="type">
对象的类型
</param>


///

<param name="bytes">
二进制字节数组存储的文件
</param>


///

<returns></returns>



public
static
object
DeserializeFromBinary(Type type,
string
path)

///

<summary>


///
获取对象的字节数组大小

///

</summary>


///

<param name="o">
对象
</param>


///

<returns></returns>



public
static
long
GetByteSize(
object
o)

///

<summary>


///
克隆一个对象

///

</summary>


///

<param name="o">
对象
</param>


///

<returns></returns>



public
static
object
Clone(
object
o)

2)辅助类的使用例子代码如下所示

public
class
TestSerializeUtil

{
public
static
string
Execute()
{
string
result =
string
.Empty;
result +=
"
使用SerializeUtil序列化及反序列化的辅助类:
"
+
"
\r\n
"
;

Person person =
new
Person();
person.Name =
"
wuhuacong
"
;
person.Age =
20
;

byte
[] bytes = SerializeUtil.SerializeToBinary(person);
Person person2 = SerializeUtil.DeserializeFromBinary(
typeof
(Person), bytes)
as
Person;
result += ReflectionUtil.GetProperties(person2) +
"
\r\n
"
;

string
xml = SerializeUtil.SerializeToXml(person);
Person person3 = SerializeUtil.DeserializeFromXml(
typeof
(Person), xml)
as
Person;
result +=
"
person3:\r\n
"
+ ReflectionUtil.GetProperties(person3) +
"
\r\n
"
;

result +=
"
SerializeUtil.GetByteSize(person3):
"
+ SerializeUtil.GetByteSize(person3) +
"
\r\n
"
;

Person person4 = SerializeUtil.Clone(person3)
as
Person;
result +=
"
person4:\r\n
"
+ ReflectionUtil.GetProperties(person4) +
"
\r\n
"
;

result +=
"
Util.AreObjectsEqual(person3, person4):
"
+ Util.AreObjectsEqual(person3, person4)+
"
\r\n
"
;

SerializeUtil.SerializeToXmlFile(person3, Util.CurrentPath +
"
person3.xml
"
, FileMode.Create);
Person person5 = SerializeUtil.DeserializeFromXmlFile(
typeof
(Person), Util.CurrentPath +
"
person3.xml
"
)
as
Person;
result +=
"
person5:\r\n
"
+ ReflectionUtil.GetProperties(person5) +
"
\r\n\r\n
"
;

result += SerializeUtil.ReadFile(Util.CurrentPath +
"
person3.xml
"
) +
"
\r\n\r\n
"
;
result += SerializeUtil.ReadFileFromEmbedded(
"
TestUtilities.EmbedFile.xml
"
) +
"
\r\n\r\n
"
;

return
result;
}
}

3、实现命令行解析的常用操作的辅助类 CommandLine。

实现效果

1)本辅助类主要是用来方便实现命令行解析的常用操作,命令行的解析在很多情况下是非常必要的,如自动并带参数启动的操作等。

2)命令行参数。这包括两个列表,一个是参数对,一个是独立的参数。
3)参数是定义为键/值对。参数键必须以'-', '--'或者'\'开始,在参数和值之间必须有一个空格或者字符'='。多余的空格将被忽略。参数后面必须跟着一个值,如果没有指定值,那么字符串'true'将被指定。如果值有空格,必须使用双引号来包含字符,否则字符不能被正确解析。

实现代码

1)辅助类提供的方法接口如下所示:

///

<summary>


///
解析传递的命令行参数,并返回结果到一个CommandArgs对象。

///
假设命令行格式: CMD [param] [[-|--|\]&lt;arg&gt;[[=]&lt;value&gt;]] [param]

///
例如:cmd first -o outfile.txt --compile second \errors=errors.txt third fourth --test = "the value" fifth

///

</summary>


///

<param name="args">
命令行参数数组
</param>


///

<returns>
包含转换后的命令行对象CommandArgs
</returns>

public
static
CommandArgs Parse(
string
[] args)

///

<summary>


///
包含解析的命令行参数。这包括两个列表,一个是参数对,一个是独立的参数。

///

</summary>



public
class
CommandArgs
{
///

<summary>


///
返回参数/参数值的键值字典

///

</summary>



public
Dictionary<
string
,
string
> ArgPairs

///

<summary>


///
返回独立的参数列表

///

</summary>



public
List<
string
> Params

}

2)辅助类的使用例子代码如下所示

///

<summary>


///
应用程序的主入口点。

///

</summary>



[STAThread]
static
void
Main(
string
[] args)
{
//
参数字符串:first -o outfile.txt --compile second \errors=errors.txt third fourth --test = "the value" fifth


CommandArgs objArgs = CommandLine.Parse(args);

//
键值参数列表,得到输出

//
o:outfile.txt

//
compile:second

//
errors:errors.txt

//
test:the value


foreach
(
string
str
in
objArgs.ArgPairs.Keys)
{
Debug.WriteLine(
string
.Format(
"
{0}:{1}
"
, str, objArgs.ArgPairs[str]));
}


//
非键值参数列表:得到first third fourth fifth 共四个字符串


foreach
(
string
str
in
objArgs.Params)
{
Debug.WriteLine(str);
}

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false
);
Application.Run(
new
Form1());

}

3)输出结果如下所示

我们给程序输入命令行参数first -o outfile.txt --compile second \errors=errors.txt third fourth --test = "the value" fifth,得到的输出结果如下所示。
o
:outfile
.txt
compile
:second
errors
:errors
.txt
test
:the
value
first
third
fourth
fifth


4、枚举操作辅助类 EnumHelper。

实现效果

1)本辅助类主要是用来方便实现枚举的各种相关操作。

2)枚举操作,涉及字符串和枚举对象互转、获取枚举成员、获取名称和值集合、获取枚举值、枚举描述等操作。
3)枚举可以说是一种强类型的对象操作,比起使用古怪字符、或者数值等内容,具有强类型,编译时刻就确定等特点,在实际开发中,我们还可以使用中文枚举来方便实现各种操作。

实现代码

1)辅助类提供的方法接口如下所示:

///

<summary>


///
通过字符串获取枚举成员实例

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>


///

<param name="member">
枚举成员的常量名或常量值,

///
范例:Enum1枚举有两个成员A=0,B=1,则传入"A"或"0"获取 Enum1.A 枚举类型
</param>



public
static
T GetInstance<T>(
string
member)

///

<summary>


///
获取枚举成员名称和成员值的键值对集合

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>



public
static
Dictionary<
string
,
object
> GetMemberKeyValue<T>()

///

<summary>


///
获取枚举所有成员名称

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>



public
static
string
[] GetMemberNames<T>()

///

<summary>


///
获取枚举成员的名称

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>


///

<param name="member">
枚举成员实例或成员值,

///
范例:Enum1枚举有两个成员A=0,B=1,则传入Enum1.A或0,获取成员名称"A"
</param>



public
static
string
GetMemberName<T>(
object
member)

///

<summary>


///
获取枚举所有成员值

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>



public
static
Array GetMemberValues<T>()

///

<summary>


///
获取枚举成员的值

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>


///

<param name="memberName">
枚举成员的常量名,

///
范例:Enum1枚举有两个成员A=0,B=1,则传入"A"获取0
</param>



public
static
object
GetMemberValue<T>(
string
memberName)

///

<summary>


///
获取枚举的基础类型

///

</summary>


///

<param name="enumType">
枚举类型
</param>



public
static
Type GetUnderlyingType(Type enumType)

///

<summary>


///
检测枚举是否包含指定成员

///

</summary>


///

<typeparam name="T">
枚举名,比如Enum1
</typeparam>


///

<param name="member">
枚举成员名或成员值
</param>



public
static
bool
IsDefined<T>(
string
member)

///

<summary>


///
返回指定枚举类型的指定值的描述

///

</summary>


///

<param name="t">
枚举类型
</param>


///

<param name="v">
枚举值
</param>


///

<returns></returns>



public
static
string
GetDescription(System.Type t,
object
v)

///

<summary>


///
返回指定枚举类型的指定值的名称

///

</summary>


///

<param name="t">
指定枚举类型
</param>


///

<param name="v">
指定值
</param>


///

<returns></returns>



private
static
string
GetName(System.Type t,
object
v)

///

<summary>


///
获取枚举类型的对应序号及描述名称

///

</summary>


///

<param name="t">
枚举类型
</param>


///

<returns></returns>

public
static
SortedList GetStatus(System.Type t)

2)辅助类的使用例子代码如下所示

private
void
btnTestEnum_Click(
object
sender, EventArgs e)
{
string
desc = EnumHelper.GetDescription(
typeof
(SqlOperator), SqlOperator.Like);
MessageUtil.ShowTips(
string
.Format(
"
SqlOperator.Like:{0}
"
, desc));

SortedList list = EnumHelper.GetStatus(
typeof
(SqlOperator));
StringBuilder sb =
new
StringBuilder();
foreach
(
int
key
in
list.Keys)
{
sb.AppendFormat(
"
key:{0} Value:{1} \r\n
"
, key, list[key]);
}
MessageUtil.ShowTips(sb.ToString());
}

5、身份证相关操作辅助类 IDCardHelper。

实现效果

1)本辅助类主要是用来方便实现身份证的各种相关操作,验证身份证、15到18位身份证号码转换、提取省份、县市、地区区划、出生年月及判断男女等操作。

实现代码

1)辅助类提供的方法接口如下所示:

///

<summary>


///
绑定身份证类别的名称

///

</summary>


///

<param name="cb">
ComboBox控件
</param>



public
static
void
InitIdType(ComboBox cb)

///

<summary>


///
获取身份证类别的名称(居民身份证、军官证、士兵证、军官离退休证、境外人员身份证明、外交人员身份证明)

///

</summary>


///

<returns></returns>



public
static
DataTable CreateIDType()

///

<summary>


///
验证身份证结果

///

</summary>


///

<param name="idcard">
身份证号码
</param>


///

<returns>
正确的时候返回string.Empty
</returns>



public
static
string
Validate(
string
idcard)

///

<summary>


///
15位身份证明号码转化成18位用来编码

///

</summary>


///

<param name="idcard">
15位的身份证号码
</param>


///

<returns></returns>



public
static
string
IdCard15To18(
string
idcard)

///

<summary>


///
获取身份证对应省份的区划

///

</summary>


///

<param name="id">
身份证
</param>


///

<returns>
头两位+4个0
</returns>



public
static
string
GetProvince(
string
id)

///

<summary>


///
获取身份证对应县市的区划

///

</summary>


///

<param name="id">
身份证
</param>


///

<returns>
头4位+2个0
</returns>



public
static
string
GetCity(
string
id)

///

<summary>


///
获取身份证对应地区的区划

///

</summary>


///

<param name="id">
身份证
</param>


///

<returns>
头6位
</returns>



public
static
string
GetArea(
string
id)

///

<summary>


///
根据身份证判断是否男女

///

</summary>


///

<param name="id">
身份证号码
</param>


///

<returns>
返回"男"或者"女"
</returns>



public
static
string
GetSexName(
string
id)

///

<summary>


///
根据身份证获取出生年月

///

</summary>


///

<param name="id">
身份证号码
</param>


///

<returns>
出生年月
</returns>

public
static
DateTime GetBirthday(
string
id)

2)辅助类的使用例子代码如下所示

  • 例子涉及敏感信息,自己测试下即可,呵呵
  • 6、各种输入格式验证辅助类 ValidateUtil。

    实现效果

    1)本辅助类主要是用来方便实现各种输入格式验证操作。

    2)格式验证包括各种数字格式、中文检测、身份证、邮件、邮政编码、固定电话、手机、URL地址、IP地址、日期格式、GUID、Base64编码等格式验证。
    3)本辅助类采用各种经过验证的正则表达式进行匹配,具有高效、准确的特点,请放心使用。

    实现代码

    1)辅助类提供的方法接口如下所示:

    #region
    用户名密码格式

    ///

    <summary>


    ///
    返回字符串真实长度, 1个汉字长度为2

    ///

    </summary>


    ///

    <returns>
    字符长度
    </returns>



    public
    static
    int
    GetStringLength(
    string
    stringValue)

    ///

    <summary>


    ///
    检测用户名格式是否有效

    ///

    </summary>


    ///

    <param name="userName">
    用户名
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsValidUserName(
    string
    userName)

    ///

    <summary>


    ///
    密码有效性

    ///

    </summary>


    ///

    <param name="password">
    密码字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsValidPassword(
    string
    password)

    #endregion

    #region
    数字字符串检查

    ///

    <summary>


    ///
    int有效性

    ///

    </summary>



    static
    public
    bool
    IsValidInt(
    string
    val)

    ///

    <summary>


    ///
    是否数字字符串

    ///

    </summary>


    ///

    <param name="inputData">
    输入字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsNumeric(
    string
    inputData)

    ///

    <summary>


    ///
    是否数字字符串

    ///

    </summary>


    ///

    <param name="inputData">
    输入字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsNumber(
    string
    inputData)

    ///

    <summary>


    ///
    是否数字字符串 可带正负号

    ///

    </summary>


    ///

    <param name="inputData">
    输入字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsNumberSign(
    string
    inputData)

    ///

    <summary>


    ///
    是否是浮点数

    ///

    </summary>


    ///

    <param name="inputData">
    输入字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsDecimal(
    string
    inputData)

    ///

    <summary>


    ///
    是否是浮点数 可带正负号

    ///

    </summary>


    ///

    <param name="inputData">
    输入字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsDecimalSign(
    string
    inputData)

    #endregion

    #region
    中文检测

    ///

    <summary>


    ///
    检测是否有中文字符

    ///

    </summary>



    public
    static
    bool
    IsHasCHZN(
    string
    inputData)

    ///

    <summary>


    ///
    检测含有中文字符串的实际长度

    ///

    </summary>


    ///

    <param name="str">
    字符串
    </param>



    public
    static
    int
    GetCHZNLength(
    string
    inputData)

    #endregion

    #region
    常用格式

    ///

    <summary>


    ///
    验证身份证是否合法  15 和  18位两种

    ///

    </summary>


    ///

    <param name="idCard">
    要验证的身份证
    </param>



    public
    static
    bool
    IsIdCard(
    string
    idCard)

    ///

    <summary>


    ///
    是否是邮件地址

    ///

    </summary>


    ///

    <param name="inputData">
    输入字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsEmail(
    string
    inputData)

    ///

    <summary>


    ///
    邮编有效性

    ///

    </summary>



    public
    static
    bool
    IsValidZip(
    string
    zip)

    ///

    <summary>


    ///
    固定电话有效性

    ///

    </summary>



    public
    static
    bool
    IsValidPhone(
    string
    phone)

    ///

    <summary>


    ///
    手机有效性

    ///

    </summary>



    public
    static
    bool
    IsValidMobile(
    string
    mobile)

    ///

    <summary>


    ///
    电话有效性(固话和手机 )

    ///

    </summary>



    public
    static
    bool
    IsValidPhoneAndMobile(
    string
    number)

    ///

    <summary>


    ///
    Url有效性

    ///

    </summary>



    static
    public
    bool
    IsValidURL(
    string
    url)

    ///

    <summary>


    ///
    IP有效性

    ///

    </summary>



    public
    static
    bool
    IsValidIP(
    string
    ip)

    ///

    <summary>


    ///
    domain 有效性

    ///

    </summary>


    ///

    <param name="host">
    域名
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsValidDomain(
    string
    host)

    ///

    <summary>


    ///
    判断是否为base64字符串

    ///

    </summary>



    public
    static
    bool
    IsBase64String(
    string
    str)

    ///

    <summary>


    ///
    验证字符串是否是GUID

    ///

    </summary>


    ///

    <param name="guid">
    字符串
    </param>


    ///

    <returns></returns>



    public
    static
    bool
    IsGuid(
    string
    guid)

    #endregion

    #region
    日期检查

    ///

    <summary>


    ///
    判断输入的字符是否为日期

    ///

    </summary>



    public
    static
    bool
    IsDate(
    string
    strValue)

    ///

    <summary>


    ///
    判断输入的字符是否为日期,如2004-07-12 14:25|||1900-01-01 00:00|||9999-12-31 23:59

    ///

    </summary>



    public
    static
    bool
    IsDateHourMinute(
    string
    strValue)

    #endregion

    #region
    其他

    ///

    <summary>


    ///
    检查字符串最大长度,返回指定长度的串

    ///

    </summary>


    ///

    <param name="sqlInput">
    输入字符串
    </param>


    ///

    <param name="maxLength">
    最大长度
    </param>


    ///

    <returns></returns>



    public
    static
    string
    CheckMathLength(
    string
    inputData,
    int
    maxLength)

    ///

    <summary>


    ///
    转换成 HTML code

    ///

    </summary>



    public
    static
    string
    Encode(
    string
    str)

    ///

    <summary>


    ///
    解析html成 普通文本

    ///

    </summary>

    public
    static
    string
    Decode(
    string
    str)

    2)辅助类的使用例子代码如下所示

    string
    [] qunList = lineString.Split(
    new
    char
    [] {
    '
    ,
    '
    ,
    '
    ;
    '
    ,
    '

    '
    });
    foreach
    (
    string
    qunNumber
    in
    qunList)
    {
    if
    (!
    string
    .IsNullOrEmpty(qunNumber) && ValidateUtil.IsNumber(qunNumber))
    {
    #region
    对每个号码进行查询
    if
    (!QunDict.ContainsKey(qunNumber))
    {
    this
    .lstItems.Invoke(
    new
    MethodInvoker(
    delegate
    ()
    {
    this
    .lstItems.Items.Add(qunNumber);
    this
    .lstItems.Refresh();
    }));

    QunDict.Add(qunNumber, qunNumber);
    }
    else
    {
    skipCount++;
    }
    #endregion
    }

    }

    3)辅助类使用例子代码2如下所示

    string
    src = CRegex.GetImgSrc(img);
    bool
    isurl = ValidateUtil.IsValidURL(src);
    if
    (isurl)
    {
    continue
    ;

    }

    CHM帮助文档持续更新中,统一下载地址是:
    http://www.iqidi.com/download/commonshelp.rar

    最新公用类库DLL+XML注释文件下载地址是:
    https://files.cnblogs.com/wuhuacong/WHC.OrderWater.Commons.rar


    前面几篇WCF框架的文章,一直是介绍我的WCF框架的形成中的知识,期间虽然我在工作项目中已经成功运用各种WCF的概念及特性,而且是多个部门之间的数据管理系统,基本上WCF框架的雏形已经形成了,不过我一直想把我成熟的Winform开发框架,提炼整合到WCF框架上,这样在成熟的Winform框架基础上应用的WCF技术,才是我整个WCF开发框架的终极形式,虽然项目时间很紧,但业余空闲时间我一直未曾停步,前阵子通宵达旦完成,并经过多番测试,今天有幸和大家分享一下这个WCF框架的真面目及其中的一些经验总结。

    整个终极的WCF框架和Winform一样,整合了权限控制管理、字典管理模块、公用类库、通用程序自动更新等模块,具备良好的界面布局和分布式服务应用的特点,支持数据分页、数据导入、Excel导出、支持多界面样式、支持闪屏、热键控制、多数据库支持,并且和代码生成工具Database2Sharp紧密结合等等特点,不一一尽数。

    前面几篇介绍了WCF相关的开发知识,如果有兴趣可以浏览下:

    WCF开发框架形成之旅--WCF应用常见问题处理

    WCF开发框架形成之旅--如何实现X509证书加密

    WCF开发框架形成之旅--您的数据是否需要加密

    基于我的Winform开发框架扩展而成的WCF开发框架

    基于Winform框架改造而成的WCF框架分层结构如下所示,首先我们在界面UI层和业务逻辑BLL层插入一层WCF服务层,界面层UI不再业务层BLL打交道,而是代之以WCF服务层的客户端代理类打交道,而WCF服务层则是BLL层更进一步的包装,设计图如下所示。

    整个WCF框架的项目工程如下所示,其中展开的是服务层,把所有项目中涉及到的业务类,公布为WCF服务层,如果系统设计数据比较敏感,可以采用证书加密传输,或者通过其他加密方式,具体可以参考我的随笔《
    WCF开发框架形成之旅--如何实现X509证书加密

    上图把数据合约类(或者实体类)放到一个独立的层,这个是无奈之举,因为我的业务类之间有一些公用的实体类信息需要传输,如果把他整合到服务层,那么就会发生命名冲突的问题,这样把数据合约类(或者实体类)独立成工程项目作为引用,就能够解决该问题。

    本WCF框架中的WHC.WareHouseMis层是业务逻辑层,包含业务逻辑、数据访问层在内的整个模块,其中支持SQLServer数据库、Access数据库两种数据库访问,由于构造通过工厂方式,因此通过配置参数即可实现切换,当然扩展下即可实现更多的数据库接入。

    另外本WCF框架提供两种常见的界面框架,一种是传统的界面框架(采用Weifenluo布局空间),一种采用DevExpress界面组件形成,均具有一定的代表性,WCF框架的界面层,虽然其获取数据的方式不同,但和Winform框架具备相同的功能,如数据分页,数据导入、数据导出、权限控制、字典管理等等。

    下面的图示界面层工程项目展开的截图,我们可以看到,在Winform框架中独立的通用权限管理模块、通用字典管理模块,在这里做了一个整合,不再是独立应用的程序集模块,所谓合久必分,分久必合,就是这样的道理。其中红色部分就是字典和权限管理的控制界面模块,这里把它作为界面的一部分,方便服务层的统一部署,统一使用或者统一修改配置等。 另外绿色部分是界面层的基类,这个和Winform框架是一样的,都是为了达到统一、合理封装的目的。

    我们来看看两种不同的界面效果,如下所示:

    1)传统的界面布局效果如下所示。

    2)基于漂亮的界面控件DevExpress的界面效果如下所示


    3)由于WCF框架整合了字典模块和权限模块的界面,因此同时更新了界面效果,其中DevExpress界面效果的字典模块如下所示

    4)其中DevExpess界面效果的权限控制模块如下所示

    另外包含的WCF框架模块自动更新模块,由于采用了图片的背景界面效果。Winform开发框架和WCF开发框架的效果一样,而且都是采用独立的自动更新模块,通过配置更新地址和配置文件即可实现,不再赘述。

    本文主要介绍WCF开发框架的总体内容,不设计代码,这可能给一切代码至上的朋友有些失望,不过却可以作为给大家进行分布式部署应用的一个思路及参考,如果您有好的建议或者问题,希望大家一起沟通,共同进步。

    一般在业务系统里面,除了存储个人的基本信息外,可能也都需要存储个人的一些图片信息,通常如肖像、名片、身份证等重要图片信息,而这些信息偏小为了方便管理,一般也是和个人基本信息一起放在数据库里面的。

    本人在开发形成自己的Winform开发框架及WCF开发框架过程中,对这些进行了优化整理,现公布出来和大家一起讨论学习,希望给大家提供一个参考外,自己有进一步的提升。本文主要以WCF开发框架下的个人图片信息上传保存作为主题,介绍其中涉及到的一些知识点和操作,以及规避其中一些常见的问题。

    1)首先,我们需要在数据库里面设置几个Image对象字段(我这里采用的是SqlServer数据库)。



    2)我们需要先做好数据库存储底层的操作函数,把图片信息存储在不同的字段里面,由于这个操作类似,因此设置一个枚举来选择不同的字段存储,如下所示。

    ///

    <summary>


    ///
    根据图片枚举类型获取对应的字段名称

    ///

    </summary>


    ///

    <param name="imageType">
    图片枚举类型
    </param>


    ///

    <returns></returns>


    private
    string
    GetFieldNameByImageType(UserImageType imageType)
    {
    string
    fieldName =
    "
    Portrait
    "
    ;
    switch
    (imageType)
    {
    case
    UserImageType.个人肖像:
    fieldName =
    "
    Portrait
    "
    ;
    break
    ;
    case
    UserImageType.身份证照片1:
    fieldName =
    "
    IDPhoto1
    "
    ;
    break
    ;
    case
    UserImageType.身份证照片2:
    fieldName =
    "
    IDPhoto2
    "
    ;
    break
    ;
    case
    UserImageType.名片1:
    fieldName =
    "
    BusinessCard1
    "
    ;
    break
    ;
    case
    UserImageType.名片2:
    fieldName =
    "
    BusinessCard2
    "
    ;
    break
    ;
    }
    return
    fieldName;
    }


    ///

    <summary>


    ///
    更新个人相关图片数据

    ///

    </summary>


    ///

    <param name="imagetype">
    图片类型
    </param>


    ///

    <param name="userId">
    用户ID
    </param>


    ///

    <param name="imageBytes">
    图片字节数组
    </param>


    ///

    <returns></returns>


    public
    bool
    UpdatePersonImageBytes(UserImageType imagetype,
    string
    userId,
    byte
    [] imageBytes)
    {
    string
    fieldName = GetFieldNameByImageType(imagetype);

    string
    sql =
    string
    .Format(
    "
    update Users set {0}=@image where Id = '{1}'
    "
    , fieldName, userId);
    Database db = DatabaseFactory.CreateDatabase();
    DbCommand dbCommand = db.GetSqlStringCommand(sql);
    db.AddInParameter(dbCommand,
    "
    image
    "
    , DbType.Binary, imageBytes);
    return
    db.ExecuteNonQuery(dbCommand) >
    0
    ;

    }

    3)以上是保存图片的操作,还需要做一个通用类型的图片下载操作,把用户图片信息保存在byte数组中,方便在客户端把字节转换为具体的文件字节。

    ///

    <summary>


    ///
    根据个人图片枚举类型获取图片数据

    ///

    </summary>


    ///

    <param name="imagetype">
    图片枚举类型
    </param>


    ///

    <returns></returns>


    public
    byte
    [] GetPersonImageBytes(UserImageType imagetype,
    string
    userId)
    {
    string
    fieldName = GetFieldNameByImageType(imagetype);

    string
    sql =
    string
    .Format(
    "
    Select {0} from Users where Id = '{1}'
    "
    , fieldName, userId);
    Database db = DatabaseFactory.CreateDatabase();
    DbCommand dbCommand = db.GetSqlStringCommand(sql);

    byte
    [] imageBytes =
    null
    ;
    using
    (IDataReader reader = db.ExecuteReader(dbCommand))
    {
    if
    (reader.Read())
    {
    imageBytes = (reader.IsDBNull(reader.GetOrdinal(fieldName))) ?
    null
    : (
    byte
    [])reader[
    0
    ];
    }
    }

    return
    imageBytes;
    }

    4)然后设计一个图片上传显示的窗体,其中窗体的图片控件默认显示一个替代的图片,一个美观,二个也方便用户快速设置图片,如下所示。

    其最终效果如下所示,除了可以展示图片外,双击可以预览图片的内容,便于用户放大缩小对图片细看。

    5)其中实现图片上传的WCF客户端代码如下所示。

    private
    void
    btnSavePortrait_Click(
    object
    sender, EventArgs e)
    {
    if
    (picPortrait.Image !=
    null
    )
    {
    new
    UserServiceClient().Using(client =>
    {
    try
    {
    byte
    [] imageBytes = ImageHelper.ImageToBytes(
    this
    .picPortrait.Image);
    bool
    sucess = client.UpdatePersonImageBytes(UserImageType.个人肖像,
    Portal.gc.LoginInfo.Id, imageBytes);
    MessageDxUtil.ShowTips(sucess ?
    "
    个人肖像 图片保存成功!
    "
    :
    "
    保存失败!
    "
    );
    }
    catch
    (Exception ex)
    {
    MessageDxUtil.ShowError(ex.Message);
    LogTextHelper.Error(ex);
    }
    });
    }
    }

    重置图片的代码如下所示。

    private
    void
    ResetDefaultImage(UserImageType imageType)
    {
    System.ComponentModel.ComponentResourceManager resources =
    new
    System.ComponentModel.ComponentResourceManager(
    typeof
    (FrmPersonalInfo));
    switch
    (imageType)
    {
    case
    UserImageType.个人肖像:
    this
    .picPortrait.EditValue = ((
    object
    )(resources.GetObject(
    "
    picPortrait.EditValue
    "
    )));
    break
    ;
    case
    UserImageType.身份证照片1:
    this
    .picIDCard1.EditValue = ((
    object
    )(resources.GetObject(
    "
    picIDCard1.EditValue
    "
    )));
    break
    ;
    case
    UserImageType.身份证照片2:
    this
    .picIDCard2.EditValue = ((
    object
    )(resources.GetObject(
    "
    picIDCard2.EditValue
    "
    )));
    break
    ;
    case
    UserImageType.名片1:
    this
    .picCard1.EditValue = ((
    object
    )(resources.GetObject(
    "
    picCard1.EditValue
    "
    )));
    break
    ;
    case
    UserImageType.名片2:
    this
    .picCard2.EditValue = ((
    object
    )(resources.GetObject(
    "
    picCard2.EditValue
    "
    )));
    break
    ;
    }
    }

    由于采用了枚举类型
    UserImageType
    来区分不同的图片信息,因此多种图片的上传、显示、重置操作,基本上都相同的,较好地实现了代码的重用。另外值得注意的是,WCF默认不支持大一点的图片上传,一般需要设置配置文件来实现图片数据的上传(一般图片还是有点大的),所以需要设置服务端和客户端的配置文件,如下所示。

    服务端的Web.Config配置文件如下所示

    客户端配置如下所示。

    在开发一个个人项目的时候,有客户反映默认GridView多选操作不是很方便和理想,想在列表的左边增加一列可以勾选,并且最好支持列表头部全选的操作,否则数据多的时候一个个勾选要到天荒地老。

    基于以上需求,找了不少例子进行比较,并对代码进行测试改进,终于完成了以上的功能了, 并且由于我本身做了多套界面的处理,因此,基于传统的DataGridView全选操作不能少,而且基于DevExpress控件的GridView全选操作也应该支持,呵呵。

    无图无真相,下面先上图介绍两种不同的效果,然后在详细介绍代码的实现。




    1)DevExpress控件的GridView的实现多选操作

    先讲DevExpress控件的GridView的实现,要实现的功能基本上是处理单击全选操作、重新绘制表头等操作,首先在加载第一步实现相关的事件和操作,如下所示。

    this
    .gridView1.Click +=
    new
    System.EventHandler(
    this
    .gridView1_Click);
    this
    .gridView1.CustomDrawColumnHeader +=
    new
    DevExpress.XtraGrid.Views.Grid.ColumnHeaderCustomDrawEventHandler(
    this
    .gridView1_CustomDrawColumnHeader);
    this
    .gridView1.DataSourceChanged +=
    new
    EventHandler(gridView1_DataSourceChanged);

    然后就是实现里面的事件操作了,对应的代码如下所示。

    private
    void
    gridView1_Click(
    object
    sender, EventArgs e)
    {
    if
    (DevControlHelper.ClickGridCheckBox(
    this
    .gridView1,
    "
    Check
    "
    , m_checkStatus))
    {
    m_checkStatus = !m_checkStatus;
    }
    }

    private
    void
    gridView1_CustomDrawColumnHeader(
    object
    sender, DevExpress.XtraGrid.Views.Grid.ColumnHeaderCustomDrawEventArgs e)
    {
    if
    (e.Column !=
    null
    && e.Column.FieldName ==
    "
    Check
    "
    )
    {
    e.Info.InnerElements.Clear();
    e.Painter.DrawObject(e.Info);
    DevControlHelper.DrawCheckBox(e, m_checkStatus);
    e.Handled =
    true
    ;
    }
    }
    void
    gridView1_DataSourceChanged(
    object
    sender, EventArgs e)
    {
    GridColumn column =
    this
    .gridView1.Columns.ColumnByFieldName(
    "
    Check
    "
    );
    if
    (column !=
    null
    )
    {
    column.Width =
    80
    ;
    column.OptionsColumn.ShowCaption =
    false
    ;
    column.ColumnEdit =
    new
    RepositoryItemCheckEdit();
    }
    }

    其中单击和绘制表头的操作,交给另外一个类
    DevControlHelper
    来独立进行处理,数据源变化
    gridView1_DataSourceChanged
    实现的操作是寻找对应的全选列,并设置列宽、隐藏表头标题,并设置为复选框样式。

    DevControlHelper
    类的实现代码如下所示:

    public
    static
    void
    DrawCheckBox(DevExpress.XtraGrid.Views.Grid.ColumnHeaderCustomDrawEventArgs e,
    bool
    chk)
    {
    RepositoryItemCheckEdit repositoryCheck = e.Column.ColumnEdit
    as
    RepositoryItemCheckEdit;
    if
    (repositoryCheck !=
    null
    )
    {
    Graphics g = e.Graphics;
    Rectangle r = e.Bounds;

    DevExpress.XtraEditors.ViewInfo.CheckEditViewInfo info;
    DevExpress.XtraEditors.Drawing.CheckEditPainter painter;
    DevExpress.XtraEditors.Drawing.ControlGraphicsInfoArgs args;
    info = repositoryCheck.CreateViewInfo()
    as
    DevExpress.XtraEditors.ViewInfo.CheckEditViewInfo;

    painter = repositoryCheck.CreatePainter()
    as
    DevExpress.XtraEditors.Drawing.CheckEditPainter;
    info.EditValue = chk;
    info.Bounds = r;
    info.CalcViewInfo(g);
    args =
    new
    DevExpress.XtraEditors.Drawing.ControlGraphicsInfoArgs(info,
    new
    DevExpress.Utils.Drawing.GraphicsCache(g), r);
    painter.Draw(args);
    args.Cache.Dispose();
    }
    }

    public
    static
    bool
    ClickGridCheckBox(DevExpress.XtraGrid.Views.Grid.GridView gridView,
    string
    fieldName,
    bool
    currentStatus)
    {
    bool
    result =
    false
    ;
    if
    (gridView !=
    null
    )
    {
    gridView.ClearSorting();
    //
    禁止排序


    gridView.PostEditor();
    DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo info;
    Point pt = gridView.GridControl.PointToClient(Control.MousePosition);
    info = gridView.CalcHitInfo(pt);
    if
    (info.InColumn && info.Column !=
    null
    && info.Column.FieldName == fieldName)
    {
    for
    (
    int
    i =
    0
    ; i < gridView.RowCount; i++)
    {
    gridView.SetRowCellValue(i, fieldName, !currentStatus);
    }
    return
    true
    ;
    }
    }
    return
    result;
    }

    2)传统DataGridView实现全选操作

    首先在第一列增加一个CheckBox控件,然后通过相关的事件,调整其位置,并相应对应的单击全选操作,初始化代码如下所示。

    CheckBox HeaderCheckBox =
    null
    ;
    public
    FrmNormalGridViewSelect()
    {
    InitializeComponent();

    if
    (!
    this
    .DesignMode)
    {
    HeaderCheckBox =
    new
    CheckBox();
    HeaderCheckBox.Size =
    new
    Size(
    15
    ,
    15
    );
    this
    .dgvSelectAll.Controls.Add(HeaderCheckBox);

    HeaderCheckBox.KeyUp +=
    new
    KeyEventHandler(HeaderCheckBox_KeyUp);
    HeaderCheckBox.MouseClick +=
    new
    MouseEventHandler(HeaderCheckBox_MouseClick);
    dgvSelectAll.CurrentCellDirtyStateChanged +=
    new
    EventHandler(dgvSelectAll_CurrentCellDirtyStateChanged);
    dgvSelectAll.CellPainting +=
    new
    DataGridViewCellPaintingEventHandler(dgvSelectAll_CellPainting);
    }
    }

    事件实现了CheckBox重绘调整,并处理单击事件,如下所示。

    private
    void
    HeaderCheckBox_MouseClick(
    object
    sender, MouseEventArgs e)
    {
    HeaderCheckBoxClick((CheckBox)sender);
    }

    private
    void
    dgvSelectAll_CellPainting(
    object
    sender, DataGridViewCellPaintingEventArgs e)
    {
    if
    (e.RowIndex == -
    1
    && e.ColumnIndex ==
    0
    )
    ResetHeaderCheckBoxLocation(e.ColumnIndex, e.RowIndex);
    }

    private
    void
    ResetHeaderCheckBoxLocation(
    int
    ColumnIndex,
    int
    RowIndex)
    {
    Rectangle oRectangle =
    this
    .dgvSelectAll.GetCellDisplayRectangle(ColumnIndex, RowIndex,
    true
    );
    Point oPoint =
    new
    Point();
    oPoint.X = oRectangle.Location.X + (oRectangle.Width - HeaderCheckBox.Width) /
    2
    +
    1
    ;
    oPoint.Y = oRectangle.Location.Y + (oRectangle.Height - HeaderCheckBox.Height) /
    2
    +
    1
    ;
    HeaderCheckBox.Location = oPoint;
    }

    private
    void
    HeaderCheckBoxClick(CheckBox HCheckBox)
    {
    foreach
    (DataGridViewRow Row
    in
    dgvSelectAll.Rows)
    {
    ((DataGridViewCheckBoxCell)Row.Cells[
    "
    chkBxSelect
    "
    ]).Value = HCheckBox.Checked;
    }
    dgvSelectAll.RefreshEdit();
    }

    非常感谢你阅读及支持,如果有好的建议及问题,可以联系我,共同讨论促进。

    前面介绍了一篇《
    Winform传统DataGridView和DevExpress控件的GridControl两者表头全选功能的实现(源码提供)
    》,介绍了传统DataGridView和DevExpress控件的GridView的表头全选功能实现,现把功能应用在我的Winform分页控件上,只需要很少的代码即可实现,代码更加简洁优雅。

    Winform分页控件,在很多场合都需要用到,由于整合较多的功能操作,使用起来效果更好,界面统一性也比较一致。其中的勾选操作,在有些场合下,也是比较有用的,因此提供该功能的整合。

    我们先来看看基于我的分页控件实现的表头全选功能,界面效果如何。

    1)传统界面的效果

    2)DotNetBar界面效果

    3)DevExpress界面效果

    以上就是.NET开发中非常广泛应用的三组界面效果,分页控件分别提供了3种控件实现,几乎所有的属性及操作方法均一致,本实例中实现表头操作也是完全一致的,我们以其中传统界面效果的分页控件来进行介绍。

    首先指定分页控件的全选列的字段名称(
    如果是
    DataTable
    类型数据源,那么就是
    数据列名
    ,如果是
    实体类
    ,那么就是实体类的
    属性名称

    另外在绑定数据的时候,添加一列对应上面的字段的IsCheck即可。

    以上代码指定,就出现本文开始的效果了,可以实现表头的全选操作,是不是还算简洁优雅的呢,其他效果的DotNetBar和DevExpresss界面效果的,使用方法完全一致。