2023年2月

使用EnterpriseLibary做数据库访问底层是我一贯的做法,除了其能兼容多种数据库,且使用其进行数据库访问,对各种数据库操作均是透明的,基本不需要对特定的数据库进行操作,编写一次操作代码,基本在各种数据库都适用。对于一些特殊的数据库,很多同行已经编写出各种各样的扩展类库,直接适用即可。

言归正传,动态改变EnterpriseLibary数据库访问链接字符串一般在使用Access数据库、Sqlite数据库等文件式的数据库比较常见,因为我们不知道客户会把程序拷贝到哪里进行使用(即使是做了安装包,这样动态改变连接字符串的方式,也是一种很好的处理方式)。

1)第一种方式,使用前动态改变配置节点内容。

这种方式很常见,一般常用在Winform程序上,在使用程序访问数据库前,先根据当前的程序运行位置,修改配置项里面的内容,然后更新配置节点,从而达到可以应用最新配置信息的操作。

我们先来看看一个配置文件例子。

如果要修改更新其中的配置信息,具体代码如下所示。

            string connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}Database1.mdb;User ID=Admin;Jet OLEDB:Database Password=;", System.AppDomain.CurrentDomain.BaseDirectory);
AppConfig config
= newAppConfig();
config.SetConnectionString(
"DataAccess", connectionString);//更新配置文件,以便起效 ConfigurationManager.RefreshSection("dataConfiguration");
ConfigurationManager.RefreshSection(
"connectionStrings");
ConfigurationManager.RefreshSection(
"appSettings");

其中数据库参数设置我封装在了
公用类库
的AppConfig配置类里面了,你也可以使用自己的操作进行修改。

这样更新操作后,数据库更新为正确的路径地址,我们在EnterpriseLibary里面就不用再做任何操作,就能正常访问操作数据库了。

2)第二种方式,在EnterpriseLibrary里面对连接字符串进行动态修改。

有时候,我们会碰到另外一种情况,就是程序虽然是使用Access数据库或者Sqlite数据库,但是需要在Web端部署,有无更方便的修改配置参数方式呢。

除了上面的一种方式,还有一种方式是在EnterpriseLibrary里面修改Database对象的连接字符串。

首先我们在配置文件里面,相对路径使用参数$Start$变量进行标识,使用连接字符串创建数据库的时候,我们替换这个变量,从而达到修改数据库字符串的目的。

然后我们定义一个创建EnterpriseLibrary的Database对象的方法,用来动态修改连接字符串。

        /// <summary>
        ///根据配置数据库配置名称生成Database对象/// </summary>
        /// <returns></returns>
        protected overrideDatabase CreateDatabase()
{
Database db
= null;if (string.IsNullOrEmpty(dbConfigName))
{
db
=DatabaseFactory.CreateDatabase();
}
else{
db
=DatabaseFactory.CreateDatabase(dbConfigName);
}

DbConnectionStringBuilder sb
= db.DbProviderFactory.CreateConnectionStringBuilder();
sb.ConnectionString = GetConnectionString();
GenericDatabase newDb = new GenericDatabase(sb.ToString(), db.DbProviderFactory);
db = newDb;
returndb;
}
public stringGetConnectionString()
{
AppConfig config
= newAppConfig();string connectionString = config.GetConnectionString("DataAccess2");

connectionString
= connectionString.Replace("$Start$", AppDomain.CurrentDomain.BaseDirectory);returnconnectionString;
}

上面红色部分就是动态修改的核心所在,这样我们封装了一个CreateDatabase对象后,所有创建Database对象的操作,均使用这个方法即可。下面是一个Sqlite数据库查找记录的操作,调用例子如下所示。

        /// <summary>
        ///查找记录表中最旧的一条记录/// </summary>
        /// <returns></returns>
        public overrideT FindFirst()
{
string sql = string.Format("Select {0} From {1} Order by {2} ASC LIMIT 1", selectedFields, tableName, GetSafeFileName(sortField));
T entity
= null;

Database db
=CreateDatabase();
DbCommand command
=db.GetSqlStringCommand(sql);using (IDataReader dr =db.ExecuteReader(command))
{
if(dr.Read())
{
entity
=DataReaderToEntity(dr);
}
}
returnentity;
}

