天天看點

動态載入資料的無重新整理TreeView控件(4)

  前三天我們把TreeView給顯示出來了,不過光是顯示顯然是不夠的。TreeView的UI還需要根據使用者的各種操作和不同的屬性設定産生不同的效果變化,比如:Actived、Selected、Checked等。下面就來設計并實作TreeView的UI動态更新問題。

對于控件開發,不管是Web上的還是WinForm上,使用滑鼠和鍵盤來觸發的UI更新和使用程式代碼來觸發更新是同等地位的。是以我們在設計中最好不要在事件處理函數裡面去直接的更新控件UI,為什麼呢?因為這樣的更新是單向服務的(雖然可以在程式中去調用HTML元素的事件回調,不過文法上太蹩腳了),當我們需要在程式中去更新控件UI,比如設定Selected狀态,就需要再寫一套代碼來從程式的角度去更新UI元素的屬性。這時我們會發現前面那種單向服務的代碼,其實是完全可以被後者包括(在功能上)的。繼續說Selected,當我們用滑鼠點選TreeNode時,我們可以從事件響應代碼中直接拿到event.srcElement(這就是顯示TreeNode的HTML元素),我們如果在此時修改這個元素的屬性來顯示Selected狀态,很容易。可是如果我們還需要在程式中去調用TreeNode.SetSelected(true)來得到Selected效果時,前面所說的單向服務的代碼就都被後者(SetSelected)包含了。

哦,那麼我們就實作n個方法,比如:SetActived(bool)、SetSelected(bool)、SetChecked(bool),在這些方法中去分别修改控件UI元素屬性。由于我們在JS控件中,需要在腳本對象和DHMTL對象中來回引用和查找,并且有些狀态的UI的顯示還存在優先級的問題(比如Checked和Selected都需要文字顔色變化,但Selected優先級高于Checked)。是以我們也不在每個SetXXX函數中去更新UI元素的屬性,而是使用一個統一的函數,來對整個控件的UI更新作出處理。于是我們定義了一個ApplyUIChange()函數,在這裡面處理所有和UI呈現有關屬性的處理,并具體修改UI元素的屬性。

    SetXXX方法實作為:

動态載入資料的無重新整理TreeView控件(4)

 TreeNode.prototype.SetChecked = function(isCheck)

動态載入資料的無重新整理TreeView控件(4)

 {

動态載入資料的無重新整理TreeView控件(4)

    var innerCache = this.m_Tree.m_InnerCache;

動态載入資料的無重新整理TreeView控件(4)

    if ( isCheck )

動态載入資料的無重新整理TreeView控件(4)

    {

動态載入資料的無重新整理TreeView控件(4)

        if ( !innerCache.m_Checkeds.Contains(this) ) 

動态載入資料的無重新整理TreeView控件(4)

        {

動态載入資料的無重新整理TreeView控件(4)

            innerCache.m_Checkeds.Add(this);

動态載入資料的無重新整理TreeView控件(4)

        }

動态載入資料的無重新整理TreeView控件(4)

    }

動态載入資料的無重新整理TreeView控件(4)

    else

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

        innerCache.m_Checkeds.Remove(this);

動态載入資料的無重新整理TreeView控件(4)

    }    

動态載入資料的無重新整理TreeView控件(4)

    this.m_Checked = isCheck;

動态載入資料的無重新整理TreeView控件(4)

    this.ApplyUIChange();

動态載入資料的無重新整理TreeView控件(4)

 };

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

 TreeNode.prototype.SetSelected = function(isSelected)

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

    if ( isSelected )

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

        if ( !innerCache.m_Selecteds.Contains(this) ) 

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

             innerCache.m_Selecteds.Add(this);

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

        innerCache.m_Selecteds.Remove(this);

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

    this.m_Selected = isSelected;

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

    它們隻負責維護控件對象的屬性狀态,所有的控件的UI相關操作交由this.ApplyUIChange()去處理。這個設計也和WinForm控件中修改屬性後的顯示調用Invalidate()的設計類似,一切的UI更新都在OnPaint中做。innerCache相關操作在這裡不用關心,那是用來記錄TreeView執行個體中被Checked和Selected的Nodes用的,以後再講。

    ApplyUIChange代碼實作如下:

動态載入資料的無重新整理TreeView控件(4)

 TreeNodeBase.prototype.ApplyUIChange = function()

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

     if ( this.m_Element.CheckBox )

動态載入資料的無重新整理TreeView控件(4)

     {

動态載入資料的無重新整理TreeView控件(4)

         this.m_Element.CheckBox.checked = this.m_Checked;

動态載入資料的無重新整理TreeView控件(4)

     } 

動态載入資料的無重新整理TreeView控件(4)

     var elmtNode = this.m_Element.Content;

動态載入資料的無重新整理TreeView控件(4)

     if ( this.m_Selected )

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

         elmtNode.style.color = this.Styles('SelectedForeColor');

動态載入資料的無重新整理TreeView控件(4)

         elmtNode.style.background = this.Styles('SelectedBackColor');

動态載入資料的無重新整理TreeView控件(4)

     }

動态載入資料的無重新整理TreeView控件(4)

     else

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

         if ( this.m_Checked )

動态載入資料的無重新整理TreeView控件(4)

         {

動态載入資料的無重新整理TreeView控件(4)

             elmtNode.style.color = this.Styles('CheckedForeColor');

動态載入資料的無重新整理TreeView控件(4)

             elmtNode.style.background = this.Styles('CheckedBackColor');

動态載入資料的無重新整理TreeView控件(4)

         }

動态載入資料的無重新整理TreeView控件(4)

         else

動态載入資料的無重新整理TreeView控件(4)

         {    

動态載入資料的無重新整理TreeView控件(4)

             elmtNode.style.color = this.Styles('NormalForeColor');

動态載入資料的無重新整理TreeView控件(4)

             elmtNode.style.background = this.Styles('NormalBackColor');

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

     if ( this.m_IsActive )

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

         elmtNode.runtimeStyle.textDecoration = 'underline';

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

         elmtNode.runtimeStyle.textDecoration  = '';

動态載入資料的無重新整理TreeView控件(4)
動态載入資料的無重新整理TreeView控件(4)

    在這個方法中,它隻用關心屬性間的優先級和對UI元素屬性的修改,同時這也是程式中唯一修改HTML元素屬性的地方。不過本控件中Node的子樹的Expand和Collapse的UI元素屬性更新沒有放在這裡,這時因為放在它們獨自的方法中也很清晰(不存在和其它UI顯示沖突的問題)。也就是說我們雖然有設計原則,不過有時可以使用别的簡便方法實作時,也不用太拘泥于原則。設計本身就是妥協,而且我們實際需要的就是簡便清晰的實作,而不是要完美的原則。

    附各中TreeView的外觀樣式變化:

本文轉自部落格園鳥食軒的部落格,原文連結:http://www.cnblogs.com/birdshome/,如需轉載請自行聯系原部落客。

繼續閱讀