文章目錄
- 文檔的載入和儲存
- 使用者介面相關的介面
- 維護文檔對象樹
摘要
本文討論了如何使用C#編寫一個所見即所得 (WYSIWYG)的設計器,分析了設計器的基本原理,可能遇到的技術問題,以及如何調用.NET架構來實現一個設計器。
著作權聲明
本文是XDesigner軟體工作室撰寫,XDesigner軟體工作室擁有本文著作權,轉載請註明出處,並保留本著作權聲明。
前言
隨著電腦資訊系統不斷深入發展,其系統結構要求越來越靈活,這種靈活性就是表現為程式的高度可配置性,可能應用程式的工作流程可以隨便改變,使用者介面也可以隨便改變,面對這種不斷增強靈活,是不可能通過修改程式碼來實現的,應用系統本身需要發生深刻變化,需要實現很強的擴充性和靈活性。此外z專門用於修改系統配置的外圍工具也是非常重要的。這些系統外圍定製工具很大一部分就是一些所見即所得 (WYSIWYG)的設計器。比如工作流程編製工具,WinForm或WebForm介面設計器,而報表設計師也是典型的外圍定製工具。
總所周知,所見即所得 (WYSIWYG)的設計器是個相當複雜的程式,首先它需要複雜的圖形化使用者介面編程,包括圖形的繪製,滑鼠鍵盤事件的處理,還要抗螢幕閃爍。其次還有它背景資料維護處理,包括使用者介面和資料的同步,資料的組織安排,以及載入和儲存文檔的處理。而且這些處理過程可以算是糾纏在一起,需要非常認真小心的分析設計,仔細編碼。
本文就是探討如何?一個所見即所得 (WYSIWYG)的設計器。 關於本文,可以參考作者的另一篇文章-如何使用C#編寫文字編輯器。
設計器類型
設計器按照使用者介面和使用體驗,可以分為兩種模式,一種是基於直角座標方式,另一種是基於流式排版方式。微軟的Visio就是典型的直角座標方式,而Word則是流式排版方式,而VS.NET的WebForm表單設計器就是這兩者的結合。
在直角座標方式的設計器中,設計項目是使用XY座標來在設計檢視中定位的,對於矩形元素一般指定它的左上方的位置來定位,設計者需要指定設計項目的位置,有時還要設定它的大小。對於線段需要指定兩個端點的XY座標。設計者只要設定好了各個元素的位置大小就完成了設計文檔的基本結構,剩下的就是設定各個元素各自的內容了。
在流式排版設計器中,設計項目是不需要指定位置的,是根據一般根據從左至右,從上到下的排列原則填充到設計檢視中(但有時會變成其他排列原則)。設計項目的位置是動態計算的。流式設計器可能還要使用鍵盤直接輸入文本,需要顯示光線標。流式排版設計器可以看作文文書處理器。
這兩種設計器使用者介面和使用體驗不一樣,因此其程式處理的方式也不一樣,直角座標設計器存在設計項目間相互覆蓋,這影響繪圖,此外還需要大量的滑鼠拖拽操作,需要認真處理滑鼠事件,但鍵盤事件處理得不多。而流式排版設計器中元素不會相互覆蓋,因此繪製起來方便點,滑鼠事件處理不多,但鍵盤事件處理的多,此外還需要處理游標。但這兩種設計器它的文件物件模型有比較大的類似性。
在本文中,以下只討論直角座標方式的設計器。
設計器的功能
個人認為一個設計器應當實現的功能有
- 設計文檔的載入和儲存,設計器可以將當前設計的內容儲存到一個文檔中,這個文檔可以儲存到檔案中,也可儲存到資料庫或某個伺服器中。設計器可以載入文檔來完全重現上次的設計結果。
- 設計器可以快速準確的繪製文檔視圖,當視圖大小超過設計地區時,使用者介面應當出現捲軸來進行滾動操作。
- 當前有互換式設計體驗,使用者可以使用滑鼠拖拽操作來改變元素的位置大小等布局設定,使用者改變了元素的布局或某些屬性時,必須立即更新文檔視圖,而且更新地區應當盡量小。
- 支援所見即所得 (WYSIWYG)的設計體驗,當設計器需要進行圖形輸出,例如輸出圖片或列印時,使用者在設計器中的設計檢視應當和輸出的圖形保持一致。
- 盡量減少螢幕閃爍。這需要繪製圖形或更新視圖時需要進行最佳化,儘快完成繪製操作。
- 若設計器需要進行擴充時,設計器應當提供足夠的擴充能力,開發人員可以在這個設計器的基礎上添加新的特性,使得設計器能顯示新樣式的文檔視圖。並且載入和儲存文檔時也能處理新的文檔結構。
- 若需要可以支援VBA指令碼,使用者可以編寫VBA指令碼來控制設計器,包括其設計的文檔內容。
文件物件模型
對於電腦程式,後台決定前台,而設計器的後台就是文件物件模型。相信大家對文件物件模型有所瞭解,我們在WEB頁面中使用JAVASCRIPT指令碼時就是訪問了HTML文件物件模型,我們操作XML文檔就是訪問XML文件物件模型。
W3C國際組織對文件物件模型是這樣定義的(摘自 http://www.w3.org/DOM/ )
The Document Object Model is a platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. The document can be further processed and the results of that processing can be incorporated back into the presented page. This is an overview of DOM-related materials here at W3C and around the web.
以我個人的英文水平翻譯如下
文件物件模型是一種語言中立的介面或平台,程式或指令碼能利用它來訪問和更新結構化的文檔。這些文檔可以被進一步的處理,處理結果可以組成一個有效頁面。這是W3C對web上的對文件物件模型原理的一般看法。
我個人認為,對於編程,文件物件模型其主要內容就是,面對比較複雜的文檔,使用物件導向的編程思想,使用一個個程式世界中的對象來映射文檔中的每一個特定的部分。載入文檔時,可以解析文檔,並把其表示的內容映射為一個個對象,此時應用程式可以修改這些對象的資料,當儲存文檔時,可以將這些對象資料群組織起來按照特定的格式儲存到文檔中。這樣程式就通過訪問文檔對象來訪問文檔,也可以修改文檔對象來修改文檔,如此實現了對複雜文檔的處理。文件物件模型是處理複雜文檔的標準操作模式。
設計器處理的是複雜的文檔,因此也需要使用文件物件模型。文件物件模型可分為三大部分:文檔基本元素,文檔對象和各種類型的從文檔基本元素派生出的文件項目。
文檔基本元素是整個文件物件模型的最基礎的對象(就像Object類型是.NET對象集團的基礎一樣),它定義了文件項目的通用介面,一般定義為抽象類別,類型名稱可以為DesignElement 。
文檔對象是文件物件模型的頂級對象,它包含了整個文檔的內容,其類型名稱可以為 DesignDocument 。
各種類型的文件項目,它是派生自文檔基本元素類型,用於描述文檔中各種實際存在的元素。其中可以定義一種文件項目,它們可以容納其他的文件項目,這些元素就是容器元素。實際上文檔對象就是最大的容器元素。由於文件物件模型中存在容器元素,因此所有的對象都組成一個樹狀結構,稱為文檔對象樹,其中根節點就是文檔對象。各種文件項目是文件物件模型的活躍分子,擴充文件物件模型大部分工作就是擴充這些文件項目,擴充文件項目需要擴充它們的兩個功能,一個是文檔的載入和儲存,一個就是文檔本身儲存的資料。
文件物件模型可以和使用者介面相關,也可以不相關,例如XML文件物件模型是無使用者介面的。設計器的文件物件模型是和使用者介面相關的,對此,擴充設計文件物件模型的文件項目時還需要擴充它們的繪製圖形的能力以便設計器能繪製新型的文件項目圖形。
對於設計文件物件模型,其文檔基礎元素可以定義的內容有三個方面,文檔的載入和儲存,使用者介面相關的介面,維護文檔對象樹的介面。
文檔的載入和儲存
設計文檔可以儲存為二進位文檔,純文字文檔和其他格式,在此推薦使用XML文檔格式。其好處是
- 設計文件物件模型和XML文件物件模型都屬於文件物件模型,兩者原理和結構上都有著很大的相似性,設計文件項目和XML文件項目可以存在一一對應的關係。因此使用XML文檔載入和儲存設計文檔對象是很自然的,實現起來比較簡單。
- XML文檔是國際標準的文檔格式,非常開方,其他應用程式很容易利用設計器產生的檔案,簡化了設計器和其他應用系統的資料介面。
- 已經存在標準的XML文檔解析器和XML文件物件模型,因此不需自己處理XML文檔,只需調用標準庫載入XML文件物件模型,然後按照一一對應的關係來產生設計文件物件模型。
- 使用XML文檔有利於保持設計器的各個版本間的相容性。只要XML文檔結構不發生大變化,低版本的設計器可以載入高版本的設計器產生的文檔,同樣高版本的設計器也很容易載入低版本的設計器產生的文檔。若使用二進位檔案格式,則設計器需要編寫對於不同版本的設計文檔的前置處理器,比較麻煩而且很難做到向上相容。
在儲存對象資料到XML文檔時,儲存方式有兩種,儲存到XML屬性和儲存到XML元素。當指定某個XML元素用於儲存對象資料時,若使用儲存到XML屬性時,會對對象每一個屬性,將其資料儲存到指定名稱的XML屬性中,而儲存到XML元素時,會在當前的XML節點下新增一個指定名稱的XML子項目。然後將屬性值儲存到XML子項目中。這兩種方式產生的XML片斷為
<element attributename1="value1" attributename2="value2" />
和
<element >
<attributename1>value1</attributename1>
<attributename2>value2</attributename2>
</element>
面對這兩種方式,我建議選擇第二種,其原因有
- 若儲存到XML屬性,則當對象屬性比較多是,使用縮排方式輸出的XML文檔將比較寬,在查看是會出現橫向捲軸,不利於閱讀。而儲存到XML元素時,XML文檔不會很寬,便於閱讀。
- 若多行文本儲存到XML屬性,則一般不會以多行文本的方式儲存,不利於閱讀。而儲存到XML元素時,則儲存的文本和實際的文本比較接近,便於閱讀。
- 若儲存到XML屬性,則儲存方式只能是一個屬性字串,而儲存到XML元素時則儲存的方式很容易進行擴充。
- 雖然儲存到XML屬性方式產生的XML文檔比儲存為XML元素的方式要小,但XML文檔格式的設計目標是方便儲存資料和交換資料,而不在乎文檔是否冗餘,因此我們選擇儲存方式時不必在乎XML文檔的大小。而且一般設計文檔的內容不很多,以目前電腦硬體條件無須在意XML文檔大小。
當設計器從XML文檔載入設計文檔時, 首先產生XML文檔對象樹, 然後根據一一對應的關係來產生設計文檔對象樹,此時需要從XML元素儲存的資訊來判斷該XML元素是對應於那種設計文件項目,設計器可以從XML元素名稱來判斷,也可以從某個XML屬性來判斷,在此我使用XML元素名稱來判斷,首先是針對一個XML元素,獲得其名稱比獲得某個屬性值要方便,其次是XML名稱是必然存在的,肯定不為空白,而XML屬性則可能由於某種原因而缺失,XML名稱比XML屬性要穩定。
基於上述的認識,當採用XML文檔作為儲存方式時,設計基礎元素需要定義兩個虛函數,一個用於從XML文檔載入對象屬性資料,另一個要向XML文檔儲存對象資料。而其他文件項目對象則根據需要重載這兩個函數來實現自己的載入和儲存對象屬性的操作,對於容器元素,還需要儲存子項目資料到XML文檔和從XML文檔載入子項目。當然在實際應用中還要根據需要定義一些輔助成員來協助載入和儲存XML文檔。
設計器產生的XML文檔一般儲存為檔案形式,當然可以根據需要來儲存的資料庫裡或者上傳到各種伺服器中。若直接儲存到資料庫中,則整個應用系統中所有的設計器編輯的都是同一個文檔版本,而且一旦儲存便可立即應用。
使用者介面相關的介面
設計器需要繪製文檔視圖,則需要設計文件物件模型提供支援。因此文檔基本元素需要定義兩類通用介面,一個是和繪製文檔相關的介面,一個是處理滑鼠鍵盤事件相關的介面。
繪製文檔相關介面
大部分文件項目需要在文檔視圖中繪製內容,因此它們需要重載繪製文檔的介面,這類介面主要有兩個函數,一個是計算元素大小的函數,一般命名為 RefreshSize , 一個是繪製元素的函數,一般命名為RefreshView。
一般設計者指定元素的大小,元素本身不需要計算其大小,但某些元素可能是根據其內容自動化佈建大小,因此需要重載計算元素大小的函數RefreshSize來自動化佈建大小。自動化佈建大小可能只是設定元素的寬度或高度,也可能是同時設定其寬度和高度。同一個元素,可能在一種狀態下不會自動化佈建大小,而在另外一種狀態下需要自動化佈建大小。所有的這些操作都需要在RefreshSize函數中完成。
一般的設計項目都需要在文檔視圖中繪製內容,這時需要重載RefreshView函數,這個函數參數包含了一個System.Drawing.Graphics對象,元素需要使用這個Graphics對象來繪製自己特定的內容,可能是繪製文本,圖片或其他圖形。
當所有的文件項目都實現了繪製文檔相當的介面,則在設計器的調度下,一個完整的設計文檔視圖就繪製出來了。而擴充設計器時,若需要指定新顯示樣式的元素時,需要重載RefreshView和RefreshSize函數來實現新的顯示樣式,此時擴充的設計器就能顯示新樣式的文檔視圖。
處理滑鼠鍵盤事件相關介面
設計器中主要處理滑鼠事件,文檔基礎元素可以定義一些處理滑鼠事件的虛函數,名稱可以為 HandleMouseDown , HandleMouseMove 和 HandleMouseUp 。
為了方便文件項目處理滑鼠座標,設計器在調用文件項目的HandleMouse函數時,首先將滑鼠游標座標進行轉換,要將滑鼠游標在視圖地區中的座標轉換為文件項目內部的相對座標,即相對於元素左上方的相對座標。
設計器要依靠滑鼠事件來實現設計項目的拖拽操作以實現互換式設計體驗。關於滑鼠拖拽操作典型的應用就是使用8個控制點來編輯元素邊界。當一個元素邊界是矩形時,會在元素的邊界矩形的四個角和四個邊的中點上分布8個控制點,當滑鼠移動到這8個點時會修改滑鼠游標樣式,當滑鼠游標在某個控制點上時,使用者按下滑鼠按鍵則開始進行滑鼠拖拽操作,拖拽時會顯示一個虛線繪製的邊框,當鬆開滑鼠按鍵則拖拽操作結束,此時設計器修改拖拽的元素的矩形邊界。
某些文件項目並不進行標準的滑鼠拖拽操作,例如對於容器元素,其內部的滑鼠拖拽不移動對象而是畫出一個選取矩形來選擇若干個子物件;對於表格元素,它的表格線上的滑鼠拖拽操作是修改表格行的高度和表格列的寬度;而對於線段則是修改端點位置。
當使用者不小心按下滑鼠按鍵,或只是選擇某個元素而並不想進行滑鼠拖拽操作,此時可以使用一個參數 System.Windows.Forms.SystemInformation.DragSize 來判斷是否進行滑鼠拖拽。當滑鼠按鍵按下時,設計器就鎖定滑鼠,若滑鼠按鍵按下後滑鼠移動距離超出了 DragSize 的範圍時,則表示使用者是想進行滑鼠拖拽操作的,此時開始真正的滑鼠拖拽操作。若滑鼠按鍵從按下到鬆開時滑鼠移動距離始終沒超出 DragSize 的範圍,則表示使用者沒有進行滑鼠拖拽操作的意圖。這樣的判斷可以讓設計器容忍使用者的一些誤操作。
設計器還要處理滑鼠雙擊事件處理,對於某些包含文本的元素,使用者雙擊該元素,則在設計檢視中顯示個文本輸入框來直接編輯對象的常值內容。可以定義一個介面 ILabelEditable , 當使用者雙擊某個元素,設計器發現該元素實現了 ILabelEditable 介面,則在設計檢視中動態顯示一個文本輸入框,然後調用該介面的成員來直接編輯對象常值內容。
維護文檔對象樹
文檔基礎元素要定義不少介面來用於維護文檔對象樹。要定義 OwnerDocument 屬性來指定元素所在的文檔對象,要定義 Parent 屬性來指明元素的父節點,定義 Items 屬性來指明該元素的子項目列表。對於容器元素,還要維護它的子項目列表。
設計文檔對象作為文檔樹的根節點,擔負著維護整個對象樹的重任,包括文檔整體的載入儲存,文檔整體的繪製,遍曆整個對象樹結構入口,還要為指令碼提供介面。它是訪問文檔對象樹的進入點。
一些比較基礎的文件項目類型
可以從文檔基礎元素上派生一些比較基礎的文件項目類型。這些比較基礎的文件項目類型可以包括
矩形元素基礎類型,類型名稱為DesignRectangleElement , 設計文檔中大部分元素的邊界是矩形,因此定義矩形元素基礎類型作為這些矩形類型的元素的共同基礎。矩形元素基礎類型實現了使用8個點的控制點來修改元素位置和大小的能力,滑鼠在對象邊界只那的滑鼠拖拽操作就可移動元素位置。此外還定義了內容和邊界之間的邊距資訊。
線段類型,類型名稱為DesignLineElement, 設計文檔某些元素是以線段方式顯示的,因此定義線段類型作為這些元素類型的基礎類,線段類型定義了兩個端點的位置,線段的顯示樣式,標籤文檔等資訊。此外還重載了滑鼠事件,使得使用者可以使用滑鼠拖拽線段的兩個端點來修改線段端點的座標。此外還要重載命中操作,用於判斷某個座標是否命中線段對象,若指定點距離線段的垂直距離小於某個參數,和點線上段某個端點上的拖拽點中則命中線段,否則沒命中。
容器元素類型,類型名稱為DesignElementContainer , 該元素可以包含若干個子項目,它是從DesignRectangleElement 派生的,因此它的邊界是矩形。滑鼠在容器中的拖拽操作不是移動容器,而是動態繪製一個選取矩形,當完成拖拽操作時,就根據這個選取矩形來設定子項目的選中狀態。根據選取矩形來選擇子項目有兩種方式,一種是,若子項目邊界和選取矩形粘邊就被選中,另一種是,若子項目完全在選取矩形內部時才被選中。容器元素在繪製子項目時就執行矩形覆蓋操作後再調用子項目的RefreshView成員。
帶標題容器元素,類型名稱為 DesignCaptionContainer , 該元素派生自容器元素,可以包含若干個子項目,但它頂端有個標題列,可以顯示文本,使用者使用滑鼠拖拽這個標題列可以修改元素的位置。此外它還實現了 ILabelEditable 介面,當使用者雙擊標題列時可以直接編輯標題列文本。
文本元素,類型名稱為DesignTextElement,很多文件項目只是簡單的顯示常值內容,則定義文本元素作為這些簡單顯示常值內容的元素的共同基礎。它派生自DesignRectangleElement , 此外還實現了 ILabelEditable 介面用於直接編輯常值內容。此外還支援文本輸出角度控制,此時繪製文本時將以元素中心為原點旋轉任意角度進行繪製。文本元素繪製帶角度的文本時需要臨時修改圖形繪製對象Graphics的轉換矩陣來設定繪製角度。
增強文本元素,類型名稱為DesignTextElementExt , 該元素派生自DesignTextElement, 對文本輸出格式進行了強化,它支援行間距和字元間距,此外還進行了文本右邊緣的對齊操作。顯示對於大段文本時,尤其包含中文字元和英文字元,某些程式沒有進行文本右邊緣對齊操作。例如IE,記事本等,這是因為中文字元和英文字元寬度不一樣。每一行文本的內容寬度由於中英字元的個數不一樣,很容易導致文本寬度不一樣,因此當文本左邊緣對齊時,其右邊緣很可能是參差不齊的。但MS Word顯示大段文本時它的文本左右邊緣都是對齊的,它通過在顯示文本時插入額外的使用者難以察覺字元間距來修本文本顯示寬度。增強型文本元素就利用了這個原理來實現文本右邊緣對齊。
表格元素,類型名稱為DesignTableElement,表格元素是一種複雜的容器元素,它包含表格行(DesignTableRowElement),表格列(DesignTableColumnElemetn)和儲存格(DesignTableCellElement)對象,其中儲存格可以進行橫向合并和縱向合并。而表格包含的表格行和儲存格也是容器元素,使用者不能直接修改儲存格的大小位置,而只能調解表格行的高度和表格列的寬度來修改儲存格的大小位置。儲存格也是容器元素,因此儲存格內可以放置若干個子項目。在很多情況下儲存格只是顯示簡單的常值內容,因此儲存格定義了一些用於顯示常值內容的屬性,此外實現了 ILabelEditable 介面來方便直接編輯儲存格常值內容。
圖片元素,類型名稱為 DesignImageElement , 它是從DesignRectangleElement 派生的,用於簡單的顯示一個圖片。由於圖片對象(System.Drawing.Image)使用了未託管資源,因此圖片元素實現了 System.IDisposable 介面。
此外還定義了一些元素,這些元素可以類比繪製Windows基礎控制項,包括文字標籤,按鈕,單選框,複選框,文字框,列表,下列列表,組合框,進度條和表單。可以根據這些元素來很容易的類比出一個表單設計器。
繪製文檔視圖
設計器的主要工作之一就是繪製文檔視圖。其繪製過程一般是
設計器控制項重載它的OnPaint成員或綁定Paint事件。
當作業系統需要重新繪製設計器控制項時會觸發它的Paint事件。
設計器獲得繪製圖形使用的System.Drawing.Graphics對象和一個表示繪製地區的剪下矩形ClipRectangle,然後將其作為參數調用文檔對象的RefreshView函數。
文檔對象進行一個初始化工作,然後遍曆對象樹結構,找到所有和剪下矩形粘邊的文件項目,調用它們的RefreshView函數,讓各個元素繪製各自內容。
當所有工作完畢,則文檔視圖繪製完畢。
設計器繪製文檔是遇到一個難題就是閃爍,當使用者滾動視圖和更新視圖時,使用者介面很容易出現閃爍,過多的閃爍會比較嚴重的影響使用者的使用。關於閃爍的原理我曾經寫過一篇文章討論了一下(點擊查看)。由於設計文檔是比較複雜的文檔,繪製整個文檔視圖工作量大,繪製時間長,因此需要採用各種最佳化來減少繪製時間,減少閃爍。
對於閃爍有一個算是一勞永逸的辦法就是使用雙緩衝技術。在繪製圖形時,首先將圖形繪製到一個記憶體中的BMP圖片上,然後將這個BMP圖片繪製到使用者介面上。這種方法可以最大程度的減少閃爍,而且在.NET中使用雙緩衝也比較簡單。但我不大使用雙緩衝技術,有兩個原因
雙緩衝實際上增加了整個繪製文檔的工作量,延長了繪圖時間。當使用者滾動視圖時,會造成視圖很“沉重”的感覺,使用者介面響應遲鈍。
雙緩衝掩蓋了程式的不足之處。開發人員可以根據閃爍程度來判斷繪圖操作是否需要最佳化,以及最佳化效果。但雙緩衝消滅了閃爍,開發人員也就沒有最佳化繪圖操作的迫切需求,助長了開發人員的懶惰。程式繪製圖形時緩慢不堪,而很難從表面看出問題的可能原因。
其實可以這樣,設計器在開發時不使用雙緩衝,但發布時則使用雙緩衝。
由於設計器採用直角座標方式,因此各個元素間存在相互覆蓋的關係,當存在大面積的覆蓋時,繪製文檔時必需要針對這種情況進行最佳化處理來提高繪製文檔的速度,減少電腦螢幕閃爍。針對覆蓋現象而進行最佳化時可以進行矩形覆蓋操作,對於矩形覆蓋操作,本人有另一篇文章對此進行了說明(點擊查看)。設計器繪製某個元素時,首先針對這個元素進行矩形覆蓋運算,將運算結果作為RefreshView函數的某個參數來傳入,當文件項目內容比較多時,可以根據這個矩形覆蓋運算結果來減少繪製量,提高繪製速度。
設計檢視還應提供縮放顯示功能,可以放大設計檢視來更清楚的顯示細節,可以縮小設計檢視來總體的把握整個文檔。GDI+有個轉換矩陣,可以很容易的實現設計檢視的縮放顯示。但此時所有的滑鼠座標資料都得進行相應的縮放處理。
設計檢視控制項
設計檢視控制項是設計器在使用者介面上的展示介面。它是一個標準的Windows控制項,該控制項派生自System.Windows.Form.UserControl。使用者使用滑鼠和鍵盤在這個控制項裡面編輯文檔,它重載了OnMouseDown , OnMouseMove 和 OnMouseUp 成員,對滑鼠訊息進行了一下封裝後供設計文檔對象使用。重載了OnPaint 成員來更新文檔視圖。重載了 OnDoubleClick 來進行試圖直接編輯文件項目的常值內容。
當使用者佈建某個元素為當前元素,則設計檢視控制項將根據需要來進行滾動以便當前元素出現在可視地區中。若當前元素大小小於可視地區大小,則處理比較簡單,只要根據可視地區大小和元素在視圖中的位置就可計算滾動位置。若元素寬度或高度大於可視地區的寬度和高度,則需要進行額外的判斷,以避免滾動時發生跳躍。
鷹眼技術
一個好的設計器應當支援鷹眼技術,所謂鷹眼,通俗的講就是小地圖,它一般放置在程式介面的某個角落,它的面積不大,主要功能是讓人瞥上一眼就能大體瞭解整個文檔的結構,並能通過滑鼠點擊快速的滾動文檔。關於鷹眼,本人寫過一個文章專門討論了它(點擊查看).
總結
使用方便的所見即所得 (WYSIWYG)的設計器是一個複雜的程式,需要豐富的相關開發經驗,它涉及到圖形化,文件物件模型以及其他各種編程技術,是一個多種編程技術的有機混合,通常需要編寫數萬行的代碼才能實現。因此其技術門檻比較高,一般的小公司沒有能力完成,即使有些公司有實力開發,那也要花數月的時間,有可能影響公司正常的項目開發。但隨著各種資訊系統越來越靈活,它們必須配備良好的設計器,若有一個使用方便功能強大的設計器,則處理這種系統配置是事半功倍的,因此很多開發人員都不得不面對開發設計器這個技術難題。
有鑒於此,XDesigner軟體工作室憑著自身豐富的設計器開發經驗開發了XDesignerLib,一個設計器中介軟體,也就是一個設計器的半成品,這個中介軟體實現了所見即所得 (WYSIWYG)的設計器的全部基礎,並提供了非常充分的擴充介面.開發人員瞭解了XDesignerLib以後就可以僅僅編寫比較簡單的幾千行代碼就能實現一個功能強大的設計器。藉助XDesignerLib,開發人員不必處理非常繁瑣的底層細節,只需瞭解XDesignerLib的介面,擴充它就行了。實事上XDesigner工作室已經開發的各種設計器都是基於XDesignerLib的。關於XDesigner軟體工作室和XDesignerLib,請訪問 http://www.xdesigner.cn .
XDesigner軟體工作室 2006-8-21