2023年2月

权限管理系统的重要特性总结:

1)
高度集成
的权限系统、独立模块,能快速整合使用。
2) 符合权限的国际通用标准,基于
RBAC
(基于角色的访问控制)的角色权限控制。
3)
多数据库架构支持
,内置支持SqlServer、Oracle、MySql、SQLite、Access数据库。
4) 用户管理基于
分级管理理念
,集团分子公司、事业单位处室/局级可独立管理人员/角色等数据。
5) 用户接入的各种应用系统,均可实现用户
登陆日志、操作日志
的记录。
6) 管理员可以控制登陆用户的
黑白名单列表
,实现严格的登陆控制管理。
7) 权限系统也是基于
《Winform开发框架》的成熟架构
,稳定高效、更易使用和理解。
8) 权限管理系统
文档齐全、完善
的应用支持和集成项目经验,开发项目
更有保证

权限管理系统说明:
《Winform开发框架》、《WCF开发框架》和《混合式开发框架》三个框架是我们经过多年的项目积累,吸收众多框架产品客户的宝贵意见,反复提炼优化而成的。在这几款开发框架中,我都应用到了一个《通用的权限管理系统》(简称权限管理系统),这个作为一个独立的系统模块,但又可以整合到所有的框架产品和项目中,实现快速的权限管理和控制。
权限的分配和管理,基本上是每个业务系统需要考虑的东西,而这些常用的东西,在整个开发框架中,把它作为一个独立的模块,既方便维护管理,也留有接口很容易进行集成,这样能够在项目中反复进行使用。
权限管理系统主要的功能包括有:用户管理、组织机构管理、功能管理、角色管理和权限分配管理、菜单管理、系统类型管理、登录日志管理、操作日志管理、系统黑白名单管理等功能模块。对于每新增一个系统,我们只需要在权限管理系统中增加一个系统类型定义,以及相关的功能、菜单数据即可,非常方便管理。

一、用户管理

1、用户登陆

在权限管理系统登录界面输入账号和密码后(默认账号
admin
,密码为空),即可进入权限管理系统的主界面,权限管理系统主要的功能包括有:用户管理、组织机构管理、功能管理、角色管理和权限分配管理、菜单管理、系统类型管理、登录日志管理、操作日志管理、系统黑白名单管理等功能模块。

2、用户分级管理

权限管理系统的用户管理是基于分级管理理念,集团分子公司、事业单位处室/局级可独立管理人员/角色等信息。
系统分了两级管理员用户:超级管理员和公司管理员。超级管理员可以管理整个集团或者整个系统的人员和相关信息(包括组织机构、角色、登陆日志、操作日志等信息的分级);公司管理员可以管理分子公司、事业单位处室/局级这样的组织机构的人员和相关信息。
分级管理组织机构、角色、用户等相关数据,能够减少管理员的相关工作,提高工作效率,并能增强权限管理系统对权限的控制和资源分配等管理,提高用户的认同感。

3、新建/编辑用户

在系统用户信息模块里面,可以在组织机构树右键“新建”或者“新建”按钮上,触发弹出新建用户的操作,如下界面所示。
在新建用户的界面上,输入必须的用户名、真实姓名、所属公司、默认机构/部门等信息,其他信息可选输入。用户的所属机构、所属角色、可操作功能,在后面的介绍操作中进行分配管理,新建用户不需要管理这些信息。

在用户基本信息界面里面,用户“所属公司”,是一个下拉的树形列表,里面按照组织机构的分级进行展示公司信息,如下所示。

“默认机构/部门”是根据用户选择的“所属公司”进行过滤的,根据用户选择所属公司,列出该公司下的所有组织机构树形列表供选择,如下所示。

编辑用户界面和新建用户界面显示,在界面上显示已经录入的用户信息和用户的关系信息,包括所属机构、所属角色、可操作功能等。

4、用户导入

为了快速录入系统用户信息,权限管理系统提供Excel的数据批量导入操作,如下所示。