这样操作是不是也很方便呢?以上就是我常用的两种动态改变数据库连接字符串的操作,希望对大家在处理同类型问题的时候,有所帮助。

3)第三种方式,使用
|DataDirectory|代替运行目录

之前在很多项目中运用了第二种方式,运行良好,不过发表文章的时候,有博友指出,还可以使用这种
|DataDirectory|的方式,这个是内置的.net目录,可以替代运行时刻的当前目录,经过测试,效果非常不错,因此也作为建议使用的方式。

使用这个
|DataDirectory|关键字有一点值得注意的地方,就是如果开发Asp.net的Web应用,那么把数据库放到App_Data目录下,这是一个特殊的目录;如果是开发Winform(类似我这样的),就是把数据库放到运行程序的根目录即可,不需要在创建App_Data了,因为Winform里,这个不是特殊目录,如果你创建了这样的目录,反而是画蛇添足了。

使用这种方式,那么你构建的数据库连接方式就如下所示。

Access数据库的链接字符串:

connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\ComponentData.mdb;User ID=Admin;Jet OLEDB:Database Password=;"

Sqlite的链接字符串:

connectionString="Data Source=|DataDirectory|\ComponentData.db;Version=3;"

再次感谢提出该思路的朋友!

开发共享软件,传统的是采用注册码验证方式,这种方式是大多数共享软件采用的方式,另外还有一种常见的验证方式,就是通过网络授权认证的方式,这种方式通过在程序中调用服务器的服务进行。一般具有验证用户名可用、注册新用户、用户登录认证、用户修改密码等操作,另外还需要配备一个网络授权入口给管理员对注册的用户进行授权控制。

这个是为了进行网络授权认证搭建的一个简单的管理后台,用户在共享软件客户端通过调用服务器的服务连接,可以注册一个新用户,或者进行登录获取身份信息(试用、已注册、已禁用等状态),还可以通过服务接口来进行密码修改,提高安全性及使用合理性。

网络认证有几个好处,一是可以不受限于传统的机器码限制,可以在多个计算机中登录使用;二是方便软件开发者集中管理用户信息,动态授权或者取消授权用户的身份信息,还可以获取更多用户的信息,以便进行推广沟通。

开发网络授权业务后台的时候,需要创建一个服务接口给软件客户端进行调用,这个服务接口可以通过创建ashx这样的处理程序来进行处理,这种类和ASPX页面处理有些少不同,这个提供更原始的输出,需要什么输出什么。

这个处理页面和传统的aspx页面一样,都接受类似test.aspx?id=1&name=test 这样的参数,它的处理代码如下所示。

    /// <summary>
    ///用户测试账号可用性、注册新用户、登录验证、修改密码等操作业务处理类/// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo
