版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第10章ADO.NET(三)10.1DataSet10.2架構(gòu)的生成10.3List<T>泛型集合10.4數(shù)據(jù)展示10.5查看電影信息
10.1DataSet
數(shù)據(jù)集(DataSet)是ADO.NET的一個(gè)重要組成部分,它是數(shù)據(jù)的脫機(jī)容器,承擔(dān)著數(shù)據(jù)的中間存儲(chǔ)工作。DataSet并不直接和數(shù)據(jù)庫(kù)連接,因此它的數(shù)據(jù)不一定來(lái)源于數(shù)據(jù)庫(kù),而是可以有很多種不同的來(lái)源,甚至可以直接從測(cè)量設(shè)備中讀取。一個(gè)DataSet是由一組數(shù)據(jù)表(DataTable)對(duì)象組成的,而每個(gè)DataTable對(duì)象又是由若干個(gè)DataColumn對(duì)象和DataRow對(duì)象組成的,如圖10-1所示。我們可以看到其結(jié)構(gòu)和數(shù)據(jù)庫(kù)中的數(shù)據(jù)表非常相似。除了定義數(shù)據(jù)外,還可以在DataSet中定義表之間的鏈接,即我們?cè)跀?shù)據(jù)庫(kù)中常用的到主/從表。DataSet及其常用對(duì)象的說(shuō)明如表10-1所示。我們可以直接通過(guò)構(gòu)造來(lái)創(chuàng)建DataSet對(duì)象:DataSetds=newDataSet();DataSetds=newDataSet("myds");上面我們分別采用DataSet的兩個(gè)構(gòu)造來(lái)創(chuàng)建對(duì)象,兩種方式?jīng)]有太大的區(qū)別,只不過(guò)第二種方式DataSet對(duì)象多了一個(gè)“myds”的別稱(chēng)而已。和數(shù)據(jù)庫(kù)一樣,DataSet對(duì)象本身并不能夠存儲(chǔ)數(shù)據(jù),真正承擔(dān)這個(gè)工作的是DataTable對(duì)象,接下來(lái)我們來(lái)了解DataTable對(duì)象。數(shù)據(jù)表(DataTable)非常類(lèi)似于SQLServer2008中的數(shù)據(jù)庫(kù)表,它是由一組包含特定屬性的列組成的,可能包含0行或多行數(shù)據(jù)。和數(shù)據(jù)庫(kù)表一樣,DataTable也可以定義由一個(gè)列或者多個(gè)列組成的主鍵,列上也可以包含約束。這些信息對(duì)應(yīng)的通用術(shù)語(yǔ)稱(chēng)為DataTable的“架構(gòu)”。整個(gè)DataTable可以訪(fǎng)問(wèn)的對(duì)象如圖10-2所示。在C#中,創(chuàng)建DataTable對(duì)象可以有兩種方式:DataTabledt1=newDataTable();DataTabledt2=newDataTable("myTab");兩種方式?jīng)]有本質(zhì)上的區(qū)別,只不過(guò)dt2對(duì)象在具體使用時(shí)會(huì)更加方便一些。當(dāng)然現(xiàn)在DataTable對(duì)象依然無(wú)法存儲(chǔ)數(shù)據(jù),因?yàn)樗€沒(méi)有結(jié)構(gòu),要設(shè)定DataTable的結(jié)構(gòu),我們需要用到DataColumn對(duì)象。
10.2架構(gòu)的生成
在A(yíng)DO.NET中,DataAdapter(數(shù)據(jù)適配器)的作用是檢索和保存數(shù)據(jù),在使用的過(guò)程中它一般都是與Connection對(duì)象和Command對(duì)象一起使用,以便連接到相應(yīng)的數(shù)據(jù)庫(kù)并完成指定的操作。另一方面,DataAdapter對(duì)象本身并不具備保存數(shù)據(jù)的能力,因此它又需要和DataSet對(duì)象配合使用,才能夠臨時(shí)存儲(chǔ)數(shù)據(jù),并提供操作數(shù)據(jù)的接口。DataAdapter無(wú)疑是ADO.NET中一個(gè)非常特殊的對(duì)象,它就像一座橋梁,一頭連接著存儲(chǔ)數(shù)據(jù)的數(shù)據(jù)庫(kù),另一頭則連接著作為臨時(shí)數(shù)據(jù)存儲(chǔ)對(duì)象的DataSet。它能夠根據(jù)SQL語(yǔ)句從數(shù)據(jù)庫(kù)中提取數(shù)據(jù),也能夠?qū)⒏暮蟮臄?shù)據(jù)更新到數(shù)據(jù)庫(kù)中。DataAdapter對(duì)象屬于.NETFramework數(shù)據(jù)提供程序,不同的數(shù)據(jù)提供程序有自己的DataAdapter對(duì)象,用于OLEDB的是OleDbDataAdapter對(duì)象,而用于SQLServer的是SqlDataAdapter對(duì)象,這里我們以SqlDataAdapter對(duì)象為例來(lái)認(rèn)識(shí)DataAdapter對(duì)象。我們可通過(guò)四種方式來(lái)創(chuàng)建SqlDataAdapter對(duì)象,如表10-4所示。一般來(lái)說(shuō)第三種方式使用得比較多:stringconn=ConfigurationManager.ConnectionStrings["SQL"].ConnectionString;SqlConnectioncn=newSqlConnection(conn);stringsql="select*fromFilm";SqlDataAdapterda=newSqlDataAdapter(sql,cn);在上面的代碼中我們首先還是要?jiǎng)?chuàng)建一個(gè)SqlConnection對(duì)象,因?yàn)樵贏(yíng)DO.NET中一切操作都是以連接為基礎(chǔ),然后創(chuàng)建一個(gè)SqlDataReader對(duì)象,并且將一個(gè)Select查詢(xún)語(yǔ)句和已經(jīng)創(chuàng)建好的SqlConnection對(duì)象作為參數(shù)傳遞到它的構(gòu)造函數(shù)中。創(chuàng)建了SqlDataAdapter對(duì)象后,我們就可以使用其提供的屬性和方法來(lái)完成需要的操作。我們常用到的方法有兩個(gè):Fill():使用SELECT語(yǔ)句從數(shù)據(jù)源中檢索數(shù)據(jù)。Update():使用SQL語(yǔ)句將數(shù)據(jù)集中的數(shù)據(jù)更新到數(shù)據(jù)源。當(dāng)我們需要從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)時(shí),可以使用Fill()方法,這時(shí)與Select命令關(guān)聯(lián)的SqlConnection對(duì)象必須有效,但不需要將其打開(kāi)。如果調(diào)用Fill()方法之前SqlConnection已關(guān)閉,則將其打開(kāi)以檢索數(shù)據(jù),然后再將其關(guān)閉。如果調(diào)用Fill()方法之前連接已打開(kāi),則它將保持打開(kāi)狀態(tài):stringsql="select*from[User]";SqlDataAdapterda=newSqlDataAdapter(sql,cn);DataSetds=newDataSet();da.Fill(ds);在上面的代碼中我們創(chuàng)建了一個(gè)SqlDataAdapter對(duì)象,并且通過(guò)一條查詢(xún)語(yǔ)句從數(shù)據(jù)庫(kù)中查詢(xún)數(shù)據(jù),然后將結(jié)果使用Fill()方法填充到一個(gè)數(shù)據(jù)集對(duì)象中。如果在填充數(shù)據(jù)時(shí)遇到錯(cuò)誤或異常,則錯(cuò)誤發(fā)生之前添加的行將保留在數(shù)據(jù)集中,操作的剩余部分被中止。如果命令不返回任何行,則不向數(shù)據(jù)集中添加表,也不引發(fā)異常。在實(shí)際應(yīng)用中,DataAdapter對(duì)象多用于查詢(xún)類(lèi)型的操作,雖然它也具有其他類(lèi)型數(shù)據(jù)操作的能力,但是由于其本身缺乏對(duì)數(shù)據(jù)完整性的驗(yàn)證能力,因此其他類(lèi)型的操作我們多是借助于Command對(duì)象來(lái)完成的。在大部分程序中,數(shù)據(jù)集在使用的時(shí)候都是通過(guò)DataAdapter對(duì)象來(lái)填充的。通過(guò)DataAdapter對(duì)象的Fill()方法,我們可以將數(shù)據(jù)源中的數(shù)據(jù)一次性地填充到數(shù)據(jù)集中,這個(gè)時(shí)候數(shù)據(jù)集的結(jié)構(gòu)和內(nèi)容都由系統(tǒng)幫助我們自動(dòng)生成。填充數(shù)據(jù)集有多種不同的方式,最直接的方式是不做任何設(shè)定,一切由系統(tǒng)來(lái)決定:stringconn=ConfigurationManager.ConnectionStrings["SQL"].ConnectionString;SqlConnectioncn=newSqlConnection(conn);stringsql="select*fromFilm";SqlDataAdapterda=newSqlDataAdapter(sql,cn);DataSetds=newDataSet();da.Fill(ds);上面的代碼我們沒(méi)有做任何其他的設(shè)置,僅僅是連接數(shù)據(jù)庫(kù)后讀取Film數(shù)據(jù)表中的所有數(shù)據(jù),然后通過(guò)DataAdapter對(duì)象的Fill()方法將讀取的數(shù)據(jù)填充到一個(gè)數(shù)據(jù)集中。因?yàn)槲覀冎惶峁┝艘恍?duì)象,所以這個(gè)時(shí)候數(shù)據(jù)集中將由系統(tǒng)自動(dòng)創(chuàng)建一個(gè)名為“Table”的DataTable對(duì)象,而它的結(jié)構(gòu)則由我們的查詢(xún)語(yǔ)句來(lái)決定。例如,我們這里是查詢(xún)Film表中的所有信息,因此“Table”表的字段就是數(shù)據(jù)庫(kù)中Film數(shù)據(jù)表的所有字段,而“Table”表的數(shù)據(jù)則和Film數(shù)據(jù)表的數(shù)據(jù)一樣。后續(xù)我們使用這個(gè)數(shù)據(jù)集的時(shí)候就只能這樣訪(fǎng)問(wèn)DataTable:ds.Table["Table"]或者通過(guò)索引訪(fǎng)問(wèn):ds.Table[0]很顯然,上面的代碼雖然能夠完成任務(wù),但是不確定和不安全的地方太多了,因此我們還需要將程序?qū)懙酶訙?zhǔn)確些:SqlDataAdapterda=newSqlDataAdapter(sql,cn);da.Fill(ds,"MyFilm");這一次我們將程序做了一點(diǎn)微調(diào),在調(diào)用DataAdapter對(duì)象的Fill()方法時(shí),我們不但傳遞了數(shù)據(jù)集對(duì)象,同時(shí)還給了第二個(gè)字符串類(lèi)型的參數(shù)“MyFilm”,這個(gè)參數(shù)的作用是在進(jìn)行數(shù)據(jù)填充的時(shí)候,將系統(tǒng)自動(dòng)創(chuàng)建的DataTable對(duì)象命名為“MyFilm”,這樣在后續(xù)使用時(shí)就可以這樣寫(xiě):ds.Table["MyFilm"]相對(duì)第一段代碼,這次的程序顯得更加精確,但是依然存在問(wèn)題,主要是訪(fǎng)問(wèn)起來(lái)比較麻煩,每次都要通過(guò)數(shù)據(jù)集定位到DataTable,然后才能夠訪(fǎng)問(wèn)行和列,因此我們可以將程序再次進(jìn)行修改:SqlDataAdapterda=newSqlDataAdapter(sql,cn);DataTabledt=newDataTable();da.Fill(dt);這次程序中找不到DataSet對(duì)象了,取而代之的是一個(gè)DataTable對(duì)象,這也是我們?cè)趯?shí)際開(kāi)發(fā)中經(jīng)常會(huì)用到的一種方式,道理很簡(jiǎn)單,既然數(shù)據(jù)集的數(shù)據(jù)是存放在DataTable對(duì)象中的,那我們就可以繞過(guò)數(shù)據(jù)集而直接使用DataTable對(duì)象來(lái)操作數(shù)據(jù),當(dāng)然這樣一來(lái)我們就無(wú)法再通過(guò)數(shù)據(jù)集來(lái)管理DataTable之間的關(guān)系了。三種數(shù)據(jù)集填充方式在實(shí)際使用的過(guò)程中沒(méi)有太大的區(qū)別,具體采用哪種方式還是要根據(jù)實(shí)際開(kāi)發(fā)的情況以及個(gè)人的使用習(xí)慣來(lái)定。
10.3List<T>泛型集合
10.3.1List定義集合的具體介紹詳見(jiàn)C#高級(jí)編程的有關(guān)教材,下面要介紹的是集合中用得非常廣泛的一種:List<T>。我們首先來(lái)看一下它的語(yǔ)法:List<T>list=newList<T>();這是一個(gè)泛型集合類(lèi),重點(diǎn)在于它里面的類(lèi)型參數(shù):T。T本身沒(méi)有具體含義,它只是類(lèi)似于占位符一般的存在。它可以是任何類(lèi),如果你想創(chuàng)建一個(gè)User實(shí)體對(duì)象的集合,那么,將T改成User就行了。在實(shí)際運(yùn)用中,語(yǔ)法如下:List<User>list=newList<User>();10.3.2數(shù)據(jù)讀取光有對(duì)象是不夠的,List的作用是獲取數(shù)據(jù)庫(kù)中的數(shù)據(jù),作為數(shù)據(jù)源來(lái)使用。但是如何將數(shù)據(jù)表中的數(shù)據(jù)放到List對(duì)象中呢?下面的代碼是整個(gè)過(guò)程。首先,創(chuàng)建表的實(shí)體類(lèi),我們要將用戶(hù)表(User)的數(shù)據(jù)讀取出來(lái),先創(chuàng)建User類(lèi):publicclassUser{//屬性定義publicintID{get;set;}publicstringName{get;set;}publicstringUserName{get;set;}publicintTypeID{get;set;}publicstringTypeName{get;set;}publicstringDesc{get;set;}publicintState{get;set;}}接下來(lái),使用SqlDataReader對(duì)象讀取數(shù)據(jù):stringconStr="server=.;initialcatalog=MyFilm;integratedsecurity=SSPI;";stringsql="select*fromUser";SqlConnectionconn=newSqlConnection(conStr);conn.Open();SqlCommandcm=newSqlCommand(sql,conn);SqlDataReaderdr=cm.ExecuteReader();List<User>modelList=newList<User>(); //創(chuàng)建List泛型集合對(duì)象Usermodel=null; //在循環(huán)外部創(chuàng)建User對(duì)象,但不用實(shí)例化while(dr.Read()){model=newUser(); //每一次循環(huán)讀取數(shù)據(jù)時(shí),實(shí)例化該對(duì)象model.ID=int.Parse(dr["ID"].ToString()); //將當(dāng)前行的ID字段數(shù)據(jù)賦值給對(duì)象ID屬性model.Name=dr["Name"].ToString();model.UserName=dr["Name"].ToString();model.TypeID=int.Parse(dr["TypeID"].ToString());model.TypeName=dr["Name"].ToString();model.Desc=dr["Name"].ToString();model.State=int.Parse(dr["State"].ToString());modelList.Add(model); //最后一定要記得將實(shí)體對(duì)象添加到集合中}dr.Close(); //一定要記得在讀取完數(shù)據(jù)后關(guān)掉閱讀器conn.Close();當(dāng)執(zhí)行完上述操作后,這個(gè)集合中就獲得了查詢(xún)語(yǔ)句所查詢(xún)出來(lái)的所有數(shù)據(jù)了。
10.4數(shù)據(jù)展示
10.4.1簡(jiǎn)單控件對(duì)于DataSet來(lái)說(shuō),最直接的操作就是用簡(jiǎn)單控件來(lái)顯示其中的數(shù)據(jù),當(dāng)然在這之前我們要知道如何讀取它的值。最常見(jiàn)的就是讀取DataSet中數(shù)據(jù)表的某行或者某列的值,甚至可能會(huì)精確到某一個(gè)單元格的值。例如,用戶(hù)希望查看數(shù)據(jù)表中第二部電影的信息,那么我們的程序就可以這樣寫(xiě):stringname=(string)ds.Tables["Film"].Rows[1]["Name"];stringaddedBy=(string)ds.Tables["Film"].Rows[1]["AddedBy"];stringactor=(string)ds.Tables["Film"].Rows[1]["Actors"];stringdesc=(string)ds.Tables["Film"].Rows[1]["Desc"];MessageBox.Show("影片"+name+"是由"+actor+"主演!\ny影片簡(jiǎn)介:"+desc);上面的代碼可以訪(fǎng)問(wèn)表中的一行數(shù)據(jù),如果需要訪(fǎng)問(wèn)表中所有行的數(shù)據(jù),則需要再增加一個(gè)循環(huán)結(jié)構(gòu):foreach(DataRowdrinds.Tables["myTab"].Rows){//讀取數(shù)據(jù)}事實(shí)上,如果是這種逐行讀取數(shù)據(jù)的操作則DataReader對(duì)象是更加合適的對(duì)象,因?yàn)樗牡南到y(tǒng)資源更少,速度也更快一些。DataSet的主要用途在于更全面地展示數(shù)據(jù)。知道了如何讀取數(shù)據(jù)后,接下來(lái)使用簡(jiǎn)單控件呈現(xiàn)數(shù)據(jù)的工作就很簡(jiǎn)單了:txtName.Text=(string)ds.Tables["Film"].Rows[0]["Name"];txtActors.Text=(string)ds.Tables["Film"].Rows[0]["Actors"];txtPrice.Text=ds.Tables["Film"].Rows[0]["Price"].ToString();txtDesc.Text=(string)ds.Tables["Film"].Rows[0]["Desc"];上面的代碼依然是從數(shù)據(jù)集中讀取數(shù)據(jù),只不過(guò)讀取的數(shù)據(jù)不再使用變量,而是直接使用三個(gè)TextBox控件和一個(gè)RichTextBox控件來(lái)呈現(xiàn)數(shù)據(jù)。只不過(guò)這種方式只能夠讀取一行數(shù)據(jù),如果需要一次性展示更多的信息則還需要借助于其他的控件。我們?cè)肈ataSet來(lái)讀取數(shù)據(jù),那么List<T>是怎么讀取數(shù)據(jù)的呢?同樣的案例,我們用泛型集合來(lái)演示一次。假設(shè)讀取數(shù)據(jù)的泛型集合類(lèi)為L(zhǎng)ist<Film>,對(duì)象名稱(chēng)為modelList,同樣讀取第二行數(shù)據(jù):stringname=modelList[1].Name;stringaddedBy=modelList[1].AddedBy;其余的值依此類(lèi)推,可見(jiàn)相比較DataSet來(lái)講,List<Film>要簡(jiǎn)單方便。想要讀取所有的數(shù)據(jù),也可以用循環(huán)遍歷來(lái)實(shí)現(xiàn):foreach(FilmmodelinmodelList){//依上例讀取數(shù)據(jù)stringname=model.Name;…}控件的數(shù)據(jù)讀取依上例所示即可。10.4.2列表控件列表類(lèi)型的控件是系統(tǒng)開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)用到的控件,在之前我們用到這類(lèi)控件的時(shí)候,其選擇項(xiàng)大多是直接設(shè)定好的固定內(nèi)容,是否可以讓它們從數(shù)據(jù)集中動(dòng)態(tài)地獲取選擇內(nèi)容呢?要實(shí)現(xiàn)這個(gè)操作本身并不復(fù)雜,我們知道列表類(lèi)型的控件其選擇項(xiàng)都是在Items屬性中保存的,因此只要能夠?qū)?shù)據(jù)集中的數(shù)據(jù)“放置”到Items屬性中就可以了。問(wèn)題在于Items屬性中的每一個(gè)選擇項(xiàng)都是由Text和Value這兩個(gè)值構(gòu)成的,因此我們要做的工作就是將數(shù)據(jù)表的列和這兩個(gè)值對(duì)應(yīng)起來(lái):comboBox1.DropDownStyle=ComboBoxStyle.DropDownList;comboBox1.DisplayMember="Name";comboBox1.ValueMember="ID";comboBox1.DataSource=ds.Tables["Film"];在上面的代碼中我們?cè)O(shè)定了ComboBox控件的四個(gè)屬性。DropDownStyle屬性用來(lái)設(shè)定其顯示方式,我們?cè)O(shè)定為ComboBoxStyle.DropDownList,這樣該組合框控件就只能夠選擇而不能夠輸入信息。DisplayMember屬性用來(lái)設(shè)定每一個(gè)Item選擇項(xiàng)的Text屬性所對(duì)應(yīng)的列名,這個(gè)列名必須是數(shù)據(jù)表中存在的列。ValueMember屬性則是用來(lái)設(shè)定每一個(gè)Item選擇項(xiàng)的Value屬性所對(duì)應(yīng)的列名,同樣該列必須是數(shù)據(jù)表中存在的列,如果在程序中沒(méi)有設(shè)定ValueMember屬性,則Item選擇項(xiàng)的Value屬性值就會(huì)和Text屬性值相同。最后我們?cè)O(shè)定了組合框控件的DataSource屬性,也就是數(shù)據(jù)源屬性,這樣系統(tǒng)就會(huì)自動(dòng)在DataSource所指定的數(shù)據(jù)源中查找相應(yīng)的列,并將這些列的值一次性填充到組合框中,從而形成選擇項(xiàng)。同樣,上例也用的是DataSet數(shù)據(jù)源,如果是List集合,則只需要把最后一句代碼的數(shù)據(jù)源替換即可:comboBox1.DataSource=modelList; //記住,這里的值為整個(gè)泛型集合對(duì)象從這里開(kāi)始,后面的數(shù)據(jù)源將直接使用泛型集合,而不再使用DataSet了。如何知道用戶(hù)所選擇的內(nèi)容呢?這里我們可以通過(guò)兩個(gè)簡(jiǎn)單的屬性取得用戶(hù)選擇的信息:intid=(int)comboBox1.SelectedValue;stringname=comboBox1.Text;MessageBox.Show("電影《"+name+"》的編號(hào)是:"+id);組合框的SelectedValue屬性可以取得用戶(hù)選擇項(xiàng)的Value屬性值,而Text屬性則可以取得用戶(hù)選擇項(xiàng)的Text屬性的值。這里很容易產(chǎn)生一個(gè)疑問(wèn):為什么一個(gè)選擇項(xiàng)要設(shè)定Text和Value這兩個(gè)屬性值?這是因?yàn)樵趯?shí)際使用中,難免會(huì)出現(xiàn)重復(fù)的數(shù)據(jù)。例如,如果數(shù)據(jù)庫(kù)中存在兩部同名的電影,那么我們?nèi)绾沃烙脩?hù)選擇的究竟是哪一部電影呢?很顯然單憑Text屬性根本無(wú)法做判斷,這時(shí)候如果我們?cè)赩alue屬性中保存了電影的編號(hào),那么就可以很容易地知道用戶(hù)的選擇。因?yàn)橹暗臄?shù)據(jù)是通過(guò)屬性綁定到控件的,我們通過(guò)上面的內(nèi)容可以得到顯示和隱藏的值,但實(shí)際上我們可以通過(guò)它的SelectedItem屬性得到當(dāng)前選定項(xiàng)所綁定的整個(gè)對(duì)象:Filmmodel=(Film)comboBox1.SelectedItem;MessageBox.Show("電影《"+model.Name+"》的編號(hào)是:"+model.Id);如果是多選我們?cè)撊绾尾僮髂???duì)于像ListBox這樣的多選類(lèi)型的控件,其數(shù)據(jù)顯示部分的操作和ComboBox控件一樣,也就是說(shuō)我們將前面代碼中的ComboBox換成ListBox控件就可以了:listBox1.SelectionMode=SelectionMode.MultiExtended;listBox1.DisplayMember="Name";listBox1.ValueMember="ID";listBox1.DataSource=modelList;相對(duì)于ComboBox控件ListBox控件的讀取相對(duì)來(lái)說(shuō)復(fù)雜一些,根據(jù)DataSource所設(shè)定的數(shù)據(jù)源類(lèi)型不同,其讀取方式也會(huì)有一些細(xì)微的差別,其讀取方式為stringstr="選中的電影:";for(inti=0;i<listBox1.SelectedItems.Count;i++){Filmmodel=(Film)listBox1.SelectedItems[i];str+="\n電影名稱(chēng):"+model.Name; //如果能讀取到Name,則其他的屬性也能夠得到}MessageBox.Show(str);上面代碼的運(yùn)行效果如圖10-5所示。10.4.3DataGridView列表類(lèi)型的控件在使用的時(shí)候雖然能夠一次性呈現(xiàn)很多行數(shù)據(jù)的信息,但是只能夠顯示數(shù)據(jù)表中的某一列,如果要呈現(xiàn)數(shù)據(jù)的全貌,還是要借助于更加大型的控件,這其中最常用的就是DataGridView。DataGridView控件是WinForm中經(jīng)常使用到的一個(gè)用于呈現(xiàn)數(shù)據(jù)的大型控件,它能夠以表格的形式將數(shù)據(jù)集中的數(shù)據(jù)表完整地呈現(xiàn)出來(lái),同時(shí)還支持根據(jù)用戶(hù)的需要進(jìn)行各種不同的設(shè)置。使用DataGridView控件時(shí),可以在工具箱的“數(shù)據(jù)”選項(xiàng)卡中找到它并將其放置到窗體中,如圖10-6所示。將DataGridView控件添加到窗體上后,我們只需要一行代碼就可以將剛才創(chuàng)建的泛型集合在該控件上呈現(xiàn)出來(lái):dataGridView1.DataSource=modelList;DataGridView控件可以以表格的形式將數(shù)據(jù)集中的數(shù)據(jù)呈現(xiàn)出來(lái),該控件在使用的時(shí)候最重要的屬性就是DataSource屬性,它主要用來(lái)設(shè)置DataGridView控件數(shù)據(jù)源,在上面的代碼中我們就將電影信息讀取出來(lái)后放置在DataSet對(duì)象中并作為數(shù)據(jù)源賦給了該屬性。其運(yùn)行效果如圖10-7所示。當(dāng)然,數(shù)據(jù)是出來(lái)了,但是和實(shí)際使用差別太大了,根本就不具備可用性。首先,我們并不需要將所有的字段都展示出來(lái),像ID這樣的字段根本就不需要用戶(hù)知道它的存在。其次,列名用英文并沒(méi)有問(wèn)題,但是這里卻使用的是字段名稱(chēng),從而將我們的數(shù)據(jù)結(jié)構(gòu)暴露了出來(lái),這樣甚至?xí){到整個(gè)系統(tǒng)的安全。事實(shí)上,上面的問(wèn)題總結(jié)起來(lái)就是一點(diǎn),即需要DataGridView控件按照我們?cè)O(shè)定的方式顯示數(shù)據(jù),這就要設(shè)置DataGridView控件列,我們可以打開(kāi)DataGridView控件的智能選項(xiàng)卡,然后點(diǎn)擊“編輯列”來(lái)完成。也可以在DataGridView控件的屬性列表中來(lái)完成。無(wú)論采用哪種方式,我們都可以打開(kāi)DataGridView控件的列編輯器,如圖10-10所示。在列編輯器的左側(cè)是一個(gè)列表框,這里列出了當(dāng)前DataGridView控件中已經(jīng)添加的列對(duì)象,我們可以看到這里有四個(gè)列。選中某一個(gè)列后,在窗體的右側(cè)可以看到一個(gè)屬性列表,這當(dāng)中列出了當(dāng)前選中列對(duì)象的一些常用屬性。在這些屬性中,常用的有以下幾個(gè):Name:列對(duì)象的名稱(chēng),在程序中必須保證唯一。在命名時(shí)一般采用col作為前綴,例如colName。ColumnType:類(lèi)對(duì)象的類(lèi)型。WinForm中DataGridView控件的列共有六種類(lèi)型:按鈕列樣式(DataGridViewButtonColumn)、復(fù)選框列樣式(DataGridViewCheckBoxColumn)、組合框列樣式(DataGridViewComboBoxColumn)、圖片列樣式(DataGridViewImageColumn)、鏈接列樣式(DataGridViewLinkColumn)和文本框列樣式(DataGridTextBoxColumn,默認(rèn)樣式)。不同的列樣式會(huì)呈現(xiàn)出不同的外觀(guān),同時(shí)使用方式也有細(xì)微的差別。DataPropertyName:設(shè)置列對(duì)象所對(duì)應(yīng)的數(shù)據(jù)源字段名稱(chēng)。HeaderText:設(shè)置列對(duì)象的頁(yè)眉文本。不同的列樣式對(duì)應(yīng)著不同的使用環(huán)境,具體需要采用什么樣式還要根據(jù)實(shí)際情況來(lái)決定,一般情況下如果不能確定則都可以采用文本框樣式來(lái)呈現(xiàn)數(shù)據(jù),因?yàn)樗旧峡梢燥@示任何類(lèi)型的數(shù)據(jù)。如果要添加新的列對(duì)象,則點(diǎn)擊左側(cè)列表框下的“添加”按鈕,這樣就可以打開(kāi)添加列窗體。在這個(gè)窗體上,我們可以設(shè)置三個(gè)值?!懊Q(chēng)(N):”用來(lái)指定新添加列對(duì)象的Name屬性值?!邦?lèi)型(T):”下拉列表中可以選擇新添加列對(duì)象的樣式,也就是ColumnType屬性值?!绊?yè)眉文本(H):”則是用來(lái)設(shè)定新添加列的HeaderText屬性值。需要注意的是,這里并沒(méi)有設(shè)置DataPropertyName屬性值,因此在完成列的添加后還需要在圖10-10中找到新添加的列并設(shè)置DataPropertyName屬性,否則是無(wú)法使用的。列設(shè)置完成再次運(yùn)行我們的程序,會(huì)發(fā)現(xiàn)凡是數(shù)據(jù)表我們?cè)O(shè)置過(guò)的字段都按要求在DataGridView控件的指定列當(dāng)中呈現(xiàn)出來(lái)了,但是我們沒(méi)有設(shè)置的字段卻依然按照先前的樣式顯示在DataGridView控件中,如圖10-12所示。這是因?yàn)槟J(rèn)情況下DataGridView控件會(huì)自動(dòng)根據(jù)數(shù)據(jù)源中的表結(jié)構(gòu)來(lái)創(chuàng)建相應(yīng)的列,也就是說(shuō)數(shù)據(jù)表中有多少個(gè)字段,DataGridView控件就會(huì)自動(dòng)創(chuàng)建多少個(gè)列,并顯示數(shù)據(jù),而我們這里卻只需要它顯示我們?cè)O(shè)置的列,其他的列就不需要再自動(dòng)創(chuàng)建了。要實(shí)現(xiàn)這一效果我們可以通過(guò)下面的代碼來(lái)實(shí)現(xiàn):dgdShowData.AutoGenerateColumns=false;AutoGenerateColumns屬性的作用是用來(lái)設(shè)置DataGridView控件是否需要根據(jù)數(shù)據(jù)源來(lái)自動(dòng)創(chuàng)建列,將其設(shè)置為false后系統(tǒng)就不會(huì)再自動(dòng)創(chuàng)建列,而只會(huì)根據(jù)我們?cè)O(shè)置的列來(lái)呈現(xiàn)數(shù)據(jù),如圖10-13所示。DataGridView是WinForm中最為復(fù)雜的大型控件之一,本章我們只是介紹了DataGridView控件的基本使用方式。10.4.4ListViewListView控件是另外一個(gè)數(shù)據(jù)展示控件,和DataGridView控件不同,ListView控件只是提供數(shù)據(jù)的顯示功能而并不提供對(duì)數(shù)據(jù)的操作功能,但是其顯示方式要比DataGridView控件豐富。下面我們同樣使用ListView控件來(lái)顯示電影信息。在工具箱中找到ListView控件并放置到窗體上,如圖10-14所示。和其他控件一樣,ListView控件也有很多屬性,限于篇幅我們不可能一次性將所有的屬性及其使用方式講解完畢,因此本章我們還是圍繞著數(shù)據(jù)呈現(xiàn)來(lái)學(xué)習(xí)相關(guān)的屬性。為了能夠完成這個(gè)任務(wù),我們會(huì)用到ListView控件的以下屬性:Name:ListView控件的名稱(chēng),在代碼中必須唯一。在命名的時(shí)候一般采用lsv作為前綴。Columns:設(shè)置ListView控件的列。FullRowSelect:指示是否可以一次性選擇整行數(shù)據(jù)。GridLines:指示ListView在顯示數(shù)據(jù)的時(shí)候是否顯示網(wǎng)格線(xiàn)。View:設(shè)置ListView的顯示方式。ListView控件中提供了五種不同的顯示方式,如表10-6所示。使用ListView控件顯示數(shù)據(jù)要比使用DataGridView控件復(fù)雜一些。首先我們需要設(shè)置ListView控件的Columns屬性,也就是設(shè)置數(shù)據(jù)顯示的列。在ListView控件的屬性窗口的行為部分找到Columns屬性。點(diǎn)擊右側(cè)的按鈕后打開(kāi)ColumnHeader集合編輯器窗體。在窗體的左側(cè)“成員(M):”之下我們可以看到現(xiàn)在Columns屬性所有已經(jīng)存在的列成員。在成員列表的右側(cè)有上下兩個(gè)按鈕,選中某列后點(diǎn)擊向上或向下的按鈕就可以調(diào)整該列的排列順序,這個(gè)排列順序決定了最終數(shù)據(jù)顯示的時(shí)候該列的位置。如果未添加任何列,則該列表為空。點(diǎn)擊成員列表下方的“添加(A)”按鈕就可以添加一個(gè)新的列。在成員列表中選中某一列后,在窗體的右側(cè)可以看到當(dāng)前選中列對(duì)象的相關(guān)屬性,在這些屬性中我們需要關(guān)注的是Name和Text。Name屬性是當(dāng)前選中列對(duì)象的名稱(chēng),由于在實(shí)際操作過(guò)程中訪(fǎng)問(wèn)這些列對(duì)象時(shí)我們都采用的是下標(biāo)訪(fǎng)問(wèn),因此這里可以采用系統(tǒng)自動(dòng)生成的名字,如果要命名,可以采用col作為前綴。Text屬性則是用來(lái)設(shè)定列對(duì)象的頁(yè)眉,也就是呈現(xiàn)在ListView控件中列標(biāo)頭的文本。設(shè)定完成后,點(diǎn)擊“確定”按鈕后關(guān)閉ColumnHeader集合編輯器窗體,接下來(lái)需要完成具體的數(shù)據(jù)顯示工作。首先依然還是要將數(shù)據(jù)從數(shù)據(jù)庫(kù)中讀取出來(lái),這個(gè)過(guò)程我們可以使用DataAdapter對(duì)象與DataSet對(duì)象配合起來(lái)實(shí)現(xiàn),因?yàn)榍懊嫖覀円呀?jīng)進(jìn)行了講解,這里就不再重復(fù)說(shuō)明。由于ListView控件沒(méi)有DataGridView控件那樣的自動(dòng)數(shù)據(jù)填充功能,因此我們需要將數(shù)據(jù)集中的數(shù)據(jù)提取出來(lái),然后放入ListView控件中的相應(yīng)位置:foreach(FilmmodelinmodelList){ListViewItemitem=newListViewItem();item.SubItems[0].Text=model.Name;item.SubItems.Add(model.Actors);item.SubItems.Add(string.Format("{0:C}",model.Price));lsvShowData.Items.Add(item);}在上面的代碼中,我們首先通過(guò)一個(gè)foreach循環(huán)結(jié)構(gòu)遍歷數(shù)據(jù)集合的所有行,在循環(huán)結(jié)構(gòu)體中我們需要?jiǎng)?chuàng)建一個(gè)ListViewItem對(duì)象,該對(duì)象代表ListView控件的Items屬性中的一個(gè)成員。接下來(lái),我們就可以通過(guò)這個(gè)ListViewItem對(duì)象的SubItems屬性將數(shù)據(jù)行中的數(shù)據(jù)放置到該對(duì)象中。ListViewItem對(duì)象每調(diào)用一次Add()方法就可以向其中添加一個(gè)新的單元格,唯一需要注意的是其第一個(gè)單元格需要通過(guò)下標(biāo)訪(fǎng)問(wèn),因?yàn)樵趧?chuàng)建該對(duì)象的時(shí)候系統(tǒng)會(huì)默認(rèn)添加一個(gè)單元格。無(wú)論是設(shè)置哪一個(gè)單元格,傳遞的值都需要是字符串類(lèi)型的。那么,ListViewItem對(duì)象又是怎么和ListView控件的列建立起關(guān)聯(lián)的呢?事實(shí)上,這個(gè)過(guò)程并不復(fù)雜,在最終將ListViewItem對(duì)象通過(guò)Add()方法添加到ListView控件的Items屬性中的時(shí)候,系統(tǒng)會(huì)按順序?qū)istViewItem對(duì)象的單元格和ListView控件的列對(duì)應(yīng)起來(lái),也就是將ListViewItem對(duì)象第一個(gè)單元格的值放置到ListView控件的第一個(gè)列中,第二個(gè)單元格則放置到第二個(gè)列中,以此類(lèi)推。正因?yàn)槭沁@樣一個(gè)操作過(guò)程,所以我們?cè)跒長(zhǎng)istViewItem對(duì)象添加單元格的時(shí)候一定要對(duì)ListView控件的列組成牢記在心,否則就會(huì)出現(xiàn)數(shù)據(jù)放置錯(cuò)誤。另外,如果ListViewItem對(duì)象的單元格數(shù)量多于ListView控件的列數(shù)量,則多出來(lái)的數(shù)據(jù)就會(huì)被系統(tǒng)舍棄。上面的代碼中另外一個(gè)需要我們注意的地方是,在添加價(jià)格的時(shí)候我們并沒(méi)有直接將其轉(zhuǎn)換成為字符串,而是通過(guò)string類(lèi)的Format()方法將其轉(zhuǎn)換成了貨幣的格式。Format()方法的作用是將指定的值按照要求轉(zhuǎn)換成為特定的格式。一般在使用該方法時(shí)我們需要提供兩個(gè)參數(shù):第一個(gè)為字符串類(lèi)型,用來(lái)設(shè)定轉(zhuǎn)換的格式;第二個(gè)則是需要轉(zhuǎn)換的數(shù)據(jù)或數(shù)據(jù)集合。每個(gè)格式項(xiàng)都采用下面的形式并包含以下組件:{索引[,對(duì)齊][:格式字符串]}“索引”(也叫參數(shù)說(shuō)明符)是一個(gè)從0開(kāi)始的數(shù)字,用來(lái)標(biāo)識(shí)需要轉(zhuǎn)換的數(shù)據(jù)對(duì)象。也就是說(shuō),當(dāng)索引為0時(shí),其對(duì)應(yīng)需要轉(zhuǎn)換的第一個(gè)數(shù)據(jù)對(duì)象,如果索引為1,則對(duì)應(yīng)第二個(gè)數(shù)據(jù)對(duì)象,依次類(lèi)推,我們可以把它理解成為占位符。通過(guò)指定相同的索引,多個(gè)格式項(xiàng)可以引用轉(zhuǎn)換數(shù)據(jù)對(duì)象列表中的同一個(gè)元素。每個(gè)索引都可以引用要轉(zhuǎn)換數(shù)據(jù)對(duì)象列表中的任一對(duì)象。例如,如果有三個(gè)要轉(zhuǎn)換的數(shù)據(jù)對(duì)象,則可以通過(guò)指定類(lèi)似于“{1}{0}{2}”的復(fù)合格式字符串來(lái)設(shè)置第二、第一和第三個(gè)對(duì)象的格式。格式項(xiàng)未引用的對(duì)象會(huì)被忽略。如果索引指定了超出數(shù)據(jù)對(duì)象列表范圍的項(xiàng),將導(dǎo)致運(yùn)行時(shí)異常:txtFormat.Text=string.Format("貨幣:{0:C};百分比:{1:P};十六進(jìn)制:{0:X}",12,0.35);上面的代碼分別將數(shù)字12轉(zhuǎn)換成為貨幣格式和十六進(jìn)制數(shù),而將0.35轉(zhuǎn)換成為百分比?!皩?duì)齊”是可選的一個(gè)帶符號(hào)的整數(shù),指示設(shè)置了格式的字段寬度。如果“對(duì)齊”值小于設(shè)置了格式的字符串的長(zhǎng)度,則“對(duì)齊”會(huì)被忽略,并且使用設(shè)置了格式的字符串的長(zhǎng)度作為字段寬度。如果“對(duì)齊”為正數(shù),則字段中設(shè)置了格式的數(shù)據(jù)為右對(duì)齊;如果“對(duì)齊”為負(fù)數(shù),則字段中設(shè)置了格式的數(shù)據(jù)為左對(duì)齊。如果需要填充,則使用空白。如果指定“對(duì)齊”,就需要使用逗號(hào):txtFormat.Text=string.Format("右對(duì)齊:[{0,10}];左對(duì)齊:[{0,-10}];對(duì)齊失效:[{0,2}]","Tom");同樣是將Tom進(jìn)行格式化,當(dāng)我們使用“{0,10}”這種格式的時(shí)候,轉(zhuǎn)換的結(jié)果就是在Tom的前面增加7個(gè)空格以補(bǔ)齊10位長(zhǎng)度,而使用“{0,-10}”時(shí),則會(huì)在其后面添加7個(gè)空格以補(bǔ)齊10位長(zhǎng)度。但是在“{0,2}”中,對(duì)齊的數(shù)值小于“Tom”的長(zhǎng)度,因此“對(duì)齊”就失效了。格式字符串則是用來(lái)設(shè)定需要設(shè)定的轉(zhuǎn)換格式,表10-7列出了常用的格式字符串。10.4.5TreeView在WinForm中TreeView控件用樹(shù)的方式展示層次節(jié)點(diǎn),通過(guò)這些節(jié)點(diǎn),我們可以清晰地查看數(shù)據(jù)及其它們之間的從屬關(guān)系。傳統(tǒng)上,節(jié)點(diǎn)對(duì)象包含值,可以引用其他節(jié)點(diǎn),一個(gè)節(jié)點(diǎn)可以包含其他節(jié)點(diǎn),這時(shí)該節(jié)點(diǎn)稱(chēng)為父節(jié)點(diǎn),它所包含的節(jié)點(diǎn)稱(chēng)為子節(jié)點(diǎn)。只有子節(jié)點(diǎn)沒(méi)有父節(jié)點(diǎn)的節(jié)點(diǎn)稱(chēng)為根節(jié)點(diǎn),在WinForm中TreeView控件可以包含多個(gè)根節(jié)點(diǎn),如圖10-21所示。作為所有節(jié)點(diǎn)的管理者,TreeView控件本身的常用屬性并不多,如表10-8所示。TreeNode是TreeView控件的重要組成部分,在WinForm中TreeView控件的每一個(gè)節(jié)點(diǎn)都是一個(gè)TreeNode類(lèi)的實(shí)例,每一個(gè)TreeNode對(duì)象又都具有Nodes屬性來(lái)設(shè)置和管理它的子節(jié)點(diǎn),TreeNode對(duì)象的常用屬性如表10-9所示。對(duì)于TreeView控件來(lái)說(shuō),最為重要的就是對(duì)其中包含的節(jié)點(diǎn)進(jìn)行相關(guān)的操作和管理,因此對(duì)TreeView的應(yīng)用主要就集中在添加節(jié)點(diǎn)、取得選中的節(jié)點(diǎn)以及用戶(hù)選中節(jié)點(diǎn)后的操作等幾個(gè)方面。為T(mén)reeView控件添加節(jié)點(diǎn)的方式有兩種。首先,我們可以通過(guò)WinForm中的TreeNode編輯器在圖形界面中完成節(jié)點(diǎn)的設(shè)置,將TreeView控件添加到窗體中后找到其N(xiāo)odes屬性,點(diǎn)擊后打開(kāi)TreeNode編輯器。在打開(kāi)的TreeNode編輯器左側(cè)的“選擇要編輯的節(jié)點(diǎn)(N):”下方,我們可以看到當(dāng)前TreeView控件中已經(jīng)添加的所有節(jié)點(diǎn)及其層次結(jié)構(gòu),選中其中的某一個(gè)節(jié)點(diǎn),可以在窗體右側(cè)“節(jié)點(diǎn)X的屬性(P):”下方看到當(dāng)前選中節(jié)點(diǎn)的常用屬性,如圖10-23所示。在節(jié)點(diǎn)列表的下方,我們可以看到兩個(gè)按鈕?!疤砑痈?R)”按鈕的作用是為T(mén)reeView控件添加一個(gè)根節(jié)點(diǎn)。而“添加子級(jí)(C)”按鈕則可以為當(dāng)前選中節(jié)點(diǎn)添加子節(jié)點(diǎn)。在節(jié)點(diǎn)列表的右側(cè),自上而下分別是上移按鈕、下移按鈕和刪除按鈕。當(dāng)我們選中某個(gè)節(jié)點(diǎn)后點(diǎn)擊上移按鈕,該節(jié)點(diǎn)就會(huì)向上移動(dòng);如果點(diǎn)擊下移按鈕,那么該節(jié)點(diǎn)就會(huì)向下移動(dòng);點(diǎn)擊刪除按鈕就可以刪除該節(jié)點(diǎn)及其子節(jié)點(diǎn)。通過(guò)這幾個(gè)按鈕我們就可以根據(jù)需要設(shè)計(jì)出完整的TreeView控件。使用代碼方式添加節(jié)點(diǎn)需要先創(chuàng)建TreeNode對(duì)象,然后通過(guò)調(diào)用Add()方法,將其添加到相應(yīng)節(jié)點(diǎn)的Nodes屬性中:TreeNodetn1=newTreeNode("根節(jié)點(diǎn)1");trvFilmType.Nodes.Add(tn1);trvFilmType.Nodes.Add(newTreeNode("根節(jié)點(diǎn)2"));trvFilmType.Nodes.Add("根節(jié)點(diǎn)3");在上面的代碼中我們采用三種方式向TreeView控件中添加了根節(jié)點(diǎn)。第一種方式首先創(chuàng)建了一個(gè)TreeNode對(duì)象,在實(shí)例化的時(shí)候我們通過(guò)其構(gòu)造向該對(duì)象傳遞了一個(gè)字符串類(lèi)型的參數(shù)作為其Text屬性的值,然后調(diào)用TreeView控件Nodes屬性的Add()方法將其添加到TreeView控件中。第二種方式其實(shí)和第一種方式是一樣的,只不過(guò)我們沒(méi)有再顯式地創(chuàng)建TreeNode對(duì)象,而是在調(diào)用Add()方法的時(shí)候臨時(shí)創(chuàng)建了它,同時(shí)依然通過(guò)其構(gòu)造方法傳遞了字符串參數(shù)作為其文本值。第三種方式直接在調(diào)用Add()方法的時(shí)候傳遞字符串作為參數(shù),節(jié)點(diǎn)則是由系統(tǒng)幫助我們來(lái)創(chuàng)建。無(wú)論采用哪種方式,只要是通過(guò)TreeView控件的Nodes屬性添加的節(jié)點(diǎn)都將是樹(shù)控件的根節(jié)點(diǎn),如果需要為某個(gè)節(jié)點(diǎn)添加子節(jié)點(diǎn),就需要通過(guò)該節(jié)點(diǎn)的Nodes屬性來(lái)完成:tn1.Nodes.Add("子節(jié)點(diǎn)1");tn1.Nodes.Add(newTreeNode("子節(jié)點(diǎn)2"));trvFilmType.Nodes[1].Nodes.Add("子節(jié)點(diǎn)3");trvFilmType.Nodes[1].Nodes.Add(newTreeNode("子節(jié)點(diǎn)4"));添加子節(jié)點(diǎn)的方式我們也給出了兩種。如果我們明確知道當(dāng)前節(jié)點(diǎn)的名稱(chēng),則可以通過(guò)第一種方式來(lái)為它添加子節(jié)點(diǎn)。如果不知道當(dāng)前節(jié)點(diǎn)的名稱(chēng),我們就只能夠通過(guò)第二種方式,也就是當(dāng)前節(jié)點(diǎn)在Nodes中的排列位置找到該節(jié)點(diǎn),然后再為其添加子節(jié)點(diǎn)。一般來(lái)說(shuō),對(duì)樹(shù)控件進(jìn)行各種操作的時(shí)候都會(huì)和循環(huán)結(jié)合在一起,例如將數(shù)據(jù)表中的數(shù)據(jù)填充到TreeView控件中等。樹(shù)控件的節(jié)點(diǎn)層級(jí)越多,所需要的循環(huán)結(jié)構(gòu)越復(fù)雜,因此在實(shí)際應(yīng)用過(guò)程中最好不要?jiǎng)?chuàng)建操作三級(jí)的樹(shù)控件,否則程序?qū)?huì)變得很復(fù)雜。
10.5查看電影信息
10.5.1問(wèn)題在音像店管理系統(tǒng)中,當(dāng)用戶(hù)成功登錄到系統(tǒng)中以后,接下來(lái)就需要根據(jù)用戶(hù)自己的喜好查找電影并查看電影的詳細(xì)信息。這里我們首先需要用一個(gè)列表的方式將電影的主要信息展示出來(lái),同時(shí)要提供相應(yīng)的操作方式供用戶(hù)查找自己感興趣的電影,如圖10-26所示。該窗體的主要要求如下:(1)窗體運(yùn)行時(shí)要求在屏幕中央,不能最大化和最小化,也不能夠改變大小。(2)顯示電影類(lèi)型的下拉列表只能夠選擇不能輸入,同時(shí)為了方便用戶(hù)需要增加一個(gè)“選擇全部”選擇項(xiàng)用來(lái)查看所有電影。(3)頁(yè)面首次加載時(shí)需要以列表的形式顯示出所有電影的信息,包括電影名稱(chēng)、主演、價(jià)格和類(lèi)型。(4)當(dāng)用戶(hù)選擇了某部類(lèi)型的電影時(shí),可實(shí)現(xiàn)對(duì)電影信息的查詢(xún)功能。雙擊列表中的某一部影片后,以模式窗體打開(kāi)影片詳細(xì)信息窗體并顯示該影片的詳細(xì)信息。對(duì)于該窗體的要求如下:(1)窗體運(yùn)行時(shí)要求在屏幕中央,不能最大化和最小化,也不能夠改變大小。(2)顯示電影類(lèi)型的下拉列表只能夠選擇不能輸入,但是不需要添加“選擇全部”項(xiàng)。(3)根據(jù)由列表窗體傳遞過(guò)來(lái)的電影編號(hào)查詢(xún)電影詳細(xì)信息并顯示在窗體的相應(yīng)位置。(4)由于我們還沒(méi)有將整個(gè)程序整合,因此“保存”按鈕功能不需要實(shí)現(xiàn),但是“關(guān)閉”按鈕功能需要實(shí)現(xiàn)。10.5.2需求分析下面我們需要根據(jù)上面提出的要求做出詳細(xì)的需求分析。1.界面設(shè)計(jì)電影信息列表窗體的界面元素設(shè)計(jì)如表10-10所示。電影詳細(xì)信息窗體的界面元素設(shè)計(jì)如表10-11所示。2.添加“選擇全部”項(xiàng)在前面的章節(jié)中我們已經(jīng)學(xué)習(xí)了如何將數(shù)據(jù)表中的數(shù)據(jù)放置到下拉列表控件中,但是在進(jìn)行操作的時(shí)候有一個(gè)很重要的限制,即數(shù)據(jù)一旦通過(guò)DataSource屬性綁定到控件上后,就不允許再修改控件中的數(shù)據(jù),那么我們?cè)撊绾螌ⅰ斑x擇全部”這樣一個(gè)新的選擇項(xiàng)添加到下拉列表中呢?方法當(dāng)然有很多種,例如我們可以直接在數(shù)據(jù)庫(kù)中添加一條這樣的數(shù)據(jù),也可以循環(huán)遍歷數(shù)據(jù)表的Rows屬性,將其中的數(shù)據(jù)依次通過(guò)Add()方法添加到ComboBox控件中。但是本章我們將采用一種新的方式來(lái)解決這個(gè)問(wèn)題。事實(shí)上,仔細(xì)分析一下ComboBox控件和數(shù)據(jù)表我們就會(huì)發(fā)現(xiàn),在使用DataSource屬性進(jìn)行數(shù)據(jù)綁定的時(shí)候,控件中要顯示什么數(shù)據(jù)完全是由數(shù)據(jù)表來(lái)決定的,于是我們就有了一個(gè)新的思路:不能修改控件的數(shù)據(jù),那我們就直接修改數(shù)據(jù)表中的數(shù)據(jù),然后再進(jìn)行數(shù)據(jù)綁定,這樣也可以解決問(wèn)題。整個(gè)操作過(guò)程其實(shí)并不復(fù)雜:List<FilmType>types=newList<FilmType>();//在第一條顯示的是全部電影FilmTypet=newFilmType();t.ID=0;t.Name="全部電影";types.Add(t);using(SqlConnectionconn=newSqlConnection(strConn)){stringstrSql="select*fromFilmType";SqlCommandcomm=newSqlCommand(strSql,conn);conn.Open();SqlDataReaderdr=comm.ExecuteReader();FilmTypemodel=null;while(dr.Read()){model=newFilmType();model.ID=(int)dr["ID"];model.Name=dr["Name"].ToString();model.ParentID=(int)dr["ParentID"];model.Desc=dr["Desc"].ToString();model.State=(int)dr["State"];
types.Add(model);}dr.Close();}cboFilmType.DisplayMember="Name";cboFilmType.ValueMember="ID";cboFilmType.DataSource=types;上面的代碼大部分我們都已經(jīng)很熟悉了,首先依然是創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接對(duì)象,然后通過(guò)閱讀器對(duì)象SqlDataReader讀取數(shù)據(jù),循環(huán)添加到List集合中。因?yàn)樾枰谙吕蛑械谝恍谐霈F(xiàn)“選擇全部”,所以,我們?cè)谔砑訑?shù)據(jù)到集合前,先添加進(jìn)集合。最后我們用這個(gè)數(shù)據(jù)表對(duì)象完成了ComboBox控件的數(shù)據(jù)綁定,由于在數(shù)據(jù)表中“選擇全部”位于第一行,因此綁定后該選項(xiàng)就會(huì)出現(xiàn)在ComboBox控件的第一項(xiàng)。事實(shí)上,在實(shí)際開(kāi)發(fā)過(guò)程中我們經(jīng)常會(huì)遇到無(wú)法修改控件的值,或者修改起來(lái)很困難,這個(gè)時(shí)候就可以通過(guò)直接修改控件數(shù)據(jù)源的方式來(lái)實(shí)現(xiàn)我們所需要的操作。3.?dāng)?shù)據(jù)查詢(xún)數(shù)據(jù)查詢(xún)是我們需要重點(diǎn)實(shí)現(xiàn)的功能,根據(jù)用戶(hù)給出的條件生成相應(yīng)的查詢(xún)語(yǔ)句,在數(shù)據(jù)庫(kù)中執(zhí)行后得到查詢(xún)結(jié)果。第一步提取數(shù)據(jù)的工作并不復(fù)雜,而且在前面我們已經(jīng)做過(guò)很多次了:stringconn=ConfigurationManager.ConnectionStrings["SQL"].ConnectionString;SqlConnectioncn=newSqlConnection(conn);stringstrSql="selectF.ID,F.Name,F.Actors,F.Price,T.NameTypeNamefromFilmF";strSql+="innerjoinFilmTypeTonF.TypeID=T.ID";這里要注意的是,有一個(gè)條件是“全部電影”,也就是說(shuō)在組合查詢(xún)語(yǔ)句的時(shí)候,如果是全部電影則不需要加條件,而只有選中某一個(gè)類(lèi)型的時(shí)候才需要加上查詢(xún)條件。if(id>0)strSql+="whereF.TypeID="+id.ToString();SqlCommandcomm=newSqlCommand(strSql,conn);conn.Open();SqlDataReaderdr=comm.ExecuteReader();4.顯示電影信息對(duì)電影信息的查看我們需要提供兩種方式。首先我們需要用列表的方式將查詢(xún)到的電影信息呈現(xiàn)出來(lái),這一步操作我們可以使用ListView控件來(lái)實(shí)現(xiàn):lsvShowData.Items.Clear();while(dr.Read()){ListViewItemitem=newListViewItem();item.Tag=(int)dr["ID"]; //該屬性用來(lái)保存當(dāng)前數(shù)據(jù)的ID值item.SubItems[0].Text=dr["Name"].ToString();item.SubItems.Add(dr["Actors"].ToString());item.SubItems.Add(string.Format("{0:C}",dr["Price"]));item.SubItems.Add(dr["TypeName"].ToString());lsvShowData.Items.Add(item);}dr.Close();操作和我們?cè)谇懊鎸W(xué)習(xí)到的方式是一樣的,只不過(guò)在循環(huán)開(kāi)始之前我們調(diào)用了ListView控件Items屬性的Clear()方法,該方法的作用是將ListView控件中的數(shù)據(jù)行全部清除。這么做的原因是我們需要用這個(gè)控件反復(fù)顯示數(shù)據(jù),不過(guò)不做這個(gè)操作數(shù)據(jù)就會(huì)累加在一起。另外一個(gè)需要主意的地方是我們使用到了ListViewItem對(duì)象的Tag屬性,該屬性主要用來(lái)保存和對(duì)象相關(guān)的數(shù)據(jù),這里我們保存的是電影的編號(hào)。我們需要做的第二個(gè)顯示工作是在電影詳細(xì)信息窗體中顯示電影的詳細(xì)信息,要完成這個(gè)工作我們需要經(jīng)過(guò)幾個(gè)步驟。首先需要我們?cè)陔娪靶畔⒘斜泶绑w中獲得用戶(hù)選擇的電影的編號(hào),然后將這個(gè)編號(hào)傳遞到電影詳細(xì)信息窗體,最后根據(jù)這個(gè)編號(hào)查詢(xún)電影信息并顯示。本次我們?cè)O(shè)定的操作方式是,用戶(hù)在電影信息列表中雙擊某條電影信息就可以打開(kāi)詳細(xì)信息窗體,因此首先我們?cè)贚istView控件的事件列表中找到DoubleClick事件,雙擊后在系統(tǒng)自動(dòng)生成的事件處理程序中完成后續(xù)的操作:privatevoidlsvShowData_DoubleClick(objectsender,EventArgse){if(lsvShowData.SelectedItems.Count>0){intid=(int)lsvShowData.SelectedItems[0].Tag;
frmFilmDetailsfd=newfrmFilmDetails(id);fd.ShowDialog();}}在這段處理程序中,我們首先添加了一個(gè)if結(jié)構(gòu),這么做的目的是確保在有電影被選中的情況下才執(zhí)行該操作,因?yàn)槲覀冇玫氖荓istView控件的雙擊事件,有可能會(huì)出現(xiàn)用戶(hù)在沒(méi)有選中任何行的情況下雙擊控件而觸發(fā)事件。在if結(jié)構(gòu)中,我們可以通過(guò)ListView控件的SelectedItems屬性取得所有選中項(xiàng),ListView控件本身就支持多選,盡管我們?cè)O(shè)定了其MultiSelect屬性為false,但是在訪(fǎng)問(wèn)用戶(hù)選中的行時(shí)依然需要通過(guò)SelectedItems屬性,當(dāng)然因?yàn)橹荒軌蜻x擇一行,因此下標(biāo)就只能是零了。通過(guò)選中行的Tag屬性,就可以取得電影的編號(hào)。接下來(lái)的窗體間傳參我們?cè)谇懊娴恼鹿?jié)中已經(jīng)學(xué)習(xí)過(guò)了,這里就不再重復(fù)說(shuō)明。將電影的編號(hào)傳遞到詳細(xì)信息窗體后,我們就可以根據(jù)這個(gè)編號(hào)到數(shù)據(jù)庫(kù)中查找電影信息并顯示在窗體中,不過(guò)在這之前我們還需要首先將電影分類(lèi)信息綁定到ComboBox控件上,具體做法可參考上一個(gè)窗體中電影類(lèi)型的數(shù)據(jù)讀取和綁定,不過(guò)這一次我們不用加上“選擇全部”了。接下來(lái)就是具體的數(shù)據(jù)顯示了:using(SqlConnectionconn=newSqlConnection(strConn)){stringstrSql="select*fromFilmwhereID="+filmID.ToString();SqlCommandcomm=newSqlCommand(strSql,conn);conn.Open();SqlDataReaderdr=comm.ExecuteReader();while(dr.Read()){txtName.Text=dr["Name"].ToString();txtActors.Text=dr["Actors"].ToString();txtPrice.Text=string.Format("{0:C}",dr["Price"]);txtAmount.Text=dr["Amount"].ToString();txtDesc.Text=dr["Desc"].ToString();cboType.SelectedValue=dr["TypeID"];}dr.Close();}首先創(chuàng)建數(shù)據(jù)庫(kù)連接對(duì)象,然后使用SqlDataReader對(duì)象來(lái)提取數(shù)據(jù),當(dāng)然我們這里的SQL語(yǔ)句添加了根據(jù)電影編號(hào)查詢(xún)的條件,在將數(shù)據(jù)填充到數(shù)據(jù)表中以后,我們通過(guò)一個(gè)if結(jié)構(gòu)對(duì)數(shù)據(jù)表中的數(shù)據(jù)行做了判斷,已確定成功讀取了數(shù)據(jù)。具體的數(shù)據(jù)顯示也沒(méi)有復(fù)雜之處,我們是根據(jù)電影的編號(hào)進(jìn)行查詢(xún)的,如果存在數(shù)據(jù)那么肯定就只有一行數(shù)據(jù),因此在讀取數(shù)據(jù)的時(shí)候行下標(biāo)就賦值為零。需要注意顯示數(shù)據(jù)的最后一行,ComboBox控件的數(shù)據(jù)是使用數(shù)據(jù)表綁定的,因此要通過(guò)其SelectedValue設(shè)定其選中行才行。10.5.3實(shí)現(xiàn)電影查看本章的案例是本書(shū)中我們所制作的最復(fù)雜的程序,frmFilmList窗體代碼如下:publicpartialclassfrmFilmList:Form{publicfrmFilmList(){InitializeComponent();}stringstrConn=ConfigurationManager.ConnectionStrings["SQL"].ConnectionString;privatevoidfrmFilmList_Load(objectsender,EventArgse){
BindList();}privatevoidBindList(){List<FilmType>types=newList<FilmType>();FilmTypet=newFilmType(); //在第一條顯示的是全部電影t.ID=0;t.Name="全部電影";types.Add(t);using(SqlConnectionconn=newSqlConnection(strConn)){stringstrSql="select*fromFilmType";SqlCommandcomm=newSqlCommand(strSql,conn);conn.Open();SqlDataReaderdr=comm.ExecuteReader();FilmTypemodel=null;while(dr.Read())
{model=newFilmType();model.ID=(int)dr["ID"];model.Name=dr["Name"].ToString();model.ParentID=(int)dr["ParentID"];model.Desc=dr["Desc"].ToString();model.State=(int)dr["State"];types.Add(model);}dr.Close();}cboFilmType.DisplayMember="Name";cboFilmType.ValueMember="ID";cboFilmType.DataSource=types;}privatevoidBindListView(intid){lsvShowData.Items.Clear();using(SqlConnectionconn=newSqlConnection(strConn)){stringstrSql="selectF.ID,F.Name,F.Actors,F.Price,T.NameTypeNamefromFilmF";strSql+="innerjoinFilmTypeTonF.TypeID=T.ID";if(id>0)strSql+="whereF.TypeID="+id.ToString();SqlCommandcomm=newSqlCommand(strSql,conn);conn.Open();SqlDataReaderdr=comm.ExecuteReader();while(dr.Read()){ListViewItemitem=newListViewItem();item.Tag=(int)dr["ID"];item.SubItems[0].Text=dr["Name"].ToString();item.SubItems.Add(dr["Actors"].ToString());
item.SubItems.Add(string.Format("{0:C}",dr["Price"]));item.SubItems.Add(dr["TypeName"].ToString());lsvShowData.Items.Add(item);}dr.Close();}}privatevoidcboFilmType_SelectedIndexChanged(objectsender,EventArgse){intid=(int)cboFilmType.SelectedValue;BindListView(id);}privatevoidlsvShowData_DoubleClick(objectsender,EventArgse){if(lsvShowData.SelectedItems.Count>0)
{intid=(int)lsvShowData.SelectedItems[0].T
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 無(wú)人機(jī)精準(zhǔn)農(nóng)業(yè)-洞察分析
- 虛擬現(xiàn)實(shí)技術(shù)在言語(yǔ)康復(fù)中的應(yīng)用研究-洞察分析
- 舞臺(tái)視覺(jué)特效-第3篇-洞察分析
- 網(wǎng)絡(luò)化維修服務(wù)模式-洞察分析
- 網(wǎng)絡(luò)文學(xué)與傳統(tǒng)文學(xué)的敘事比較-洞察分析
- 異常安全風(fēng)險(xiǎn)評(píng)估-洞察分析
- 向廠(chǎng)長(zhǎng)提出調(diào)換工作崗位的申請(qǐng)書(shū)范文(7篇)
- 藝術(shù)空間激活社區(qū)活力-洞察分析
- 微納光學(xué)器件在量子計(jì)算中的應(yīng)用-洞察分析
- 水熱處理對(duì)茶葉品質(zhì)影響-洞察分析
- 四川省簡(jiǎn)陽(yáng)市禾豐鎮(zhèn)初級(jí)中學(xué)-2025年蛇年寒假特色作業(yè)【課件】
- 滬教版(上海)七年級(jí)上學(xué)期全部章節(jié)知識(shí)點(diǎn)總結(jié)
- GB/T 45004-2024鋼鐵行業(yè)低碳企業(yè)評(píng)價(jià)指南
- 2024年全國(guó)統(tǒng)一電力市場(chǎng)建設(shè)情況及展望報(bào)告-中國(guó)電力企業(yè)聯(lián)合會(huì)(潘躍龍)
- 2024年招商部門(mén)工作計(jì)劃(3篇)
- DB21T 2748-2017 拉氏鱥池塘養(yǎng)殖技術(shù)規(guī)范
- 運(yùn)河鎮(zhèn)江段航道疏浚工程環(huán)評(píng)資料環(huán)境影響
- 第一單元知識(shí)提綱(填空版) -2024-2025學(xué)年統(tǒng)編版道德與法治七年級(jí) 上冊(cè)
- 2024學(xué)年第一學(xué)期杭州市高三年級(jí)教學(xué)質(zhì)量檢測(cè)試題(杭州一模)含答案
- 生理學(xué)課件全套課件
- 《幸福終點(diǎn)站》電影賞析
評(píng)論
0/150
提交評(píng)論