在用户管理列表的“导入”操作按钮中触发,弹出一个通用的Excel数据导入界面,里面指定了导入数据的“Excel模板”,用户根据模板字段列输入相关的信息,然后通过“浏览”按钮触发数据的显示,如果确认无误,即可进行“保存数据”的操作。

5、用户导出

权限系统的用户数据,也可以通过“导出”按钮进行用户数据的导出操作,如下所示。

6、用户查询

用户的查询,可以通过按组织机构查看、按角色查看和根据查询条件查询,前两者通过树形列表,方便用户快速查询用户,由于用户是分级管理,因此不同的公司管理员,看到的组织机构和角色数据有所不同,他们可以管理自己管辖内的用户数据。

1) 按组织机构查询

2) 按角色查询

3) 根据查询条件查询

二、组织机构管理

1、组织机构列表

权限管理系统中的组织机构列表,是一个层级的树形列表,基本的节点可以分为集团、公司、部门和工作组这几个级别,在组织机构树中选择机构后,界面中间及右边区域会显示详细的组织机构信息和相关数据。

2、新建/编辑组织机构

新建组织机构,可以在左边的树形列表上的右键菜单上操作,也可以在顶部的“添加”按钮上进行操作。新建组织机构信息,处在同一个界面里面,用户输入相关数据保存即可。

3、包含用户管理

组织机构可以通过“包含用户”的方式,把系统其他部门的用户纳入到该部门管理范畴中,这样,如果分配给该部门的权限,自动会授权给这些包含进来的用户,实现用户权限的累加管理。

单击“包含用户”界面的“添加”按钮,弹出一个“选择人员”的对话框,对话框界面里的用户数据是根据部门和角色进行分类的,用户可以在左边的树列表中快速查看指定范畴内的用户数据,右边的列表中有勾选项目,勾选后单击“添加选择”即可添加到底部的用户选择区域,也可以在选择区域里面删除指定用户选择,界面如下所示。

三、角色管理

角色是权限系统管理里面最为重要的部分,整个系统符合权限的国际通用标准,基于RBAC(基于角色的访问控制)的角色权限控制,这样和权限相关的信息,都是通过角色进行关联,因此角色还需要管理和用户之间的关系、和组织机构之间的关系、和可操作功能之间的关系等等。

1、角色基础信息管理

2、包含机构管理

3、包含用户管理

和组织机构包含用户功能一样,弹出选择用户对话框,选择对应的用户列表信息。

4、可操作功能

四、系统类型定义

系统类型定义,是用作区分一个业务应用系统的标识,权限系统支持多个业务应用系统的继承,虽然默认是一个,但是可以根据需要进行扩充,使得权限管理系统管理的范畴更大,实现所有业务系统共享一个权限管理系统的布局。

1、系统类型列表

2、新建/编辑系统类型

五、功能管理

功能管理,是业务应用系统的权限控制最小单元,可以用作控制系统的按钮、菜单等界面元素,也可以用作控制显示或隐藏的某些字段的操作。

1、功能列表

2、新建/编辑功能


为了方便一次性添加多个功能单元,可以通过“批量添加”操作进行功能的批量添加,批量添加界面如下所示。

3、可操作角色

六、菜单管理

1、菜单列表

一般Winform程序中,菜单都是直接写在主程序中的,这样对于经常性修改和维护菜单的相关信息,可能有所不便,而且对于插件化的系统应用,新增菜单是常见的事情,这样就需要对菜单进行动态配置管理了,通过后台菜单的配置和权限的指定,能够实现菜单的动态加载和权限验证。
因此菜单也是权限分配的一部分,为了有效管理菜单资源,我们把菜单放到权限管理系统中进行管理控制,可根据用户权限进行动态控制显示。

设定好菜单的图标和Winform窗体类型,就能在Winform框架中动态构建菜单信息了。菜单的图表放置在系统的相对目录下即可。

2、新建/编辑菜单

新建或者编辑的菜单界面如下所示,除了需要输入“显示名称”外,还需要选择“上级菜单”,如果菜单需要进行权限控制,那么在“功能控件ID”输入需要的控制键即可,如下红色框选部分。