=WsiProfiles.BasicProfile1_1)]public classUserAction : IHttpHandler
{
public voidProcessRequest(HttpContext context)
{
//context.Response.ContentType = "text/plain";//context.Response.Write("Hello World"); context.Request.ContentEncoding =Encoding.Default ;string action = context.Request["action"];string usr = context.Request["usr"];string password = context.Request["pass"];string machineCode = context.Request["code"];

通过获取参数的内容,我们就可以进行不同的业务处理,这里我使用了一个Action的标志,用来区分是做什么操作的。

            string action = context.Request["action"];string usr = context.Request["usr"];string password = context.Request["pass"];string machineCode = context.Request["code"];bool result = false;switch(action)
{
case "r"://检测注册 UserAction.ashx?action=r&usr=&pass=&code= string reg = BLLFactory<SoftwareRegister>.Instance.CheckRegisterd(usr, password, machineCode);
context.Response.ContentType
= "text/plain";
context.Response.Write(reg);
break;

以上就是执行一个检测用户是否注册的操作代码,如果授权注册了,返回true,如果用户登录成功但没有授权,返回False,其他错误返回字符串描述。具体的
BLLFactory<SoftwareRegister>.Instance.CheckRegisterd
逻辑处理代码如下所示。

        public string CheckRegisterd(string username, string passwod, stringcode)
{
bool result =VerifyUser(username, passwod, code);if(result)
{
string condition = string.Format("Username='{0}' and IsForbid <> true", username);
SoftwareRegisterInfo info
= base.FindSingle(condition);if (info != null)
{
if(info.IsRegister)
{
if (info.MachineCode != code &&info.LastAccessed.AddMinutes(10) >=DateTime.Now)
{
return "一个账号多处登录!";
}
else{
info.MachineCode
=code;
info.LastAccessed
=DateTime.Now;base.Update(info, info.ID.ToString());return "true";
}

}
else{return "false";
}
}
else{return "账号被锁定";
}
}
else{return "账号密码不正确";
}
}

那我们在共享软件的地方如何验证用户身份呢,就是通过传递页面参数并调用ashx接口处理,判断返回值即可。具体操作代码如下所示。为了简化操作,里面使用了一个我的
公用类库
来提交数据(辅助类HttpHelper)。

       private void btnOK_Click(objectsender, EventArgs e)
{
if (this.txtUserName.Text.Length == 0)
{
MessageExUtil.ShowTips(
"请输入账号密码登录");return;
}
string data = string.Format("action=r&usr={0}&pass={1}&code={2}", this.txtUserName.Text, this.txtPassword.Text,
WHC.OrderWater.Commons.HardwareInfoHelper.GetMacAddress());

HttpHelper helper
= newHttpHelper();string result = helper.GetHtml(Portal.gc.UserActionUrl, data, true);if (!string.IsNullOrEmpty(result))
{
if (result.ToLower() == "true")
{
Portal.gc.UserName
= this.txtUserName.Text;
Portal.gc.Registered
= true;

MessageExUtil.ShowTips(
"登录成功");this.DialogResult =DialogResult.OK;
}
else if (result.ToLower() == "false")
{
MessageExUtil.ShowTips(
"未授权用户,但可继续使用");

Portal.gc.UserName
= this.txtUserName.Text;
Portal.gc.Registered
= false;this.DialogResult =DialogResult.OK;
}
else{
MessageExUtil.ShowTips(
"操作失败:" +result);
}
}
else{
MessageExUtil.ShowTips(
"操作失败");
}
}

以上就是一个功能的完整实现流程,其他的功能也是类似操作,下面给出ashx的完整代码实现,供大家参考,并指正。

    /// <summary>
    ///用户测试账号可用性、注册新用户、登录验证、修改密码等操作业务处理类/// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo
=WsiProfiles.BasicProfile1_1)]public classUserAction : IHttpHandler
{
public voidProcessRequest(HttpContext context)
{
//context.Response.ContentType = "text/plain";//context.Response.Write("Hello World"); context.Request.ContentEncoding =Encoding.Default ;string action = context.Request["action"];string usr = context.Request["usr"];string password = context.Request["pass"];string machineCode = context.Request["code"];string conditon = "";bool result = false;switch(action)
{
case "r"://检测注册 UserAction.ashx?action=r&usr=&pass=&code= string reg = BLLFactory<SoftwareRegister>.Instance.CheckRegisterd(usr, password, machineCode);
context.Response.ContentType
= "text/plain";
context.Response.Write(reg);
break;case "g"://测试登录UserAction.ashx?action=g&usr=&pass=&code= result = BLLFactory<SoftwareRegister>.Instance.VerifyUser(usr, password, machineCode);
context.Response.ContentType
= "text/plain";
context.Response.Write(result);
break;case "t"://测试用户名UserAction.ashx?action=t&usr= result = BLLFactory<SoftwareRegister>.Instance.IsExistKey("Username", usr);
context.Response.ContentType
= "text/plain";
context.Response.Write(
!result);//如果存在则返回False,否则True break;case "a"://添加用户UserAction.ashx?action=a&usr=&pass=&sex=&code=&qq=&email= bool exist = BLLFactory<SoftwareRegister>.Instance.IsExistKey("Username", usr);if (!exist)
{
password
= context.Request["pass"];
machineCode
= context.Request["code"];string sex = context.Request["sex"];string qq = context.Request["qq"];string email = context.Request["email"];

SoftwareRegisterInfo newInfo
= newSoftwareRegisterInfo();
newInfo.Username
=usr;
newInfo.Password
=MD5Util.GetMD5_16(password);
newInfo.Sex
=sex;
newInfo.MachineCode
=machineCode;
newInfo.QQ
=qq;
newInfo.Email
=email;

result
= BLLFactory<SoftwareRegister>.Instance.Insert(newInfo);
}
context.Response.ContentType
= "text/plain";
context.Response.Write(result);
break;case "ep"://修改用户密码UserAction.ashx?action=ep&usr=&pass=&newp= conditon = string.Format("Username='{0}'", usr);
password
= context.Request["pass"];string newpass = context.Request["newp"];

SoftwareRegisterInfo info
= BLLFactory<SoftwareRegister>.Instance.FindSingle(conditon);if (info != null)
{
if (MD5Util.GetMD5_16(password) ==info.Password)
{
info.Password
=MD5Util.GetMD5_16(newpass);
result
= BLLFactory<SoftwareRegister>.Instance.Update(info, info.ID.ToString());
}
}
context.Response.ContentType
= "text/plain";
context.Response.Write(result);
break;
}
}
public boolIsReusable
{
get{return false;
}
}
}

如果要考虑安全性,可能整体还需要进行一定的调整,不过具体操作,已经实现了我们所需要的功能了。欢迎大家一起探讨。

在我之前的文章《
Winform分页控件支持表头全选操作实现
》中,有介绍过一种方法来实现DataGridView的表头全选操作,不过这种方式,是通过绑定字段的方式实现,每次需要创建一个字段来专门做这个列头绑定,显得有点多余。那有没有更好的方式呢,当然有,我这里介绍一种更好表头全选实现的方式,然后说明我的分页控件封装后是如何简单实现这种效果的。

1)传统的DataGridView全选实现效果。

