动态载入数据的无刷新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方法实现为:
  TreeNode.prototype.SetChecked  =   function (isCheck)
 {
    
var  innerCache  =   this .m_Tree.m_InnerCache;
    
if  ( isCheck )
    {
        
if  (  ! innerCache.m_Checkeds.Contains( this ) ) 
        {
            innerCache.m_Checkeds.Add(
this );
        }
    }
    
else
    {
        innerCache.m_Checkeds.Remove(
this );
    }    
    
this .m_Checked  =  isCheck;
    
this .ApplyUIChange();
 };

 TreeNode.prototype.SetSelected 
=   function (isSelected)
 {
    
var  innerCache  =   this .m_Tree.m_InnerCache;
    
if  ( isSelected )
    {
        
if  (  ! innerCache.m_Selecteds.Contains( this ) ) 
        {
             innerCache.m_Selecteds.Add(
this );
        }
    }
    
else
    {
        innerCache.m_Selecteds.Remove(
this );
    }    
    
this .m_Selected  =  isSelected;
    
this .ApplyUIChange();
 };

    它们只负责维护 控件对象的属性状态,所有的控件的UI相关操作交由 this.ApplyUIChange()去处理。这个设计也和WinForm控件中修改属性后的显示调用Invalidate()的设计类似,一切的UI更新都在OnPaint中做。innerCache相关操作在这里不用关心,那是用来记录TreeView实例中被Checked和Selected的Nodes用的,以后再讲。

    ApplyUIChange代码实现如下:
  TreeNodeBase.prototype.ApplyUIChange  =   function ()
 {
     
if  (  this .m_Element.CheckBox )
     {
         
this .m_Element.CheckBox.checked  =   this .m_Checked;
     } 
     
var  elmtNode  =   this .m_Element.Content;
     
if  (  this .m_Selected )
     {
         elmtNode.style.color 
=   this .Styles('SelectedForeColor');
         elmtNode.style.background 
=   this .Styles('SelectedBackColor');
     }
     
else
     {
         
if  (  this .m_Checked )
         {
             elmtNode.style.color 
=   this .Styles('CheckedForeColor');
             elmtNode.style.background 
=   this .Styles('CheckedBackColor');
         }
         
else
         {    
             elmtNode.style.color 
=   this .Styles('NormalForeColor');
             elmtNode.style.background 
=   this .Styles('NormalBackColor');
         }
     }
     
if  (  this .m_IsActive )
     {
         elmtNode.runtimeStyle.textDecoration 
=  'underline';
     }
     
else
     {
         elmtNode.runtimeStyle.textDecoration  
=  '';
     }
 };

    在这个方法中,它只用关心属性间的优先级和对UI元素属性的修改,同时这也是程序中唯一修改HTML元素属性的地方。不过本控件中Node的子树的Expand和Collapse的UI元素属性更新没有放在这里,这时因为放在它们独自的方法中也很清晰(不存在和其它UI显示冲突的问题)。也就是说我们虽然有设计原则,不过有时可以使用别的简便方法实现时,也不用太拘泥于原则。设计本身就是妥协,而且我们实际需要的就是简便清晰的实现,而不是要完美的原则。
    
    附各中TreeView的外观样式变化:
    TreeView-3.gif

    to be continued . . .

你可能感兴趣的:(treeview)