菜单的“上级菜单”是一个下拉的树状列表,方便显示层次关系并进行选择。

七、系统黑白名单

在一般的权限系统里面,可能经常会看到系统的黑名单或者白名单的拦截功能。在一般 权限系统里面,常见的黑名单就是禁止用户在某些IP上登录系统,白名单就是允许用户只在某些IP上登录系统。本随笔主要介绍在我的权限系统里面,如何实现这个黑白名单的功能,以及介绍在其中应用到的IP对比操作,IP段判断等操作代码。

1、黑白名单列表

要完成黑名单的拦截和白名单的放行,我们需要进行名单的配置操作,我们把相关的配置放到列表里面进行展示,可以添加多个黑名单或者白名单,如下界面所示。

2、新建/编辑黑白名单

可以在黑白名单列表上单击“新建”按钮进行添加一条记录,或者在已有记录上双击黑白名单可以进行编辑,界面如下所示。

通过“添加用户”按钮,在弹出的选择人员界面中,指定黑白名单的人员列表即可。

3、系统登录拦截效果

八、用户登陆日志

1、登陆日志列表

九、用户操作日志

在很多业务系统里面,数据是很敏感的,特别对于一些增加、修改、删除等关键的操作,如果能在框架层面的支持基础上,以最少的代码实现重要表的日志记录,那么是一件非常值得庆贺的事情,也能够为我们客户的数据提供重要的日志跟踪,甚至是数据恢复的参考。
通过权限管理系统的支持和《Winform开发框架》的底层支持,业务系统模块,只需要通过一行代码就能实现业务表的日志记录,这对我们开发新的业务模块,效率可以提高很多,同时也能给客户提供更好的数据支持服务。通过在权限系统模块里面配置参数和显示操作日志记录,能够给业务开发提供基础性的开发框架支持。

1、用户操作日志列表

2、操作日志的参数设置

在操作日志的参数配置列表里面,我们可以添加一些业务表操作日志配置,然后通过在开发时刻,一行代码指定记录日志操作,即可实现操作日志的记录。

3、查看详细操作日志

1) 修改记录的操作日志

2) 增加记录的操作日志

十、系统集成管理

1、项目中集成权限系统登陆

实现代码就是调用该程序集的接口API启动权限系统的登陆界面,如下所示。

2、项目中集成权限控制

1)系统登陆及权限获取

2)项目权限控制

十一、提供基于多种数据库的整合

权限系统和其他框架一样,提供基于多种数据库(SqlServer/Oracle/MySql/SQLite/Access等数据库)的整合支持。虽然我们在实际项目中,一般采用一种数据库进行处理,但是不同的项目,采用的数据库类型可能不同,本Winform开发框架为了方便演示和扩展的需要,内置支持了SqlServer/Oracle/MySql/ SQLite /Access,更多的数据库,也可以通过扩展数据库访问基类的方式进行更多数据库的支持。

整个权限管理系统的数据库访问,能够手动配置数据库类型,对于同一种数据库,也可以把数据存储分开存储,如业务数据存储在一个数据库,权限管理控制存储在另外一个数据库这种方式。

客户关系管理系统

文件大小

37M

下载地址

更多介绍图片:

打开系统图片介绍


产品说明如下:
★软件功能
广州爱奇迪客户关系管理系统,是一款专业的客户关系管理软件(CRM管理系统),软件以客户为中心,把科学的管理与信息技术结合起来,实现市场、销售、服务协同工作统一管理。帮助企业规范业务流程、提高客户挖掘能力和客户服务质量、有效管理客户资源、提高销售成功率,达到全面提升企业核心竞争力的目的。
软件界面美观大方,易于使用,具有良好的操作性、美观性和功能稳定性等优良特点。本客户关系管理系统广泛适用于各个行业进行客户管理,销售管理,是您企业进行客户档案管理,客户资料管理,客户服务管理,客户信息管理的强大工具。
CRM系统的宗旨是:为了满足每个客户的特殊需求,同每个客户建立联系,通过同客户的联系来了解客户的不同需求,并在此基础上进行"一对一"个性化服务。“以客户为中心”,提高客户满意度,培养、维持客户忠诚度,在今天这个电子商务时代显得日益重要。客户关系管理正是改善企业与客户之间关系的新型管理机制,越来越多的企业运用CRM来增加收入、优化赢利性、提高客户满意度。
我们的CRM系统包括客户往来、客户管理、客户服务、产品及销售、通信管理、人员管理、报表数据、系统管理等主要内容。
1)客户往来:
对客户信息及相关资料进行全面的管理。包括客户跟进信息、联系人信息、客户文档、合同文档、维护记录、售后服务、客户投诉、客户活动、销售机会、产品报价、销售记录、客户拜访、客户来电、发票记录等客户相关信息的管理。