抛开我的分页控件来讲,实现传统的DataGridView的表头全选的方式,只需要引入一个类DatagridViewCheckBoxHeaderCell,它继承自DataGridViewColumnHeaderCell,我们来看具体的使用代码:

publicFrmNormalGridViewSelect2()
{
InitializeComponent();
if (!this.DesignMode)
{
DataGridViewCheckBoxColumn colCB
= newDataGridViewCheckBoxColumn();
DatagridViewCheckBoxHeaderCell cbHeader
= newDatagridViewCheckBoxHeaderCell();
colCB.HeaderCell
=cbHeader;this.dgvSelectAll.Columns.Add(colCB);

cbHeader.OnCheckBoxClicked
+= newCheckBoxClickedHandler(cbHeader_OnCheckBoxClicked);
}
}
void cbHeader_OnCheckBoxClicked(boolstate)
{
foreach (DataGridViewRow Row indgvSelectAll.Rows)
{
Row.Cells[
0].Value =state;
Row.Selected
=state;
}
this.dgvSelectAll.RefreshEdit();
}

这样额外的代码操作即可实现表头全选的操作了,实现效果如下所示

2)基于DevExpress的GridControl控件的全选实现。

做戏做全套,我们在开发中,也经常使用到基于DevExpress的系统界面开发,那么,不用创建字段的方式,在GridControl中有无好的实现方法呢。当然有,下面我来介绍一下。

首先引入一个GridCheckMarksSelection类,这个类就是用来实现这种全选效果的,我们看看其使用的代码。

        publicFrmDevGridViwSelect2()
{
InitializeComponent();
this.gridView1.OptionsBehavior.Editable = true;this.gridView1.OptionsBehavior.ReadOnly = false;this.gridControl1.DataSourceChanged += newEventHandler(gridControl1_DataSourceChanged);
}
void gridControl1_DataSourceChanged(objectsender, EventArgs e)
{
GridCheckMarksSelection selection
= newGridCheckMarksSelection(gridView1);
selection.CheckMarkColumn.VisibleIndex
= 0;
selection.CheckMarkColumn.Width
= 60;
}

