NFace TreeViewer 和ListViewer(JFace Viewer在.Net中的簡單實現)

zerostone發表於2006-08-31

  NFace的簡單實現

如果您熟悉JFace,那麼你最大的感觸是什麼?優良的設計框架?精簡易用的API?簡單方便的資料繫結?
以前做基於Eclipse RCP開發的時候,我被JFace的易用和思想吸引,感覺很優雅。JFace中的UI元件十分豐富,功能很多,今天想談談如何在.NET中實現其中的一兩個元件,也算是我技術BLOG開篇之作。對於.NET中TreeView的DataBinding,我很不喜歡,於是想到模仿JFace TreeViewer的介面寫一個.NET版本的NFace TreeViewer,另外將JFace TableViewer實現為NFace ListViewer。但這裡只說說TreeViewer的實現,ListViewer的思想是相同的。


一、首先看一下這兩個元件的類圖,懶得用建模畫UML了,下圖用VS2005自帶的ClassDiagram工具生成:
1.首先是CTreeViewer的類圖


1.1       CTreeNode繼承於TreeNode類
 

成員
說明
Data
用於存放業務資料(通常是實體類的例項),這樣,可以方便的在使用者點選樹上節點時,取得相應業務資料。
HasGotChildren
是否已經取得過子節點。
IsBlankNode
是否時空節點,空節點是看不到的節點,僅僅用於生成節點上的展開加號,這樣,當某個節點未展開時,其下有一個空節點,那麼就會形成加號。
NeedRefresh
節點是否需要重新整理。
CTreeNode(bool isBlankNode)
用是否空節點構造一個節點
CTreeNode(object obj)
用業務資料構造一個節點
CTreeNode(string text, object obj)
用節點顯示文字和業務資料構造一個節點
 
1.2          ITreeViewLabelProvider,CTreeViewer的顯示提供器
 

成員
說明
GetImageIndex(object obj)
獲取樹節點文字前的影象索引號
GetLabel(object obj)
獲取樹節點顯示的字串
GetSelectedImageIndex(object obj)
獲取樹節點被選中時文字前的影象索引號
 
1.3          ITreeViewContentProvider,CTreeViewer的內容提供器
 

成員
說明
GetElements()
獲根節點物件(可以有多個根節點)
GetElements(object obj)
獲取obj節點下的子節點
HasChildren(object obj)
判斷obj節點下是否有子節點
 
1.4          CTreeViewer類,繼承於TreeView
 

成員
說明
ContentProvider
CTreeViewer的內容提供器
LabelProvider
CTreeViewer的顯示提供器
GetChildrenWhenExpand
是否在展開樹節點是獲取其子節點,該屬性影響效能,設定為True時,節點展開時只獲取當前層的資料;設定為False時,每次展開一個節點不光獲取當前層的資料,也同時獲取當前層所有節點的子節點的資料(也就是每次展開一個節點獲取兩層節點資料)
ExpandToLevel(int)
展開樹到指定層
ExpandToLevelByThread(int)
展開樹到指定層(執行緒中完成)
RefreshOnlyOneNode(CTreeNode)
重新整理某個節點
OnAfterExpand(TreeViewEventArgs)
過載TreeView的展開後方法,完成獲取子節點,構造樹的工作
ShowTree()
根據給定的內容提供器和顯示提供器,構造顯示樹內容
 
 
2.然後是NFace ListViewer的類圖:


對於CListViewer的類圖不再作詳細解釋,類似CTreeViewer。
 
二、思想
實現IContentProvider和ILabelProvider後,CTreeViewer根據實現該介面的類例項來自動構造一顆樹,ContentProvider提供樹節點資料(後臺業務資料)以及資料之間的關係(父子節點關係),LabelProvider定義如何顯示樹節點(節點的圖示、文字內容)。
 
三、用法
這裡舉一個簡單的例子,將地區資訊顯示成一顆樹。該例中資料從XML讀取:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  
<District>
    