2)客户管理:
包括客户信息管理、客户联系人管理、竞争对手管理、供应商管理、客户合同管理、客户文档等信息管理。支持客户资料的批量导入、支持多联系人管理、支持客户名称的排重、支持多条件搜索。支持客户资料、联系人资料的修改、删除权限的控制。

3)客户服务:
包括来电记录、客户投诉、客户维护、客户售后、客户活动、客户拜访、客户跟进的管理。

4)商品及销售:
包括商品管理、供应商管理、竞争对手管理、竞争对手产品管理、报价单管理、订单管理、发票管理。支持报价单直接生成订单的操作,支持报价单和订单的打印管理。

5)通信管理:
包括系统公告信息管理、手机短信管理、电子邮件管理、个人通讯录、公共通讯录。系统公告信息能在多用户进行系统内相互交流,支持手机短信发送管理、电子邮件发送管理,对个人通讯录和公共通讯录支持分组管理,更好维护联系人信息。

6)人员管理:
管理人员的相关信息,包括基本信息、学习及职称信息、履历情况、家庭及个人信息、个人文件资料等信息。

7)报表数据:
提供对客户各种属性的报表分析,以及订单数据的报表分析功能,使管理者能够更好掌握系统的数据发展趋势,指定正确的营销策略。

8)系统管理:
包括对系统数据字典管理、用户创建及权限分配的权限管理、密码修改等功能。对系统所有模块用到的数据字典进行统一维护,使得数据更加统一有效;支持新用户的创建和用户权限控制等基础权限管理功能。

★系统需求

广州爱奇迪客户关系管理系统,使用C#语言开发 适运行在 Microsoft WindowsNT/2000/XP/2003 等平台,但必须安装有.Net4.0平台、SqlServer数据库以及Microsoft Visio.该软件利用了微软.NET Framework4.0 优秀的框架,因此在安装软件前,您需要花费一点时间来安装下面的组件:
(1).NET Framework 4.0 官方下载地址:
http://www.microsoft.com/zh-cn/download/details.aspx?id=17718
(2)最后下载 广州爱奇迪客户关系管理系统,进行安装即完成整个软件的安装。

★软件注册

广州爱奇迪客户关系管理系统 是一款共享软件,您可以自由发布和传播软件,未注册版本会在使用30天后过期。在带给您方便的同时, 希望您能考虑注册这款软件,注册软件的时候请提供软件的机器码。  注册用户可以获得我们的技术支持以及其他服务,并且可以免费升级到今后所有的新版本,请务必保留第一次注册时使用机器码及电子邮件,免费升级下一版本时,我们需要此信息。更重要的是:您的注册还将鼓励我们不断改进和完善这个软件,给大家提供更好的服务。
如果您在电脑报刊发表了介绍这个软件的文章,将刊物名称和期号告诉我,我们将免费为您提供注册码。或者您有好的建议/意见/程序错误,请写信告诉我们,如果我们采纳,也将免费为您提供注册码。     该软件版权归“广州爱奇迪软件科技有限公司”所有,作者保留该软件所有权利,未注册用户不得将该软件用于商业用途。