是不是很简单呢,它最终实现的效果会如下所示。

3)基于我的分页控件的全选操作

有这么好的实现效果,我当然会把它集成到我的分页控件里面了,当然,为了追求简单就是美的方式,我会尽量简化客户的使用代码。我们只需要设置一个属性即可实现表头全选的操作了(
DevExpress版本和传统版本代码一样
)。

this.winGridViewPager1.ShowCheckBox = true;

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

1)传统界面的效果

2)DotNetBar界面效果

3)DevExpress界面效果

这样的简单调用就能实现表头全选的操作,不需要另外其他额外的操作,是不是很好,简洁呢?这其实就是我追求的表头全选的最优方法了。

最后,可能读者还有一个疑问,就是我全选或者部分选择,我要知道我选择的是那些行,该怎么操作呢?放心,我这个分页控件也已经为你考虑了,呵呵。

通过调用下面的代码即实现。

        private void btnGetCheckedRows_Click(objectsender, EventArgs e)
{
List
<int> list = this.winGridViewPager1.GetCheckedRows();
StringBuilder sb
= newStringBuilder();int i = 1;foreach (int rowindex inlist)
{
sb.Append(rowindex.ToString()
+ ",");if (i++ % 10 == 0)
{
sb.Append(
"\r\n");
}
}
MessageUtil.ShowTips(sb.ToString());
}

演示例子下载:

分页控件传统界面例子
分页控件DevExpress样式例子

前面介绍很多关于我的WCF开发框架的文章,前面的介绍思路,主要是基于一个整个仓库管理系统来进行整体介绍的,本来另辟蹊径,着重介绍一个备件信息的表的在我的WCF开发框架中,各层是如何体现的,通过简单的一个表的操作,走完一个WCF开发过程,着重介绍一个对象类,如何实现整个wcf的应用。另外穿插介绍如何基于net.tcp传输方式实现wcf的应用,以及使用这种方式需要注重的地方等功能模块的介绍。

我们先来看看我的WCF开发框架整体架构设计图。

上图中,值得注意的是,WCF服务层,可以Host(寄宿)在IIS中,也可以Host在Console控制台应用程序中,或者Windows服务中等方式。

WCF 代理层一般通过在程序中添加服务引用的方式添加,添加成功后会自动生成WCF客户端的代理层,类似于添加WebService的方式。

UI可以是Winform的实现、也可以是Web的方式实现,甚至还可以是其他方式的UI实现。由于我前面介绍的WCF开发框架中,主要以Winform方式来体现,本文就另外使用asp.net的Web方式来简单介绍使用WCF服务的例子,通过简单的调用使用,我们更加清晰其调用逻辑,更好的串联起来整个WCF开发框架的实现思路。

1、 WCF服务开发

首先我们来了解一个WCF服务的开发,需要实现那些东西。从下图可以看到,需要独立一个实体类层,因为实体类是需要很多地方引用的,独立又很多好处。

其次就是业务层,它需要把我们的业务逻辑+数据访问层(可以实现多种数据库的操作)放到一起,这样作为一个整体的项目工程,更加方便管理。

创建一个WCF服务工程,添加一些必要的接口层以及配置信息,就可以实现了。具体的操作过程,可以参考《
基于我的Winform开发框架扩展而成的WCF开发框架
》这篇文章的介绍。

其中WCF服务层的开发就差不多定型了,您需要做的就是完善整个业务逻辑以及服务的调用(调用业务逻辑相关信息),如果你是使用我的WCF开发框架,所有基类的东西(包括业务层各种基类,WCF服务层的基类接口及服务基类)都是可以不用操心的,只需要实现自己的业务逻辑即可。

2、WCF服务发布及调用