<ID>0</ID>
    
<Name>中國</Name>
    
<ParentID>-1</ParentID>
    
<IsLeave>false</IsLeave>
  
</District>
  
<District>
    
<ID>1</ID>
    
<Name>美國</Name>
    
<ParentID>-1</ParentID>
    
<IsLeave>false</IsLeave>
  
</District>
  
<District>
    
<ID>2</ID>
    
<Name>日本</Name>
    
<ParentID>-1</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>3</ID>
    
<Name>韓國</Name>
    
<ParentID>-1</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>4</ID>
    
<Name>北京</Name>
    
<ParentID>0</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>5</ID>
    
<Name>上海</Name>
    
<ParentID>0</ParentID>
    
<IsLeave>false</IsLeave>
  
</District>
  
<District>
    
<ID>6</ID>
    
<Name>杭州</Name>
    
<ParentID>0</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>7</ID>
    
<Name>浦東新區</Name>
    
<ParentID>5</ParentID>
    
<IsLeave>false</IsLeave>
  
</District>
  
<District>
    
<ID>8</ID>
    
<Name>徐彙區</Name>
    
<ParentID>5</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>9</ID>
    
<Name>楊浦區</Name>
    
<ParentID>5</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>10</ID>
    
<Name>合慶鎮</Name>
    
<ParentID>7</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>11</ID>
    
<Name>張江鎮</Name>
    
<ParentID>7</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>12</ID>
    
<Name>川沙鎮</Name>
    
<ParentID>7</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
  
<District>
    
<ID>13</ID>
    
<Name>加州</Name>
    
<ParentID>1</ParentID>
    
<IsLeave>true</IsLeave>
  
</District>
</NewDataSet>

簡單說明一下:ID是某個地區的ID號,Name是地區名字,ParentID是上級地區的ID號,IsLeave表示是否是葉子地區(其下沒有子地區)。

3.1 新建一個WinForm程式,引入IZero.NFace.dll,在視窗上拖放一個CTreeViewer元件,取名為ctv。

3.2 實現一個ContentProvider
class ContentProvider : IZero.NFace.CTreeView.ITreeViewContentProvider 
        
{
            
private DataSet ds;

            
public ContentProvider(DataSet ds)
            
{
                
this.ds =( ds == null ? new DataSet() : ds);  //這裡資料集從建構函式傳入
            }


            
ITreeViewContentProvider 成員
        }

3.3 實現一個LabelProvider
   class LabelProvider : IZero.NFace.CTreeView.ITreeViewLabelProvider
        
{
            
ITreeViewLabelProvider 成員
        }


3.4 在FormLoad事件裡,載入XML檔案到一個DataSet,以便待會兒傳入ContentProvider,並且對CTreeViewer的內容提供器和顯示提供器設定提供器。
 private void FrmTest_Load(object sender, EventArgs e)
        
{          
            DataSet ds 
= new DataSet();
            
try
            
{
                ds.ReadXml(
"TestData.xml");
                
                
this.ctv.ContentProvider = new ContentProvider(ds);
                
this.ctv.LabelProvider = new LabelProvider();
                
this.ctv.GetChildrenWhenExpand = true;  //Default is true
            }

            
catch (Exception err)
            
{
                MessageBox.Show(err.Message);
            }

        }


3.5 在視窗上放一個顯示按鈕,在其單擊事件中,呼叫CTreeViewer的ShowTree()方法即可。


四、效果圖



今天先寫到這裡,關於CListViewer和CTreeViewer的使用,將會在後續篇幅中用到(可能是一個簡單的資料庫瀏覽器)。由於第一次寫技術BLOG,經驗不足,敬請諒解。


NFace原始碼和示例程式 下載地址: 目前似乎還不能上傳除圖片外的資源,不清楚是否支援。如果您想要原始碼和示例程式,請留下email,我會通過郵件傳送。


相關文章