我们知道,Web开发上有很多HTML的编辑控件,如FCKEditor、CKEditor、kindeditor等等,很多都做的很好,而虽然Winform里面有WebBrowser控件,但是默认这个控件是不允许编辑内容的,可以显示网页而已。Winform开发里面,有些使用RichTextBox控件来编辑HTML,也有一些结合WebBrowser控件来实现内容的编辑,其中我觉得做的最好的应该是Zeta HTML Edit Control(
http://www.codeproject.com/Articles/43954/ZetaHtmlEditControl
),这个控件是在CodeProject上开源公布的,同时也在GitHub上有一个项目的维护(
https://github.com/UweKeim/ZetaHtmlEditControl
)。本文主要介绍这个控件的使用,以及对其进行一些资源的中文汉化工作,使得我们在实际使用中更方便,并附上修改过的控件源码,希望大家有所收益。

1、控件的界面效果

控件默认很多工具栏和菜单,都是英文的,它的默认效果如下所示。

Zeta HTML Edit Control

对其所有英文的菜单、工具栏、对话框、提示内容等资源进行中文化后,并在工具栏中增加插入图片、打印功能后,界面如下所示。

2、控件的使用

控件的一些功能是可以通过配置屏蔽或者显示的,默认它的初始化代码如下所示。

htmlEditUserControl1.Configure(new HtmlEditControlConfiguration{AllowFontChange = true, AllowEmbeddedImages=true, AllowPrint = true});
htmlEditUserControl1.IsToolbarVisible
= true;

AllowFontChange 如果设置为True,可以在工具栏出现字体大小的设置内容。

AllowEmbeddedImages,可以把从剪切板里面的图片转换为Base64的字符串的字符串内容,放到HTML控件里面。

AllowPrint是可以打印的功能。

控件可以通过几种方式进行HTML的赋值的,如下所示。

const string s = @"<P><b>Some tests</b></P><p>Random content. <font color=green>Please edit</font>.</p><p>Use right-click for options.</p>";
htmlEditControl1.DocumentText
= s;

或者

const string s = @"<P>Click the buttons below to set different texts. German Umlaute: ???????</p>";
htmlEditControl1.SetDocumentText(s,
@"C:\", true);

控件的工具栏可以根据需要隐藏或者显示

htmlEditUserControl1.IsToolbarVisible = ToolbarVisibleCheckBox.Checked;

3、控件的存在问题

这个控件在使用过程中,发现有一些小问题。

1)必须对控件的DocumentText赋值,才能获取HTML的内容,否则在控件中输入内容后,通过代码获取到的DocumentText是空的。

htmlEditUserControl1.HtmlEditControl.DocumentText = "伍华聪的测试内容";

2)控件的HtmlEditControl对象在设计的时刻不出现在只能提示里面,但是使用没问题,很奇怪。

4、对控件进行汉化后,整个控件的源码

对控件全面进行了中文化修改,方便我们日常的使用。

控件下载地址如下:https://files.cnblogs.com/wuhuacong/ZetaHtmlEditControl.rar

缓存在很多情况下需要用到,
合理利用缓存可以
一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存的使用场景和使用方法。
缓存是一个中大型系统所必须考虑的问题。为了避免每次请求都去访问后台的资源(例如数据库),我们一般会考虑将一些更新不是很频繁的,可以重用的数据,通过一定的方式临时地保存起来,后续的请求根据情况可以直接访问这些保存起来的数据。这种机制就是所谓的缓存机制。

.NET 4.0的缓存功能主要由三部分组成:System.Runtime.Caching,System.Web.Caching.Cache和Output Cache。

System.Runtime.Caching这是在.NET 4.0中新增的缓存框架,主要是使用MemoryCache对象,该对象存在于程序集System.Runtime.Caching.dll。

System.Web.Caching.Cache这个则是在.NET2.0开始就一直存在的缓存对象,一般主要用在Web中,当然也可以用于Winform里面,不过要引用System.Web.dll。

Output Cache则是Asp.NET里面使用的,在ASP.NET 4.0之前的版本都是直接使用System.Web.Caching.Cache来缓存HTML片段。在ASP.NET 4.0中对它进行了重新设计,提供了一个OutputCacheProvider供开发人员进行扩展,但是它默认情况下,仍然使用System.Web.Caching.Cache来做做缓存。