通过以上的步骤1创建了WCF服务后,接下来就是如何Host我们创建的WCF服务并在客户进行调用了。WCF服务一般建议通过IIS的Host方式,这样方便管理也方便操作。如果您发布的WCF服务是net.tcp的传输方式,而且你的IIS是XP或者Win2003的,那么只能通过控制台的Host方式进发布服务了。因为Net.tcp的寄宿方式是需要IIS7以上的版本才可以。

控制台的Host方式也很简单,通过应用步骤1的WCF服务项目,然后再Program.cs类中实现下面的代码即可。

        static void Main(string[] args)
{
try{
ServiceHost serviceHost
= new ServiceHost(typeof(ItemDetailService));
serviceHost.Open();
Console.WriteLine(
"服务正在进行侦听......");
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}

运行后,效果如下所示,就表示WCF顺利通过控制台Host成功了。

WCF客户端(本例为asp.net例子)的调用代码如下所示.

namespaceTestNetTcpApp
{
public partial class_Default : System.Web.UI.Page
{
protected void Page_Load(objectsender, EventArgs e)
{
if (!this.IsPostBack)
{
BindData();
}
}
private voidBindData()
{
ItemDetailServiceClient client
= newItemDetailServiceClient();
DataTable dt
= client.FindToDataTable(string.Format("ItemName like '%六角螺栓%' or ItemName like '%轴承%'"));if (dt != null)
{
dt.Columns.Add(
"Seq", typeof(int));int i = 0;foreach (DataRow dr indt.Rows)
{
dr[
"Seq"] = i++;
}
}
this.dg.DataSource =dt;this.dg.DataBind();//new ItemDetailServiceClient().Using(client =>//{//this.dg.DataSource = client.Find(string.Format("ItemName like '%六角螺栓%'"));//this.dg.DataBind();//}); }
}
}

以上是简单的数据绑定例子,唯一值得注意的就是,本例因为考虑通过net.tcp的方式进行数据传输(也就是网络式局域网内的),因此在调用的页面,将会显示上千条的数据进行测试。如下界面所示。

3、配置信息要求。

一般的WCF服务,服务的Web.Config和调用客户的配置文件,都要对服务的相关参数进行配置,否则,很容易出现各种各种的错误提示,有响应超时、数据字节数超过支持数量、或者集合列表数据量大于设定值等等相关的错误。

1)数据量大或者集合大的配置

对于集合数据比较大,或者数量比较多的时候,如上传的图片字节比较大、返回的列表集合比较大等情况,会出现调用错误,其实这些都是因为配置参数的问题,修改即可避免,但是如果开始就知道避免,会减少反复调试的时间,提高开发效率。

2)Net.tcp的参数配置

这种方式一般是考虑在内外(局域网内)的服务调用考虑,这个调用响应会比较快,但是和传统的http配置方式有所差别,下面介绍他们的配置内容。

较早之前,曾经介绍了一篇文章《
使用DataGridView数据窗口控件,构建用户快速输入体验
》,介绍了在传统DataGridView中嵌入一个数据窗口进行选择列表,从而实现数据快速录入的操作例子,在DevExpress的控件使用中,我们应该如何实现这种效果呢,本文首先通过简单的例子介绍一下,具体的实现过程。然后进阶具体的应用,指导我们实际的开发工作,以及在使用过程中需要注意的一些特殊问题,提供相应的解决方法。

1、 GridControl集成SearchLookUpEdit的效果展现

首先我们来介绍一下整个效果图,以便有感性的印象。

1)启动后默认效果

2)弹出窗体效果

3)选中数据后效果图

其实上面是一个测试的例子,具体的应用会比较复杂一点,不过操作过程差不多,我们都是在一个Cell里面嵌入一个可以选择(包括查询)的数据列表,从中选择我们需要的内容,然后可以在另外一个Cell中输入一些其他的信息,保存的时候,一并保存即可。

2、GridControl集成SearchLookUpEdit的实现过程

