底層模型概述Spread控件提供了很多模型,這些模型提供了自定義控件的基礎(chǔ)架構(gòu),。同時,,這些模型作為底層模板,派生出了更多通用的快捷對象,。 在不使用Spread的底層模型的情況下,,你可以完成許多任務(wù)。通過使用Spread設(shè)計器或者快捷對象(如單元格,、列和行)的屬性,,你可以在表單上實現(xiàn)許多改變,。但是因為表單模型是所有快捷對象的基礎(chǔ),因此在通常情況下,,使用表單模型要比使用快捷對象的速度要快,。例如,在代碼中使用快捷對象設(shè)置一個屬性值: fpSpread1.Sheets[0].Cells[0, 0].Value = "Test"; 這與下面使用底層數(shù)據(jù)模型的方式等價: fpSpread1.Sheets[0].Models.Data.SetValue(fpSpread1.Sheets[0].GetModelRowFromViewRow(0), fpSpread1.Sheets[0].GetModelColumnFromViewColumn(0), "Test"); 快捷對象訪問的是底層模型,。當(dāng)你使用快捷對象時,,你實際上在使用控件的模型。作為一名開發(fā)人員,,如果你想完全理解Spread的工作方式,,想使用那些為你提供的豐富特性和自定義功能,你就需要理解底層模型的使用方法,。例如,,你可以用這種方法為你公司所有的開發(fā)者創(chuàng)建一個模板控件?;谶@些模型中的一種創(chuàng)建你自己的類,,你可以自定義該類并提供給所有的開發(fā)者使用。 使用底層模型有以下好處:
表單模型是一個集合,,包含了所有對象的基礎(chǔ)設(shè)置以及某個特定表單的設(shè)置項,。如果在Spread控件中有多個表單,那么每一個表單都有一個它自己的模型集合,。 控件中表單的某些部分是由底層模型管理的,,下圖對模型做了概念性的描述。 想要把使用模型描述清楚并不容易,,因為涉及到許多接口,。每一個模型類都實現(xiàn)了許多接口,并且每一個模型都要實現(xiàn)一個特定的“模型”接口,使其作為該特定模型的合法實現(xiàn),。所有對模型類的引用都是通過接口實現(xiàn)的,,并且不要猜想每一個模型中都實現(xiàn)了哪些接口(除了“模型”接口必須暴露出來之外)。如果模型類沒有實現(xiàn)一個特定的接口,,那么該功能就不能在表單中使用(例如,,如果SheetView.Models.Data沒有實現(xiàn)IDataSourceSupport接口,那么DataSource和DataMember屬性將不起作用),。如果想獲取這些接口的完整列表,,你可以在線幫助文檔中查看相關(guān)信息http://www./docs/spreadwin5help/ 。 表單模型的類型Spread控件提供了如下模型,,這些模型提供了許多可以在控件上使用的自定義設(shè)置項,。
表單(SheetView對象)可以看作是五個底層模型(軸,、數(shù)據(jù),、選擇,、合并和樣式)的組合:
因此,你對模型做的所有操作都會自動的在表單中進行更新,,并且大部分的表單修改也會在模型中進行更新,。對于單元格、行和列對象的設(shè)置也都是如此,。對這些對象的大部分修改都會自動更新到相應(yīng)的表單模型設(shè)置中,,反之亦然。如果你在數(shù)據(jù)模型中添加了一些列,,它們也會被添加到表單中,。甚至對于參數(shù)也同樣如此,,例如,只要表單未經(jīng)過排序,,數(shù)據(jù)模型GetValue和SetValue方法中的行和列參數(shù),,與表單中行和列的參數(shù)索引就是相同的。 并非所有Spread名字空間的內(nèi)容都包含在模型中,。例如,控件的某些部分,、表單標簽,、表單背景色還有網(wǎng)格線,都沒有包含在模型中,。但是對一個指定的單元格來說,,有意義的信息,如單元格的數(shù)據(jù)以及單元格的外觀,,都被包含在模型中,。表單的數(shù)據(jù)區(qū)域有自己的模型集;同樣的,,行標題和列標題是另外兩個具有自己模型集的分組,,表角是另外一個具有自己模型集的分組,。 每一個模型都包含一個基礎(chǔ)模型類,一 默認模型類和一個接口,。默認模型是你在開發(fā)時最可能用到的模型;它提供了控件的默認特性,,并且可以用來對模型進行小范圍的自定義設(shè)置?;A(chǔ)模型是創(chuàng)建默認模型的基礎(chǔ),也可以通過它創(chuàng)建自定義模型,。基礎(chǔ)模型包含最少的內(nèi)置特性,,默認模型對基礎(chǔ)模型進行了擴展,。如果你想為你的應(yīng)用程序提供不同的功能特性或者自定義它的外觀和行為,你可以通過擴展基礎(chǔ)模型創(chuàng)建一個新類來實現(xiàn),。例如,,你可以通過以上的方法為你公司的所有開發(fā)人員創(chuàng)建一個模板控件,。基于基礎(chǔ)模型創(chuàng)建自己的類,,你可以創(chuàng)建自定義類,,并把它提供給其他開發(fā)者使用。一般情況下,,如果你在編輯模型,請使用默認模型類,。但是如果你想(從頭開始)創(chuàng)建一個自定義模型,,請使用基礎(chǔ)模型類。 每一個默認模型類不僅實現(xiàn)了該模型類特有的接口,,還實現(xiàn)了其他可選的接口,。在模型類中,大多數(shù)功能(例如,,公式,、數(shù)據(jù)綁定、XML序列化等等)都是可選的,,并且是在與主模型接口(如ISheetDataModel)不同的接口中實現(xiàn)的,。因此如果你想實現(xiàn)自己的模型類,你可以自主選擇想要實現(xiàn)哪些功能,。 模型與模型之間保持同步是很重要的,,所以在組成表單的模型中,行數(shù)和列數(shù)是需要保持一致的,。SheetView對象通過SheetView.DocumentModels.Data屬性監(jiān)聽ISheetDataModel.Change事件,,并且當(dāng)行數(shù)或者列數(shù)通過以下方式改變時,會相應(yīng)的對其他模型進行更新:
如果模型之間同步失敗,,程序?qū)伋鲆粋€索引out-of-range異常,,并嘗試獲取不存在的行或列的信息。 理解數(shù)據(jù)模型數(shù)據(jù)模型包含了單元格的內(nèi)容,,不管它是數(shù)值還是公式,,或者是單元格的注釋或標記。數(shù)據(jù)模型在表單的數(shù)據(jù)域內(nèi)包含了單元格的Value屬性,,數(shù)據(jù)綁定表單的database屬性,,以及其他與單元格內(nèi)容相關(guān)的屬性。 數(shù)據(jù)模型是你在使用Spread控件時最有可能進行自定義設(shè)置的模型,。相對于其他模型,,數(shù)據(jù)模型實現(xiàn)了更多的接口,提供了更多可選擇的功能,。例如,,如果你想要實現(xiàn)類似于ActiveX Spread控件的未綁定虛擬模型功能,,自定義數(shù)據(jù)模型就可以實現(xiàn)。 數(shù)據(jù)模型對象 數(shù)據(jù)模型是一個為單元格提供值的對象,,這些值顯示在表單中,。大多數(shù)情況下,創(chuàng)建時表單所創(chuàng)建的默認數(shù)據(jù)模型就能滿足你的需求,。 默認數(shù)據(jù)模型DefaultSheetDataModel可以創(chuàng)建用來存儲注釋,、公式、標簽和值的對象,。這些對象主要設(shè)計用來在內(nèi)存使用和速度之間進行平衡,,內(nèi)存使用的大小和存取速度的快慢與數(shù)據(jù)模型的大小以及其中數(shù)據(jù)的稀疏程度相關(guān)。如果你不使用注釋,、公式以及標簽,這樣就不會占用很多內(nèi)存,,因為數(shù)據(jù)非常的稀疏,。事實上這些對象并不會為數(shù)據(jù)申請內(nèi)存,除非真的需要,。所以只要沒有在模型中設(shè)置注釋,、公式或標簽,內(nèi)存占用會一直很少,。 默認數(shù)據(jù)模型可以在未綁定模式或綁定模式下使用,。在未綁定模式下,數(shù)據(jù)模型的表現(xiàn)像是一個儲存單元格值的二維數(shù)組,。在綁定模式下,,數(shù)據(jù)模型封裝了所提供的DataSource;如果需要,,還可提供DataSource中沒有的額外設(shè)置,,例如,單元格公式,,以及未綁定行或者列,。 設(shè)置和添加數(shù)據(jù)模型 SetModelDataColumn方法與AddColumn方法的不同地方在于,你可以在數(shù)據(jù)模型中指定哪一個數(shù)據(jù)域綁定到哪一列上,。 如果你在模型中添加了一些列,那么這些列也會被添加到表單中,。只要表單未經(jīng)過排序,,數(shù)據(jù)模型GetValue和SetValue方法中的行和列參數(shù),與表單中行和列的參數(shù)索引就是相同的,。如果對表單的行或列進行了排序,,那么視圖坐標必須通過SheetView.GetModelRowFromViewRow和 SheetView.GetModelColumnFromViewColumn方法與模型坐標進行映射,。 在數(shù)據(jù)模型中,,SheetView.GetValue方法和SheetView.SetValue方法經(jīng)常用來獲取或設(shè)置數(shù)據(jù),。(這與調(diào)用SheetView.Models.Data.GetValue和SheetView.Models.Data.SetValue等價,。) 在SpreadView的SheetView中,當(dāng)單元格處于編輯模式時,,Cell.Value屬性返回editor控件中單元格的值。當(dāng)單元格結(jié)束編輯模式時,,單元格的值就會在數(shù)據(jù)模型中進行更新,。但是,,你可以通過代碼手動把值更新到數(shù)據(jù)模型中: SheetView.SetValue(row, column, SheetView.Cells[row, column].Value); 實現(xiàn)的接口 當(dāng)數(shù)據(jù)模型實現(xiàn)了IDataSourceSupport接口并被綁定到一個數(shù)據(jù)源時,數(shù)據(jù)模型中被綁定的部分就可以直接從數(shù)據(jù)源中獲取或設(shè)置數(shù)據(jù),。如果在數(shù)據(jù)模型綁定數(shù)據(jù)源之后,,使用AddColumns方法向其加入了一些列(對于這些列,IDataSourceSupport.IsColumnBound返回false),,那么這些列也可以是未綁定的。這些未綁定列的數(shù)據(jù)將會保存在數(shù)據(jù)模型中,,而不是在數(shù)據(jù)源中,。 如果數(shù)據(jù)模型也實現(xiàn)了IUnboundRowSupport接口,那么數(shù)據(jù)模型中的行也可以是未綁定狀態(tài)的,,并且這些行的數(shù)據(jù)也將保存在數(shù)據(jù)模型中而不是在數(shù)據(jù)源中,。這些行可以通過調(diào)用 IUnboundRowSupport.AddRowToDataSource函數(shù)轉(zhuǎn)換成綁定行,并且如果autoFill參數(shù)被設(shè)置為True,,未綁定的行中已綁定列的數(shù)據(jù)將以一條新的記錄或一個新的元素被添加到數(shù)據(jù)源中,,假設(shè)數(shù)據(jù)源允許這樣的操作(如果它不允許這樣的操作時,你將會得到一個異常),,這樣一個未綁定的行就轉(zhuǎn)換成了綁定行,。 默認的數(shù)據(jù)模型類,,DefaultSheetDataModel,,實現(xiàn)了所有的接口,以及許多與計算,、層次和序列化相關(guān)的接口,。 查看以下的代碼段,,可以看到默認的數(shù)據(jù)模型和表單上的對象有什么不同。這段代碼把表單綁定到一個叫MyData的數(shù)據(jù)源上,。 fpSpread1.Sheets[0].DataSource = MyData.Tables[0]; 以及
在第一個代碼段中,,開發(fā)者使用現(xiàn)有的數(shù)據(jù)模型,并把它轉(zhuǎn)化為一個數(shù)據(jù)源,; 在第二個代碼段中,,開發(fā)者使用一個新的數(shù)據(jù)模型替換老的模型,并且丟棄老的數(shù)據(jù)模型,。兩種實現(xiàn)方式的結(jié)果是相同的,,但是第一種方式將導(dǎo)致老的模型變成垃圾,并進行回收,。通常你可能不想進行數(shù)據(jù)模型替換,,除非你想創(chuàng)建屬于自己的數(shù)據(jù)模型類。一般情況下,,沒有必要使用其他的DefaultSheetDataModel替換數(shù)據(jù)模型,,因為已經(jīng)有一個在使用了。 速度和性能的平衡 如果你從DefaultSheetDataModel 上派生,,并使用GetValue和SetValue的實現(xiàn)來存儲數(shù)據(jù),,那么它將通過我們對稀疏數(shù)組和矩陣的實現(xiàn)在內(nèi)存使用和訪問速度之間進行平衡。設(shè)計它的目的是為了實現(xiàn)快速創(chuàng)建一個很大的模型(2億行*乘以2億列),,并且能夠以合理的速度進行數(shù)據(jù)的獲取和設(shè)置,,直到數(shù)據(jù)量變得很大(這種情況下,不管怎樣你都將會耗盡內(nèi)存),。當(dāng)模型很大,,并且很稀疏時(例如有至少三分之二是空的),訪問速度會變得很慢(需要使用二分查找法),,并且內(nèi)存使用效率也會降低,。在模型不是很大的情況下(少于32K行和列時),并且不稀疏(至少三分之一是滿的),,訪問速度會很快(不需要使用二分查找法)并且內(nèi)存使用效率很高,。 你可以先創(chuàng)建一個在窗體上使用Spread控件的測試工程,然后在該工程上運行一些簡單的測試,,把表單的ColumnCount和RowCount屬性設(shè)置為一個很大的值,,你不會發(fā)現(xiàn)任何延遲;這是因為內(nèi)存是基于實際數(shù)據(jù)項的大小來分配的,。如果你開始在表單中填入大量數(shù)據(jù),,不久你就會感覺到延遲,尤其當(dāng)可用內(nèi)存變小并且系統(tǒng)開始使用頁面文件來進行虛擬內(nèi)存的交換的時候(僅在有大量數(shù)據(jù)時,才會發(fā)生這種現(xiàn)象),。 如果你需要獲取更多的細節(jié),請參閱BaseSheetDataModel 類,,DefaultSheetDataModel 類和ISheetDataModel 接口,。 創(chuàng)建一個自定義的表單模型你可以以表單模型為模板來創(chuàng)建一個新的定制模型。例如,,設(shè)想創(chuàng)建一個自定義數(shù)據(jù)模型,。使用自定義數(shù)據(jù)模型,需要創(chuàng)建一個類并實現(xiàn)ISheetDataModel, 并在SheetView.Models.Data屬性中設(shè)置該類的實例,。 假設(shè)你不需要任何可選的接口,,那么 ISheetDataModel 是唯一要求實現(xiàn)的接口。所有可選的接口都在DefaultSheetDataModel 中實現(xiàn)了,。所以,,當(dāng)你想在自己的數(shù)據(jù)模型中實現(xiàn)它們時,可以很容易的僅僅實現(xiàn) DefaultSheetDataModel的子類,。 在BaseSheetDataModel 中,,Changed事件也需要你來實現(xiàn)。 在產(chǎn)品實例Samples\CS\FreeCell文件夾中,,有一個自定義數(shù)據(jù)模型的示例,。這是FreeCell游戲在數(shù)據(jù)模型中的實現(xiàn)。 在少數(shù)情況下,,因為性能原因,,你可能需要創(chuàng)建自己的自定義數(shù)據(jù)模型。例如,,假設(shè)你想要顯示一個有一百萬行十列組成的大表,,并且要計算它的值(如加法或者乘法)。如果使用默認的表單數(shù)據(jù)模型,,那么你需要計算和保存所有一千萬個值,,這將會耗費大量的時間和內(nèi)存。下面是一個代碼實例,。
|
|