1、自定义Hastable的缓存处理。

除了上面三种的缓存机制,一般我们还可以在静态对象里面通过HashTable或者Dictionary的方式进行自定义的缓存存储和使用。

例如我在我自己所开发的程序里面,都使用了工厂类来创建业务对象,由于创建业务对象以及数据访问层对象,是一个在界面或者中间层反复调用的操作,因此需要把经常调用的对象把它存储起来,下载调用的时候,直接从内存中取出来即可。如下面的BLLFactory类,就是一个基于泛型对象的业务类的创建操作,使用了基于Hashtable的静态对象进行缓存处理。

    /// <summary>
    ///对业务类进行构造的工厂类/// </summary>
    /// <typeparam name="T">业务对象类型</typeparam>
    public class BLLFactory<T> where T : class{private static Hashtable objCache = newHashtable();private static object syncRoot = newObject();/// <summary>
        ///创建或者从缓存中获取对应业务类的实例/// </summary>
        public staticT Instance
{
get{string CacheKey = typeof(T).FullName;
T bll
= (T)objCache[CacheKey];  //从缓存读取 if (bll == null)
{
lock(syncRoot)
{
if (bll == null)
{
bll
= Reflect<T>.Create(typeof(T).FullName, typeof(T).Assembly.GetName().Name); //反射创建,并缓存 objCache.Add(typeof(T).FullName, bll);
}
}
}
returnbll;
}
}
}

2、使用.NET4.0的MemoryCache对象实现缓存

MemoryCache的使用网上介绍的不多,不过这个是.NET4.0新引入的缓存对象,估计主要是替换原来企业库的缓存模块,使得.NET的缓存可以无处不在,而不用基于特定的Windows版本上使用。

首先我们使用来创建一个基于MemoryCache的辅助类MemoryCacheHelper,方便调用进行缓存处理。

    /// <summary>
    ///基于MemoryCache的缓存辅助类/// </summary>
    public static classMemoryCacheHelper
{
private static readonly Object _locker = new object();public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
{
if(String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");if(cachePopulate == null) throw new ArgumentNullException("cachePopulate");if(slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");if(MemoryCache.Default[key] == null)
{
lock(_locker)
{
if(MemoryCache.Default[key] == null)
{
var item = newCacheItem(key, cachePopulate());var policy =CreatePolicy(slidingExpiration, absoluteExpiration);

MemoryCache.Default.Add(item, policy);
}
}
}
return(T)MemoryCache.Default[key];
}
private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime?absoluteExpiration)
{
var policy = newCacheItemPolicy();if(absoluteExpiration.HasValue)
{
policy.AbsoluteExpiration
=absoluteExpiration.Value;
}
else if(slidingExpiration.HasValue)
{
policy.SlidingExpiration
=slidingExpiration.Value;
}

policy.Priority
=CacheItemPriority.Default;returnpolicy;
}
}

这个辅助类只有一个public方法,就是GetCacheItem,使用的时候,需要指定key和获取数据的处理代理,还有缓存的过期时间,是基于TimeSpan的还是基于绝对时间的,选择其一。

上面的辅助类,我们在什么情况下会使用到呢?

假如在一个工作流模块中用到了人员ID,而人员ID需要进行人员名称的转义,人员信息我们一般知道放在权限系统模块里面,那么如果在工作流里面需要频繁对人员ID进行转义,那么就需要方法调用权限系统的接口模块,这样处理就可以使用缓存模块进行优化处理的了。

        void gridView1_CustomColumnDisplayText(objectsender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
if (e.Column.FieldName.Equals("ProcUser") || e.Column.FieldName.Equals("ProcUid") || e.Column.FieldName.Equals("UserId"))
{
if (e.Value != null)
{
e.DisplayText
=SecurityHelper.GetUserFullName(e.Value.ToString());
}
}
}

