Академический Документы
Профессиональный Документы
Культура Документы
1 of15
thesefourproductvaluesplustheProductID.Likeinourpreviousoverloads,thisonewill: 1. RetrievetheproductinformationfromthedatabaseforthespecifiedProductID, 2. UpdatetheProductName,CategoryID,SupplierID,andDiscontinued fields,and 3. SendtheupdaterequesttotheDALthroughtheTableAdapter's Update() method. Forbrevity,forthisparticularoverloadI'veomittedthebusinessrulecheckthatensuresaproductbeingmarked asdiscontinuedisn'ttheonlyproductofferedbyitssupplier.Feelfreetoadditinifyouprefer,or,ideally, refactoroutthelogictoaseparatemethod. ThefollowingcodeshowsthenewUpdateProduct overloadintheProductsBLL class:
[System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update,false)] publicboolUpdateProduct(stringproductName,int?categoryID, int?supplierID,booldiscontinued,intproductID) { Northwind.ProductsDataTableproducts=Adapter.GetProductByProductID(productID) if(products.Count==0) //nomatchingrecordfound,returnfalse returnfalse Northwind.ProductsRowproduct=products[0] product.ProductName=productName if(supplierID==null)product.SetSupplierIDNull() elseproduct.SupplierID=supplierID.Value if(categoryID==null)product.SetCategoryIDNull() elseproduct.CategoryID=categoryID.Value product.Discontinued=discontinued //Updatetheproductrecord introwsAffected=Adapter.Update(product) //Returntrueifpreciselyonerowwasupdated,otherwisefalse returnrowsAffected==1 }
Step2:CraftingtheEditableGridView
WiththeUpdateProduct overloadadded,we'rereadytocreateoureditableGridView.Openthe CustomizedUI.aspx pageinthe EditInsertDelete folderandaddaGridViewcontroltotheDesigner.Next, createanewObjectDataSourcefromtheGridView'ssmarttag.ConfiguretheObjectDataSourcetoretrieve productinformationviatheProductBLL class'sGetProducts() methodandtoupdateproductdatausingthe UpdateProduct overloadwejustcreated.FromtheINSERTandDELETEtabs,select(None)fromthedrop downlists.
2 of15
Figure2:ConfiguretheObjectDataSourcetoUsetheUpdateProduct OverloadJustCreated Aswe'veseenthroughoutthedatamodificationtutorials,thedeclarativesyntaxfortheObjectDataSource createdbyVisualStudioassignstheOldValuesParameterFormatString propertytooriginal_{0}.This,of course,won'tworkwithourBusinessLogicLayersinceourmethodsdon'texpecttheoriginalProductID value tobepassedin.Therefore,aswe'vedoneinprevioustutorials,takeamomenttoremovethisproperty assignmentfromthedeclarativesyntaxor,instead,setthisproperty'svalueto{0}. Afterthischange,theObjectDataSource'sdeclarativemarkupshouldlooklikethefollowing:
<asp:ObjectDataSourceID="ObjectDataSource1"runat="server" SelectMethod="GetProducts"TypeName="ProductsBLL" UpdateMethod="UpdateProduct"> <UpdateParameters> <asp:ParameterName="productName"Type="String"/> <asp:ParameterName="categoryID"Type="Int32"/> <asp:ParameterName="supplierID"Type="Int32"/> <asp:ParameterName="discontinued"Type="Boolean"/> <asp:ParameterName="productID"Type="Int32"/> </UpdateParameters> </asp:ObjectDataSource>
ItonlyincludestheProductName,SupplierName,CategoryName BoundFieldsandtheDiscontinued CheckBoxField TheCategoryName andSupplierName fieldstoappearbefore(totheleftof)theDiscontinued CheckBoxField TheCategoryName andSupplierName BoundFields'HeaderText propertyissetto"Category"and
3 of15
"Supplier",respectively Editingsupportisenabled(checktheEnableEditingcheckboxintheGridView'ssmarttag)
Afterthesechanges,theDesignerwilllooksimilartoFigure3,withtheGridView'sdeclarativesyntaxshown below.
Figure3:RemovetheUnneededFieldsfromtheGridView
<asp:GridViewID="GridView1"runat="server"AutoGenerateColumns="False" DataKeyNames="ProductID"DataSourceID="ObjectDataSource1"> <Columns> <asp:BoundFieldDataField="ProductName" HeaderText="ProductName"SortExpression="ProductName"/> <asp:BoundFieldDataField="CategoryName"HeaderText="Category" ReadOnly="True" SortExpression="CategoryName"/> <asp:BoundFieldDataField="SupplierName"HeaderText="Supplier" ReadOnly="True" SortExpression="SupplierName"/> <asp:CheckBoxFieldDataField="Discontinued" HeaderText="Discontinued"SortExpression="Discontinued"/> </Columns>
</asp:GridView>
AtthispointtheGridView'sreadonlybehavioriscomplete.Whenviewingthedata,eachproductisrendered asarowintheGridView,showingtheproduct'sname,category,supplier,anddiscontinuedstatus.
4 of15
Step3:UsingaDropDownListfortheCategoryand SupplierEditingInterfaces
RecallthattheProductsRow objectcontains CategoryID,CategoryName,SupplierID,andSupplierName properties,whichprovidetheactualforeignkeyIDvaluesintheProducts databasetableandthe correspondingName valuesintheCategories andSuppliers tables.TheProductRow'sCategoryID and SupplierID canbothbereadfromandwrittento,whiletheCategoryName andSupplierName propertiesare markedreadonly. DuetothereadonlystatusoftheCategoryName andSupplierName properties,thecorrespondingBoundFields havehadtheirReadOnly propertysettotrue,preventingthesevaluesfrombeingmodifiedwhenarowis edited.WhilewecansettheReadOnly propertytofalse,renderingtheCategoryName andSupplierName BoundFieldsasTextBoxesduringediting,suchanapproachwillresultinanexceptionwhentheuserattempts toupdatetheproductsincethereisnoUpdateProduct overloadthattakesin CategoryName andSupplierName inputs.Infact,wedon'twanttocreatesuchanoverloadfortworeasons:
l
TheProducts tabledoesn'thave SupplierName orCategoryName fields,butSupplierID and CategoryID.Therefore,wewantourmethodtobepassedtheseparticularIDvalues,nottheirlookup tables'values. Requiringtheusertotypeinthenameofthesupplierorcategoryislessthanideal,asitrequirestheuser toknowtheavailablecategoriesandsuppliersandtheircorrectspellings.
Thesupplierandcategoryfieldsshoulddisplaythecategoryandsuppliers'nameswheninreadonlymode(asit
5 of15
doesnow)andadropdownlistofapplicableoptionswhenbeingedited.Usingadropdownlist,theenduser canquicklyseewhatcategoriesandsuppliersareavailabletochooseamongandcanmoreeasilymaketheir selection. Toprovidethisbehavior,weneedtoconverttheSupplierName andCategoryName BoundFieldsinto TemplateFieldswhoseItemTemplate emitstheSupplierName andCategoryName valuesandwhose EditItemTemplate usesaDropDownListcontroltolisttheavailablecategoriesandsuppliers. AddingtheCategories andSuppliers DropDownLists StartbyconvertingtheSupplierName andCategoryName BoundFieldsintoTemplateFieldsby:clickingonthe EditColumnslinkfromtheGridView'ssmarttagselectingtheBoundFieldfromthelistinthelowerleftand clickingthe"ConvertthisfieldintoaTemplateField"link.TheconversionprocesswillcreateaTemplateField withbothanItemTemplate andanEditItemTemplate,asshowninthedeclarativesyntaxbelow:
<asp:TemplateFieldHeaderText="Category"SortExpression="CategoryName"> <EditItemTemplate> <asp:LabelID="Label1"runat="server" Text='<%#Eval("CategoryName")%>'></asp:Label> </EditItemTemplate> <ItemTemplate> <asp:LabelID="Label1"runat="server" Text='<%#Bind("CategoryName")%>'></asp:Label> </ItemTemplate> </asp:TemplateField>
SincetheBoundFieldwasmarkedasreadonly,boththeItemTemplate andEditItemTemplate containa LabelWebcontrolwhoseText propertyisboundtotheapplicabledatafield(CategoryName,inthesyntax above).WeneedtomodifytheEditItemTemplate,replacingtheLabelWebcontrolwithaDropDownList control. Aswe'veseeninprevioustutorials,thetemplatecanbeeditedthroughtheDesignerordirectlyfromthe declarativesyntax.ToedititthroughtheDesigner,clickontheEditTemplateslinkfromtheGridView'ssmart tagandchoosetoworkwiththeCategoryfield's EditItemTemplate.RemovetheLabelWebcontroland replaceitwithaDropDownListcontrol,settingtheDropDownList'sIDpropertytoCategories.
6 of15
Figure6:CreateaNewObjectDataSourceControlNamedCategoriesDataSource
7 of15
8 of15
TemplateFieldwillincludebothaDropDownListandanObjectDataSource:
<asp:TemplateFieldHeaderText="Category"SortExpression="CategoryName"> <EditItemTemplate> <asp:DropDownListID="Categories"runat="server" DataSourceID="CategoriesDataSource" DataTextField="CategoryName"DataValueField="CategoryID"> </asp:DropDownList> <asp:ObjectDataSourceID="CategoriesDataSource"runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"TypeName="CategoriesBLL"> </asp:ObjectDataSource> </EditItemTemplate> <ItemTemplate> <asp:LabelID="Label1"runat="server" Text='<%#Bind("CategoryName")%>'></asp:Label> </ItemTemplate> </asp:TemplateField>
Note:TheDropDownListintheEditItemTemplate musthaveitsviewstateenabled.Wewillsoonadd databindingsyntaxtotheDropDownList'sdeclarativesyntaxanddatabindingcommandslikeEval() andBind () canonlyappearincontrolswhoseviewstateisenabled. RepeatthesestepstoaddaDropDownListnamedSuppliers totheSupplierName TemplateField's EditItemTemplate.ThiswillinvolveaddingaDropDownListtotheEditItemTemplate andcreatinganother ObjectDataSource.TheSuppliers DropDownList'sObjectDataSource,however,shouldbeconfiguredto invoketheSuppliersBLL class'sGetSuppliers() method.Additionally,configuretheSuppliers DropDownListtodisplaytheCompanyName fieldandusetheSupplierID fieldasthevalueforits ListItems. AfteraddingtheDropDownListstothetwoEditItemTemplates,loadthepageinabrowserandclicktheEdit buttonfortheChefAnton'sCajunSeasoningproduct.AsFigure9shows,theproduct'scategoryandsupplier columnsarerenderedasdropdownlistscontainingtheavailablecategoriesandsupplierstochoosefrom. However,notethatthefirstitemsinbothdropdownlistsareselectedbydefault(Beveragesforthecategory andExoticLiquidsasthesupplier),eventhoughChefAnton'sCajunSeasoningisaCondimentsuppliedby NewOrleansCajunDelights.
Figure9:TheFirstItemintheDropDownListsisSelectedbyDefault
9 of15
Furthermore,ifyouclickUpdate,you'llfindthattheproduct'sCategoryID andSupplierID valuesaresetto NULL.BothoftheseundesiredbehaviorsarecausedbecausetheDropDownListsintheEditItemTemplate sare notboundtoanydatafieldsfromtheunderlyingproductdata. BindingtheDropDownListstotheCategoryID andSupplierID DataFields Inordertohavetheeditedproduct'scategoryandsupplierdropdownlistssettotheappropriatevaluesandto havethesevaluessentbacktotheBLL'sUpdateProduct methoduponclickingUpdate,weneedtobindthe DropDownLists'SelectedValue propertiestotheCategoryID andSupplierID datafieldsusingtwoway databinding.ToaccomplishthiswiththeCategories DropDownList,youcanaddSelectedValue='<%#Bind ("CategoryID")%>' directlytothedeclarativesyntax. Alternatively,youcansettheDropDownList'sdatabindingsbyeditingthetemplatethroughtheDesignerand clickingtheEditDataBindingslinkfromtheDropDownList'ssmarttag.Next,indicatethattheSelectedValue propertyshouldbeboundtotheCategoryID fieldusingtwowaydatabinding(seeFigure10).Repeateitherthe declarativeorDesignerprocesstobindtheSupplierID datafieldtotheSuppliers DropDownList.
Figure10:BindtheCategoryID totheDropDownList'sSelectedValue PropertyUsingTwoWay Databinding OncethebindingshavebeenappliedtotheSelectedValue propertiesofthetwoDropDownLists,theedited product'scategoryandsuppliercolumnswilldefaulttothecurrentproduct'svalues.UponclickingUpdate,the CategoryID andSupplierID valuesoftheselecteddropdownlistitemwillbepassedtotheUpdateProduct method.Figure11showsthetutorialafterthedatabindingstatementshavebeenaddednotehowtheselected dropdownlistitemsforChefAnton'sCajunSeasoningarecorrectlyCondimentandNewOrleansCajun Delights.
10 of15
Usercannotuseourinterfacetochangeaproduct'scategoryorsupplierfromanonNULL valuetoaNULL one IfaproducthasaNULL CategoryID orSupplierID,clickingtheEditbuttonwillresultinanexception. ThisisbecausetheNULL valuereturnedbyCategoryID (orSupplierID)intheBind() statementdoes notmaptoavalueintheDropDownList(theDropDownListthrowsanexceptionwhenits SelectedValue propertyissettoavaluenot initscollectionoflistitems).
InordertosupportNULL CategoryID andSupplierID values,weneedtoaddanotherListItem toeach DropDownListtorepresenttheNULL value.IntheMaster/DetailFilteringWithaDropDownList tutorial,we sawhowtoaddanadditionalListItem toadataboundDropDownList,whichinvolvedsettingthe DropDownList'sAppendDataBoundItems propertytotrue andmanuallyaddingtheadditionalListItem.In thatprevioustutorial,however,weaddedaListItem withaValue of1.ThedatabindinglogicinASP.NET, however,willautomaticallyconvertablankstringtoaNULL valueandviceaversa.Therefore,forthistutorial wewanttheListItem'sValue tobeanemptystring. StartbysettingbothDropDownLists'AppendDataBoundItems propertytotrue.Next,addtheNULL ListItem byaddingthefollowing<asp:ListItem> elementtoeachDropDownListsothatthedeclarativemarkuplooks like:
<asp:DropDownListID="Categories"runat="server" DataSourceID="CategoriesDataSource"DataTextField="CategoryName" DataValueField="CategoryID"SelectedValue='<%#Bind("CategoryID")%>' AppendDataBoundItems="True"> <asp:ListItemValue="">(None)</asp:ListItem> </asp:DropDownList>
I'vechosentouse"(None)"astheTextvalueforthisListItem,butyoucanchangeittoalsobeablankstring ifyou'dlike.
11 of15
Note:AswesawintheMaster/DetailFilteringWithaDropDownList tutorial,ListItemscanbeaddedtoa DropDownListthroughtheDesignerbyclickingontheDropDownList'sItems propertyintheProperties window(whichwilldisplaytheListItem CollectionEditor).However,besuretoaddtheNULL ListItem for thistutorialthroughthedeclarativesyntax.IfyouusetheListItem CollectionEditor,thegenerateddeclarative syntaxwillomittheValue settingaltogetherwhenassignedablankstring,creatingdeclarativemarkuplike: <asp:ListItem>(None)</asp:ListItem>.Whilethismaylookharmless,themissingValuecausesthe DropDownListtousetheText propertyvalueinitsplace.ThatmeansthatifthisNULL ListItem isselected, thevalue"(None)"willbeattemptedtobeassignedtotheCategoryID,whichwillresultinanexception.By explicitlysettingValue="",aNULL valuewillbeassignedto CategoryID whentheNULL ListItem isselected. RepeatthesestepsfortheSuppliersDropDownList. WiththisadditionalListItem,theeditinginterfacecannowassignNULL valuestoaProduct's CategoryID and SupplierID fields,asshowninFigure12.
Figure12:Choose(None)toAssignaNULL ValueforaProduct'sCategoryorSupplier
Step4:UsingRadioButtonsfortheDiscontinued Status
Currentlytheproducts'Discontinued datafieldisexpressedusingaCheckBoxField,whichrendersadisabled checkboxforthereadonlyrowsandanenabledcheckboxfortherowbeingedited.Whilethisuserinterfaceis oftensuitable,wecancustomizeitifneededusingaTemplateField.Forthistutorial,let'schangethe CheckBoxFieldintoaTemplateFieldthatusesaRadioButtonListcontrolwithtwooptions"Active"and "Discontinued"fromwhichtheusercanspecifytheproduct'sDiscontinued value. StartbyconvertingtheDiscontinued CheckBoxFieldintoaTemplateField,whichwillcreateaTemplateField withanItemTemplate andEditItemTemplate.BothtemplatesincludeaCheckBoxwithitsChecked property boundtotheDiscontinued datafield,theonlydifferencebetweenthetwobeingthattheItemTemplate's CheckBox'sEnabled propertyissettofalse. ReplacetheCheckBoxinboththeItemTemplate andEditItemTemplate withaRadioButtonListcontrol,
12 of15
Figure13:Add"Active"and"Discontinued"OptionstotheRadioButtonList SincetheRadioButtonListintheItemTemplate shouldn'tbeeditable,setitsEnabled propertytofalse, leavingtheEnabled propertytotrue (thedefault)fortheRadioButtonListintheEditItemTemplate.Thiswill maketheradiobuttonsinthenoneditedrowasreadonly,butwillallowtheusertochangetheRadioButton valuesfortheeditedrow. WestillneedtoassigntheRadioButtonListcontrols'SelectedValue propertiessothattheappropriateradio buttonisselectedbasedupontheproduct'sDiscontinued datafield.AswiththeDropDownListsexamined earlierinthistutorial,thisdatabindingsyntaxcaneitherbeaddeddirectlyintothedeclarativemarkupor throughtheEditDataBindingslinkintheRadioButtonLists'smarttags. AfteraddingthetwoRadioButtonListsandconfiguringthem,theDiscontinued TemplateField'sdeclarative markupshouldlooklike:
<asp:TemplateFieldHeaderText="Discontinued"SortExpression="Discontinued"> <ItemTemplate> <asp:RadioButtonListID="DiscontinuedChoice"runat="server" Enabled="False"SelectedValue='<%#Bind("Discontinued")%>'> <asp:ListItemValue="False">Active</asp:ListItem> <asp:ListItemValue="True">Discontinued</asp:ListItem> </asp:RadioButtonList> </ItemTemplate> <EditItemTemplate> <asp:RadioButtonListID="DiscontinuedChoice"runat="server" SelectedValue='<%#Bind("Discontinued")%>'> <asp:ListItemValue="False">Active</asp:ListItem> <asp:ListItemValue="True">Discontinued</asp:ListItem> </asp:RadioButtonList>
13 of15
</EditItemTemplate> </asp:TemplateField>
Figure14:TheDiscontinuedCheckBoxesHaveBeenReplacedbyRadioButtonPairs Note:SincetheDiscontinued columnintheProducts databasecannothaveNULL values,wedonotneedto worryaboutcapturingNULL informationintheinterface.If,however,Discontinued columncouldcontain NULL valueswe'dwanttoaddathirdradiobuttontothelistwithits Value settoanemptystring(Value=""), justlikewiththecategoryandsupplierDropDownLists.
Summary
WhiletheBoundFieldandCheckBoxFieldautomaticallyrenderreadonly,editing,andinsertinginterfaces, theylacktheabilityforcustomization.Often,though,we'llneedtocustomizetheeditingorinsertinginterface, perhapsaddingvalidationcontrols(aswesawintheprecedingtutorial)orbycustomizingthedatacollection userinterface(aswesawinthistutorial).CustomizingtheinterfacewithaTemplateFieldcanbesummedupin thefollowingsteps: 1. AddaTemplateFieldorconvertanexistingBoundFieldorCheckBoxFieldintoaTemplateField 2. Augmenttheinterfaceasneeded 3. BindtheappropriatedatafieldstothenewlyaddedWebcontrolsusingtwowaydatabinding InadditiontousingthebuiltinASP.NETWebcontrols,youcanalsocustomizethetemplatesofa TemplateFieldwithcustom,compiledservercontrolsandUserControls. HappyProgramming!
14 of15
AbouttheAuthor
ScottMitchell,authorofsixASP/ASP.NETbooksandfounderof4GuysFromRolla.com,hasbeenworking withMicrosoftWebtechnologiessince1998.Scottworksasanindependentconsultant,trainer,andwriter, recentlycompletinghislatestbook, SamsTeachYourselfASP.NET2.0in24Hours.Hecanbereachedat mitchell@4guysfromrolla.comorviahisblog,whichcanbefoundathttp://ScottOnWriting.NET.
15 of15