在开始介绍之前,我们要清楚,这个GridControl必须先绑定数据源(数据源可以为空),如果不绑定数据源,那么虽然可以弹出列表供选择,但是鼠标移开值就会丢失的问题,一开始不明白其中道理,搞了很久。

首先要为GridControl添加两个字段,设置好他们的显示Caption和FieldName即可,然后在我们需要弹出窗口的单元格对象中,选择它的ColumnEdit控件为SearchLookup控件即可,如下所示。

这个时候,它会生成一个repositoryItemSearchLookUpEdit1的控件,这个控件就是该单元格的内嵌编辑控件了,可以从中选择列表的值,我们设置这个列表的DisplayMember为Name(显示的字段内容),ValueMember为ID(保存的值字段),如下所示。

除了你要设置主窗体里面的GridControl运行添加列外,你还需要设置编辑控件里面的View中OpitonsView里面的
NewItemRowPosition为Botton
(默认为None),这一步很重要,否则无法出现一个新建的行给你录入数据的。

例子代码比较简单,主要是为了演示这种方式的使用,代码如下所示

        DataTable dt = newDataTable();private void Form1_Load(objectsender, EventArgs e)
{
dt.Columns.Add(
"ID");
dt.Columns.Add(
"Name");for (int i = 0; i < 100; i++)
{
DataRow row
=dt.NewRow();
row[
"ID"] =i.ToString();
row[
"Name"] = (newRandom()).NextDouble().ToString();
dt.Rows.Add(row);
System.Threading.Thread.Sleep(
1);
}
this.repositoryItemSearchLookUpEdit1.DataSource =dt;this.gridControl1.DataSource =dt.Clone();
}
private void gridView1_CellValueChanged(objectsender, DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgs e)
{
if (e.Column.FieldName == "ID")
{
string id =e.Value.ToString();
DataRow[] dr
= dt.Select(string.Format("ID = '{0}'", id));if(dr != null && dr.Length > 0)
{
DataRow row
= dr[0];string name = row["Name"].ToString();
gridView1.SetRowCellValue(e.RowHandle,
"Name", name);
}
}
}

3、 GridControl集成SearchLookUpEdit的实际案例操作

一个实际的案例就是门诊的时候,医生用药的情况,除了选择其他内容外,主要的就是快速录入药品信息。我们平常去大一点 的医院看病,好像看到的多数操作都是这样。还有一种方式就是销售人员提供的报价单,从产品里面选择信息,然后修改下价格,这些场景都是很适合这样的操作的。下面是一个门诊的例子。

在实际应用中,我们在编辑一些历史数据的时候,不希望原来的记录被修改,但是可以增加新的记录,但是前面所有介绍的内容,没有能够解决这个问题,那么我们应该如何操作才能实现这个效果呢?

其实GridView对象里面有一个ShowingEditor的事件,用来判断是否显示单元格的编辑器的,这样我们对数据库已有记录进行控制,不让它在列表中显示编辑控件出来即可,具体代码如下所示。

        this.gridView1.ShowingEditor += newCancelEventHandler(gridView1_ShowingEditor);//实际使用的代码void gridView1_ShowingEditor(objectsender, CancelEventArgs e)
{
object ID = this.gridView1.GetRowCellValue(this.gridView1.FocusedRowHandle, "ID");if (ID != null && !string.IsNullOrEmpty(ID.ToString()))
{
e.Cancel
= true;
}
}

在保持数据的时候,我们对历史数据就不用修改保持,只需要针对新增的内容即可,如何做到的呢?其实就是判定他的绑定值是否存在即可,如果有绑定值,那么就是历史的数据,没有就是新的,进行特殊操作即可,如下代码所示。

            if (this.gridView1.RowCount > 0)
{
#region 提交用药记录明细 for (int i = 0; i < this.gridView1.RowCount; i++)
{
//根据ID来判断是否新增的用药记录 object ID = this.gridView1.GetRowCellValue(i, "ID");if (ID == null || string.IsNullOrEmpty(ID.ToString()))
{
//......................... }
}
#endregion}