其中的SecurityHelper.GetUserFullName是我对调用进行基于缓存的二次封装,具体逻辑如下所示。

        /// <summary>
        ///根据用户的ID,获取用户的全名,并放到缓存里面/// </summary>
        /// <param name="userId">用户的ID</param>
        /// <returns></returns>
        public static string GetUserFullName(stringuserId)
{
string key = "Security_UserFullName" +userId;string fullName = MemoryCacheHelper.GetCacheItem<string>(key,delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); },new TimeSpan(0, 30, 0));//30分钟过期 returnfullName;
}

MemoryCacheHelper的方法GetCacheItem里面的Func<T>我使用了一个匿名函数用来获取缓存的值。

delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); }

而调用BLLFactory<User>.Instance.GetFullNameByID则是从数据库里面获取对应的数据了。

这样在第一次或者缓存过期的时候,自动调用业务对象类的方法来获取数据了。

最后,在界面上调用GetUserFullName的方法即可实现基于缓存方式的调用,程序第一次使用的,碰到指定的键没有数据,就去数据库里面获取,以后碰到该键,则直接获取缓存的数据了。

下面图形是程序具体的实现效果。

当然,以上两种方式都还可以通过AOP的注入方式实现代码的简化操作,不过由于对AOP的引入,会涉及到更多的知识点,而且熟悉程序还不够,所以依然采用较为常用的方式来处理缓存的数据。

在很多DevExpress的使用例子里面,我们可以看到,基于GridView实现的不同控件展示的时候,每一列的控件类型都是一样的,如果我要某一列的一行让用户可以从下列列表选择选项,而其他行不可选择,那我们可以实现这种效果吗,应该如何实现?

1、GridView实现的显示效果

例如下面的效果就是我希望达到的,在第一行的流程处理人列允许用户选择,其他行禁止用户选择。

单用户单击第一行的“流程处理人”列的时候,弹出一个列表供用户选择,选择后显示具体的人员的姓名即可。

2、功能实现具体步骤

实现上面所说的功能,最主要就是创建两个In-place(嵌入)的编辑器,一个用于特定行的编辑,一个用于其他行的编辑。如下所示。

从上面可以看到,我添加了一个LookupEdit控件和一个TextEdit的控件,分别用来操作不同的行列内容。

然后就是需要实现gridView的单元格自定义编辑事件,如下所示。

            this.gridView1.CustomRowCellEdit += new DevExpress.XtraGrid.Views.Grid.CustomRowCellEditEventHandler(this.gridView1_CustomRowCellEdit);

然后在事件实现里面,对不同的行,指定不同的编辑器,如下代码所示。

        private void gridView1_CustomRowCellEdit(objectsender, DevExpress.XtraGrid.Views.Grid.CustomRowCellEditEventArgs e)
{
if (e.Column.FieldName == "ProcUser")
{
if (e.RowHandle == 0)
{
e.RepositoryItem
= this.repositoryddlProcUser;
}
else{
e.RepositoryItem
= this.repositorytxtProcUser;
}
}
}

最后,还需要实现这两个内嵌的编辑控件的ParseValue事件,如下所示。

            this.repositorytxtProcUser.ParseEditValue += newDevExpress.XtraEditors.Controls.ConvertEditValueEventHandler(repositorytxtProcUser_ParseEditValue);this.repositoryddlProcUser.ParseEditValue += new DevExpress.XtraEditors.Controls.ConvertEditValueEventHandler(repositoryProcUser_ParseEditValue);
        void repositorytxtProcUser_ParseEditValue(objectsender, DevExpress.XtraEditors.Controls.ConvertEditValueEventArgs e)
{
e.Value
= "人员未定";
}
void repositoryProcUser_ParseEditValue(objectsender, DevExpress.XtraEditors.Controls.ConvertEditValueEventArgs e)
{
if (e.Value isString)
{
int result = 0;if (Int32.TryParse((String)e.Value, outresult))
{
e.Value
=result;
e.Handled
= true;
}
}
}

这样,我们就能实现上面所说的效果,可以在某行列里面显示下拉列表,其他的行列显示文本框,并且文本框不可以编辑的操作了。

通过以上的操作,我们还可以为某行列指定更多不同类型的内嵌编辑控件,从而丰富我们的列表单元格编辑操作。