注冊(cè)會(huì)員,創(chuàng)建你的web開(kāi)發(fā)資料庫(kù),
在數(shù)據(jù)庫(kù)應(yīng)用程序開(kāi)發(fā)中,我們知道數(shù)據(jù)操作的主要任務(wù)是:“瀏覽、編輯、刪除、添加記錄”,利用vb.net的“數(shù)據(jù)窗體向?qū)А笨梢詭椭覀冄杆賱?chuàng)建實(shí)現(xiàn)上述功能的windows 窗體及相關(guān)代碼,這種自動(dòng)生成的代碼完全具有實(shí)用性和可借鑒性。然而筆者在使用中發(fā)現(xiàn),在“數(shù)據(jù)窗體向?qū)А钡牟僮鬟^(guò)程中,如果我們選擇的是“單個(gè)控件的單個(gè)記錄”顯示樣式,假如控件綁定到的數(shù)據(jù)源中的字段又有不允許為null值的話,運(yùn)行自動(dòng)生成的窗體,單擊“添加”后會(huì)出現(xiàn)錯(cuò)誤。
為了避免該錯(cuò)誤,已有的解決方法是:“添加”功能不使用“數(shù)據(jù)窗體向?qū)А鄙傻拇a,而是新建一窗體然后采用非數(shù)據(jù)綁定結(jié)構(gòu)來(lái)單獨(dú)實(shí)現(xiàn)“添加”功能。筆者經(jīng)過(guò)探索發(fā)現(xiàn)完全沒(méi)有必要另建窗體,只需對(duì)“數(shù)據(jù)窗體向?qū)А鄙傻拇a進(jìn)行適當(dāng)?shù)母倪M(jìn)就可以在同一個(gè)窗體中同時(shí)實(shí)現(xiàn)“瀏覽、編輯、刪除、增加”功能,如下通過(guò)實(shí)例說(shuō)明(注:開(kāi)發(fā)工具為microsoft visual studio .net 2003 ,示例數(shù)據(jù)庫(kù)是sql server 2000中的“pubs”;以下代碼雖然以vb為例,但方法同樣適用于vs.net中的其它開(kāi)發(fā)語(yǔ)言)。
一、 有不允許為null值的字段綁定到非textbox類控件
如下圖一所示就是屬于這類情況,窗體中“contract”旁的復(fù)選框控件綁定到的列字段“contract”就不允許有null值。運(yùn)行該窗體并“加載”后,單擊“添加”可以“新增”記錄(編號(hào)為24的記錄),但單擊導(dǎo)航按鈕(比如最后一條“>>”),記錄位置不能移到該新增記錄。
圖一窗體及代碼是由“數(shù)據(jù)窗體向?qū)А弊詣?dòng)生成(菜單操作:“文件/添加新項(xiàng)”,然后選 “數(shù)據(jù)窗體向?qū)А保瑪?shù)據(jù)窗體實(shí)例的名稱是“demo”,數(shù)據(jù)集的名稱是“ds”,數(shù)據(jù)連接是以sql server 2000中的“pubs” 示例數(shù)據(jù)庫(kù)為例,選擇“authors”表,選擇“單個(gè)控件的單個(gè)記錄”顯示樣式,其它都采用“數(shù)據(jù)窗體向?qū)А钡哪J(rèn)值。圖一這一類情況的改進(jìn)方法是首先修改“添加”按鈕的單擊事件處理代碼,如下所示。
private sub btnadd_click(byval sender as system.object, byval e as system.eventargs) handles btnadd.click
try
me.bindingcontext(objds, "authors").endcurrentedit()
me.bindingcontext(objds, "authors").suspendbinding() '臨時(shí)掛起數(shù)據(jù)綁定
me.bindingcontext(objds, "authors").addnew() '增加新記錄
'如下兩層循環(huán)先找出authors表中不允許為null的列字段,然后找出綁定到該字段的binding對(duì)象,
'依據(jù)綁定到的控件屬性不同來(lái)為新增記錄中不能為空的字段賦不同初始值
dim i as integer
for i = 0 to objds.authors.columns.count - 1 '遍歷authors表中所有列字段
'找出authors表中不允許為null的列字段
if objds.tables("authors").columns(i).allowdbnull = false then
dim j as integer
for j = 0 to me.bindingcontext(objds, "authors").bindings.count - 1 '遍歷所有binding對(duì)象
'找出綁定到不允許為null字段的binding對(duì)象
if me.bindingcontext(objds, "authors").bindings(j).bindingmemberinfo.bindingfield = _
objds.authors.columns(i).columnname then
'如果綁定到的控件的屬性為text
if bindingcontext(objds, "authors").bindings(j).propertyname() = "text" then
'新增加記錄中不能為null的字段賦初始值"",該語(yǔ)句還可用緊挨著的注釋語(yǔ)句代替!
me.bindingcontext(objds, "authors").current(j) = ""
'bindingcontext(objds, "authors").current(i) = bindingcontext(objds, "authors"). _
' bindings(j).control.text()
exit for '退出當(dāng)前for循環(huán),尋找下一個(gè)不允許為null的列字段
else
'如果綁定到的控件的屬性為checked(其它綁定屬性…,應(yīng)該可以自己仿照搞定了.)
if bindingcontext(objds, "authors").bindings(j).propertyname = "checked" then
'新增加記錄中不能為null的字段賦初始值true, 該語(yǔ)句可用緊挨著的4行注釋語(yǔ)句代替!
me.bindingcontext(objds, "authors").current(j) = true
'dim tmpobj as object
'tmpobj = bindingcontext(objds, "authors").bindings(j).control
'tmpobj = ctype(tmpobj, checkbox)
'me.bindingcontext(objds, "authors").current(j) = tmpobj.checked
exit for '退出當(dāng)前for循環(huán),尋找下一個(gè)不允許為null的列字段
end if
end if
end if
next
end if
next
'如新增加行不需利用row_changing事件進(jìn)行數(shù)值驗(yàn)證,可啟用下邊注釋行
'me.bindingcontext(objds, "authors").endcurrentedit()
me.bindingcontext(objds, "authors").resumebinding() '恢復(fù)數(shù)據(jù)綁定
'移動(dòng)表中位置到新增加記錄
me.bindingcontext(objds, "authors").position = me.bindingcontext(objds, "authors").count - 1
catch eendedit as system.exception
system.windows.forms.messagebox.show(eendedit.message)
me.bindingcontext(objds, "authors").cancelcurrentedit() '出錯(cuò),取消新增加行
me.bindingcontext(objds, "authors").resumebinding()
end try
me.objds_positionchanged()
end sub
以上btnadd.click事件處理代碼改進(jìn)的實(shí)質(zhì)是:臨時(shí)掛起數(shù)據(jù)綁定,新增一記錄,然后對(duì)記錄中不允許為null值的列字段賦值(如不需利用rowchanging事件進(jìn)行新增記錄數(shù)據(jù)檢驗(yàn),也可僅對(duì)不允許null值且不能綁定到文本框textbox的字段賦初值),最后恢復(fù)數(shù)據(jù)綁定。
此外,還要對(duì)四個(gè)導(dǎo)航按鈕(第一條、上一條、下一條、最后一條)的單擊事件處理程序作如下修改(為了簡(jiǎn)化,此處只以上一條“<”按鈕的單擊事件處理程序?yàn)槔?,其它按鈕仿照)。
private sub btnnavprev_click(byval sender as system.object, byval e as system.eventargs) handles btnnavprev.click
try '采用try語(yǔ)句進(jìn)行錯(cuò)誤處理(null及唯一性)
me.bindingcontext(objds, "authors").position = (me.bindingcontext(objds, "authors").position - 1)
catch ex as exception
messagebox.show(ex.message) '顯示錯(cuò)誤信息
exit sub '如有錯(cuò)誤,不許移動(dòng)位置
end try
me.objds_positionchanged()
end sub
如果想利用rowchanging事件對(duì)新增加或編輯…記錄進(jìn)行數(shù)據(jù)檢驗(yàn)(建議),則還需要增加如下rowchanging事件處理代碼。
private sub row_changing(byval sender as object, byval e as ds.authorsrowchangeevent)
'對(duì)新增加行進(jìn)行數(shù)值驗(yàn)證
if e.action = datarowaction.add then
'此處為了簡(jiǎn)單,以字段au_id不能為""為例
if editau_id.text = "" then
throw (new exception("數(shù)據(jù)不能為空"))
end if
end if
'還可以對(duì)記錄的編輯值進(jìn)行驗(yàn)證
'if e.action = datarowaction.change then
'此處填入編輯驗(yàn)證代碼
'end if
'其它驗(yàn)證,依照上面加入吧
end sub
要啟動(dòng)rowchanging事件處理,請(qǐng)?jiān)诔绦虻倪m當(dāng)位置加入如下語(yǔ)句(本人是加在loaddataset()方法中的語(yǔ)句objds.merge(objdatasettemp)后面)。
addhandler objds.authors.authorsrowchanging, addressof row_changing
二、 雖然有不允許為null值的字段,但全部都能綁定到textbox類控件
為了說(shuō)明方便,我們?cè)倮谩皵?shù)據(jù)窗體向?qū)А毙陆ㄒ淮绑w(注:新窗體可以建在上一個(gè)窗體的同一個(gè)項(xiàng)目中,數(shù)據(jù)窗體的名稱是“demo2”,新建數(shù)據(jù)集名稱為“ds2”),該數(shù)據(jù)窗體是綁定到“pubs”數(shù)據(jù)庫(kù)中的“employee”表。如圖二所示,該表中的所有不允許為null值的字段都能綁定到textbox類控件。
運(yùn)行該窗體后,單擊“加載”后可以新增記錄(編號(hào)為44的記錄),但是如果新增記錄后不輸入任何值而單擊任一導(dǎo)航按鈕(比如上一條“<”),會(huì)出現(xiàn)如圖三所示錯(cuò)誤。
這一類錯(cuò)誤較輕,完全可以采用第一種情況的解決方法,當(dāng)然如果你嫌多的話,還可以采用如下更為簡(jiǎn)單的方法: 在“數(shù)據(jù)窗體向?qū)А弊詣?dòng)生成的代碼中,只需對(duì)四個(gè)導(dǎo)航按鈕(第一條、上一條、下一條、最后一條)的單擊事件處理程序代碼進(jìn)行適當(dāng)修改(注意:還是按照第一種情況中四個(gè)導(dǎo)航按鈕的代碼修改方法進(jìn)行修改),其它代碼不變也不增加,一切就0k了,此時(shí)再試試,你會(huì)見(jiàn)到如圖四友好的界面,提示你必須對(duì)不允許空值的列字段進(jìn)行輸入,然后才能改變記錄位置。
三、 總結(jié)
當(dāng)有不許null值的字段綁定到數(shù)據(jù)窗體上時(shí),為了避免出現(xiàn)新增記錄錯(cuò)誤,在上面筆者介紹了可以在代碼中找到解決辦法,另外我們還可以在數(shù)據(jù)集中找到解決辦法:“在數(shù)據(jù)集的架構(gòu)中,對(duì)不允許null值的列字段給它設(shè)置一默認(rèn)值即可”,當(dāng)然具體采用哪種解決方法還是請(qǐng)你根據(jù)實(shí)際情況靈活選擇。
上面給出了第一種情況的主要解決代碼,末盡之處請(qǐng)大家參照下邊完整代碼。
public class demo
inherits system.windows.forms.form
'為了簡(jiǎn)化,“windows 窗體設(shè)計(jì)器生成的代碼”去掉了,記住在“數(shù)據(jù)窗體向?qū)А眻?zhí)行時(shí)按照以下要求即可。
'數(shù)據(jù)窗體實(shí)例的名稱是“demo”,數(shù)據(jù)集的名稱是“ds”,數(shù)據(jù)連接是以sql server 2000中
'的“pubs” 示例數(shù)據(jù)庫(kù)為例,選擇“authors”表、“單個(gè)控件的單個(gè)記錄”顯示樣式,其它都采用的默認(rèn)值。
private sub btncancel_click(byval sender as system.object, byval e as system.eventargs) handles btncancel.click
me.bindingcontext(objds, "authors").cancelcurrentedit()
me.objds_positionchanged()
end sub
private sub btndelete_click(byval sender as system.object, byval e as system.eventargs) handles btndelete.click
if (me.bindingcontext(objds, "authors").count > 0) then
me.bindingcontext(objds, "authors").removeat(me.bindingcontext(objds, "authors").position)
me.objds_positionchanged()
end if
end sub
private sub btnadd_click(byval sender as system.object, byval e as system.eventargs) handles btnadd.click
try
me.bindingcontext(objds, "authors").endcurrentedit()
me.bindingcontext(objds, "authors").suspendbinding()
me.bindingcontext(objds, "authors").addnew()
dim i as integer
for i = 0 to objds.authors.columns.count - 1
if objds.tables("authors").columns(i).allowdbnull = false then
dim j as integer
for j = 0 to me.bindingcontext(objds, "authors").bindings.count - 1
if me.bindingcontext(objds, "authors").bindings(j).bindingmemberinfo.bindingfield = _
objds.authors.columns(i).columnname then
if bindingcontext(objds, "authors").bindings(j).propertyname() = "text" then
me.bindingcontext(objds, "authors").current(j) = ""
'bindingcontext(objds, "authors").current(i) = bindingcontext(objds, "authors"). _
' bindings(j).control.text()
exit for
else
if bindingcontext(objds, "authors").bindings(j).propertyname = "checked" then
me.bindingcontext(objds, "authors").current(j) = true
'dim tmpobj as object
'tmpobj = bindingcontext(objds, "authors").bindings(i).control
'tmpobj = ctype(tmpobj, checkbox)
'me.bindingcontext(objds, "authors").current(i) = tmpobj.checked
exit for
end if
end if
end if
next
end if
next
me.bindingcontext(objds, "authors").resumebinding()
me.bindingcontext(objds, "authors").position = me.bindingcontext(objds, "authors").count - 1
catch eendedit as system.exception
system.windows.forms.messagebox.show(eendedit.message)
me.bindingcontext(objds, "authors").cancelcurrentedit()
me.bindingcontext(objds, "authors").resumebinding()
end try
me.objds_positionchanged()
end sub
private sub btnupdate_click(byval sender as system.object, byval e as system.eventargs) handles btnupdate.click
try
'嘗試更新數(shù)據(jù)源。
me.updatedataset()
catch eupdate as system.exception
'在此處添加錯(cuò)誤處理代碼。
'顯示錯(cuò)誤信息(如果有)。
objds.rejectchanges() '我增加的語(yǔ)句
system.windows.forms.messagebox.show(eupdate.message)
end try
me.objds_positionchanged()
end sub
private sub btnload_click(byval sender as system.object, byval e as system.eventargs) handles btnload.click
try
'嘗試加載數(shù)據(jù)集。
me.loaddataset()
catch eload as system.exception
'在此處添加錯(cuò)誤處理代碼。
'顯示錯(cuò)誤信息(如果有)。
system.windows.forms.messagebox.show(eload.message)
end try
me.objds_positionchanged()
end sub
private sub btnnavfirst_click(byval sender as system.object, byval e as system.eventargs) handles btnnavfirst.click
try
me.bindingcontext(objds, "authors").position = 0
catch ex as exception
messagebox.show(ex.message)
exit sub
end try
me.objds_positionchanged()
end sub
private sub btnlast_click(byval sender as system.object, byval e as system.eventargs) handles btnlast.click
' me.bindingcontext(objds, "authors").position = (me.objds.tables("authors").rows.count - 1)
try
'注意下一條語(yǔ)句我進(jìn)行了修改
me.bindingcontext(objds, "authors").position = me.bindingcontext(objds, "authors").count - 1
catch ex as exception
messagebox.show(ex.message)
exit sub
end try
me.objds_positionchanged()
end sub
private sub btnnavprev_click(byval sender as system.object, byval e as system.eventargs) handles btnnavprev.click
try '采用try語(yǔ)句進(jìn)行錯(cuò)誤檢查(null及唯一性)
me.bindingcontext(objds, "authors").position = (me.bindingcontext(objds, "authors").position - 1)
catch ex as exception
messagebox.show(ex.message)
exit sub '如有錯(cuò)誤,不許移動(dòng)位置
end try
me.objds_positionchanged()
end sub
private sub btnnavnext_click(byval sender as system.object, byval e as system.eventargs) handles btnnavnext.click
'if bindingcontext(objds, "authors").position = bindingcontext(objds, "authors").count - 1 then '可不要
' messagebox.show("數(shù)據(jù)到頂了!")
' exit sub
'end if
try
me.bindingcontext(objds, "authors").position = (me.bindingcontext(objds, "authors").position + 1)
catch ex as exception
messagebox.show(ex.message)
exit sub
end try
me.objds_positionchanged()
end sub
private sub objds_positionchanged()
me.lblnavlocation.text = (((me.bindingcontext(objds, "authors").position + 1).tostring + " 的 ") _
+ me.bindingcontext(objds, "authors").count.tostring)
end sub
private sub btncancelall_click(byval sender as system.object, byval e as system.eventargs) handles btncancelall.click
me.objds.rejectchanges()
me.objds_positionchanged() '我增加的語(yǔ)句
end sub
public sub updatedataset()
'創(chuàng)建一個(gè)新數(shù)據(jù)集來(lái)保存對(duì)主數(shù)據(jù)集所做的更改。
dim objdatasetchanges as ds = new ds
'停止當(dāng)前的任何編輯。
me.bindingcontext(objds, "authors").endcurrentedit()
'獲取對(duì)主數(shù)據(jù)集所做的更改。
objdatasetchanges = ctype(objds.getchanges, ds)
'檢查是否做了任何更改。
if (not (objdatasetchanges) is nothing) then
try
'需要做一些更改,所以嘗試通過(guò)調(diào)用 update 方法
'和傳遞數(shù)據(jù)集以及任何參數(shù)來(lái)更新數(shù)據(jù)源。
me.updatedatasource(objdatasetchanges)
objds.merge(objdatasetchanges)
objds.acceptchanges()
catch eupdate as system.exception
'在此處添加錯(cuò)誤處理代碼。
throw eupdate
end try
'添加代碼以檢查返回的數(shù)據(jù)集中是否有任何可能已被
'推入到行對(duì)象錯(cuò)誤中的錯(cuò)誤。
end if
end sub
public sub loaddataset()
'創(chuàng)建一個(gè)新數(shù)據(jù)集以保存從 filldataset 調(diào)用返回的記錄。
'使用了一個(gè)臨時(shí)數(shù)據(jù)集,這是因?yàn)樘畛洮F(xiàn)有的數(shù)據(jù)集
'需要重新綁定數(shù)據(jù)綁定。
dim objdatasettemp as ds
objdatasettemp = new ds
try
'嘗試填充臨時(shí)數(shù)據(jù)集。
me.filldataset(objdatasettemp)
catch efilldataset as system.exception
'在此處添加錯(cuò)誤處理代碼。
throw efilldataset
end try
try
'清空數(shù)據(jù)集中的舊記錄。
objds.clear()
'將記錄合并到主數(shù)據(jù)集中。
objds.merge(objdatasettemp)
'我在此處加入rowchanging事件
addhandler objds.authors.authorsrowchanging, addressof row_changing
catch eloadmerge as system.exception
'在此處添加錯(cuò)誤處理代碼。
throw eloadmerge
end try
end sub
public sub updatedatasource(byval changedrows as ds)
try
'在有掛起的更改時(shí),只需要更新數(shù)據(jù)源即可。
if (not (changedrows) is nothing) then
'打開(kāi)連接。
me.oledbconnection1.open()
'嘗試更新數(shù)據(jù)源。
oledbdataadapter1.update(changedrows)
end if
catch updateexception as system.exception
'在此處添加錯(cuò)誤處理代碼。
throw updateexception
finally
'無(wú)論是否引發(fā)了異常都關(guān)閉連接。
me.oledbconnection1.close()
end try
end sub
public sub filldataset(byval dataset as ds)
'在填充數(shù)據(jù)集前關(guān)閉約束檢查。
'這允許適配器填充數(shù)據(jù)集而不用考慮
'表之間的依賴項(xiàng)。
dataset.enforceconstraints = false
try
'打開(kāi)連接。
me.oledbconnection1.open()
'嘗試通過(guò) oledbdataadapter1 填充數(shù)據(jù)集。
me.oledbdataadapter1.fill(dataset)
catch fillexception as system.exception
'在此處添加錯(cuò)誤處理代碼。
throw fillexception
finally
'重新打開(kāi)約束檢查。
dataset.enforceconstraints = true
'無(wú)論是否引發(fā)了異常都關(guān)閉連接。
me.oledbconnection1.close()
end try
end sub
private sub row_changing(byval sender as object, byval e as ds.authorsrowchangeevent)
'對(duì)新增加行進(jìn)行數(shù)值驗(yàn)證
if e.action = datarowaction.add then
'此處為了簡(jiǎn)單,以字段au_id不能為""為例
if editau_id.text = "" then
throw (new exception("數(shù)據(jù)不能為空"))
end if
end if
'還可以對(duì)記錄的編輯值進(jìn)行驗(yàn)證
'if e.action = datarowaction.change then
'此處填入編輯驗(yàn)證代碼
'end if
'其它驗(yàn)證,依照上面加入吧
end sub
end class
以上代碼在microsoft visual studio .net 2003 + sql server 2000中的“pubs” 示例數(shù)據(jù)庫(kù)中調(diào)試通過(guò)。