• Discuz!NT控件剖析 之 Tab 属性页 [原创: 附源码]


             继上篇文章之后(链接),大家给了一些反馈和意见,有些我已动手进行了部分修改,将会在2.0版本中提供给大家。希望大家能
    继续支持我们这个开源项目。

             好了,开始今天的话题,今天就说一下 Tab 控件。

            先贴一张运行效果图让大家看一下:
        
           

       

             开发动机:在去年开发后台功能时,最早使用的是ComponentArt控件库。相信园子里有不少人都用过这个商业控件库。在beta1版
    正式发布后,才有时间将这个库中的控件一个一个的替除出来,其中就有tabs 控件。因为必定是商业控件,所以还是自己设计开发的
    用着踏实。
             今天这个下载包中的控件代码可是全新,这些代码如果不出意外的话,将会随同2.0版本一起发布出去。同时为了使用方便,我将
    一些样式部分的代码单拿出来(因为2.0版本中样式表采用继承的方式进行设计)。现在就按下载包中的文件逐一给大家做一下说明:

              在Discuz.Controls项目中的admin/tab/目录下有下面一些文件
        
              TabControl.cs  : tab控件的主体类,主要负责前端UI代码的生成,事件订制,子控件生成等
              TabControlDesigner.cs :顾名思义,这里对TabControl控件进行设计时支持的类
              TabEditorForm.cs : 对tab控件中的属性页进行添加,修改,删除进行可视化支持的窗体类
              TabEditor.cs : 对在TabEditorForm窗体中操作的数据保存到设计时页面进行支持
        
              TabPage.cs : 属性页控件类,作为TabControl的子控件进行显示其中的内容并进行相关属性绑定
              TabPageCollection.cs : 将TabPage类实例以数据集合形式提供给TabControl的ITEM属性
       
       
       
              现在大家就应该对整个控件有一个大概了解了吧!
       
              那么现在就对这几个文件中的关键代码作一下概述:
       
              TabControl.cs 中的服务器端事件处理,定义及其postback过程处理如下
        
       

     1  private static readonly object TabSelectedIndexChangedEvent;
     2 
     3     public event EventHandler TabSelectedIndexChanged
     4     {
     5             add
     6             {
     7                 base.Events.AddHandler(TabControl.TabSelectedIndexChangedEvent, value);
     8             }
     9             remove
    10             {
    11                 base.Events.RemoveHandler(TabControl.TabSelectedIndexChangedEvent, value);
    12             }
    13     }
    14     
    15     protected void OnTabSelectedIndexChanged(EventArgs e)
    16     {
    17             if (base.Events != null)
    18             {
    19                 EventHandler handler1 = (EventHandler)base.Events[TabSelectedIndexChangedEvent];
    20                 if (handler1 != null)
    21                 {
    22                     handler1(this, e);
    23                 }
    24             }
    25     }
    26     
    27     void IPostBackDataHandler.RaisePostDataChangedEvent()
    28     {
    29          this.OnTabSelectedIndexChanged(EventArgs.Empty);
    30     }
    31 
    32 

        
             其余主要属性参见注释代码:
        
        

     1 //当选定某一属性页索引值时
     2     public int SelectedIndex
     3     {
     4             get
     5             {
     6                 if (this.Items.Count <= 0)
     7                 {
     8                     return (this._SelectedIndex = -1);
     9                 }
    10                 if (this._SelectedIndex == -1)
    11                 {
    12                     for (int i = 0; i < this.Items.Count; i++)
    13                     {
    14                         
    15                 
    16                 return this._SelectedIndex;
    17             }
    18             set
    19             {
    20                 if ((value < -1|| (value >= this.Items.Count))
    21                 {
    22                     throw new ArgumentOutOfRangeException("选项页必须小于" + this.Items.Count.ToString());
    23                 }
    24                 this._SelectedIndex = value;
    25             }
    26      }
    27     
    28     
    29     [Description("顶部属性页标题距左边偏移量"), DefaultValue(0)]
    30     public int LeftOffSetX
    31     {
    32             get
    33             {
    34                 object obj = ViewState["LeftOffSetX"];
    35                 return obj == null ? 0 : Convert.ToInt32(obj.ToString());
    36             }
    37             set
    38             {
    39                 ViewState["LeftOffSetX"= value;
    40             }
    41     }
    42 

        
              这个控件的render函数实现逻辑很清楚,这里就不多说了,大家可以去看一下相关代码就行了。
       
       
              TabControlDesigner.cs 文件的源码如下(请看一下注释即可):
        
        

     1 public class TabControlDesigner : ControlDesigner
     2     {
     3         protected override string GetEmptyDesignTimeHtml()
     4         {
     5             return CreatePlaceHolderDesignTimeHtml("右击选择创建新的属性页");
     6         }
     7         
     8         private DesignerVerbCollection _verbs;
     9 
    10         //定义处理的动作
    11         public override DesignerVerbCollection Verbs
    12         {
    13             get
    14             {
    15                 if (_verbs == null)
    16                 {
    17                     _verbs = new DesignerVerbCollection(new DesignerVerb[] { new DesignerVerb("创建新的属性页"new EventHandler(this.OnBuildTabStrip)) });
    18                 }
    19 
    20                 return _verbs;
    21             }
    22         }
    23 
    24 
    25   //处理动作要运行的操作,这里是显示TabEditorForm窗体
    26         private void OnBuildTabStrip(object sender, EventArgs e)
    27         {
    28             TabEditor oEditor = new TabEditor();
    29             oEditor.EditComponent(this.Component);
    30         }
    31 
    32         //得到设计时Html代码
    33         public override string GetDesignTimeHtml()
    34         {
    35 
    36             try
    37             {
    38                 TabControl oTabStrip = ((TabControl)Component);
    39 
    40                 if (oTabStrip.Items == null || oTabStrip.Items.Count == 0)
    41                 {
    42                     return GetEmptyDesignTimeHtml();
    43                 }
    44 
    45                 System.Text.StringBuilder oSB = new System.Text.StringBuilder();
    46                 StringWriter oStringWriter = new StringWriter(oSB);
    47                 HtmlTextWriter oWriter = new HtmlTextWriter(oStringWriter);
    48 
    49                 oTabStrip.RenderDownLevelContent(oWriter);
    50                 oWriter.Flush();
    51                 oStringWriter.Flush();
    52 
    53                 return oSB.ToString();
    54             }
    55             catch (Exception ex)
    56             {
    57                 return CreatePlaceHolderDesignTimeHtml("生成设计时代码错误:\n\n" + ex.ToString());
    58             }
    59         }
    60      }
    61      
    62 
    63 

         
         TabEditor.cs文件的内容主要是用于对操作数据绑定到相关的web设计页面。
         相关主要代码如下:
        

     1  internal class TabEditor : WindowsFormsComponentEditor
     2     {
     3         public override bool EditComponent(ITypeDescriptorContext context, object component, IWin32Window owner)
     4         {
     5             TabControl oControl = (TabControl)component;
     6             IServiceProvider site = oControl.Site;
     7             IComponentChangeService changeService = null;
     8 
     9             DesignerTransaction transaction = null;
    10             bool changed = false;
    11 
    12             try
    13             {
    14                 if (site != null)
    15                 {
    16                     IDesignerHost designerHost = (IDesignerHost)site.GetService(typeof(IDesignerHost));
    17                     transaction = designerHost.CreateTransaction("BuildTabStrip");
    18 
    19                     changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
    20                     if (changeService != null)
    21                     {
    22                         try
    23                         {
    24                             changeService.OnComponentChanging(component, null);
    25                         }
    26                         catch (CheckoutException ex)
    27                         {
    28                             if (ex == CheckoutException.Canceled)
    29                                 return false;
    30                             throw ex;
    31                         }
    32                     }
    33                 }
    34 
    35                 try
    36                 {
    37                     TabEditorForm oEditorForm = new TabEditorForm(oControl);
    38                     if (oEditorForm.ShowDialog(owner) == DialogResult.OK)
    39                     {
    40                         changed = true;
    41                     }
    42                 }
    43                 finally
    44                 {
    45                     if (changed && changeService != null)
    46                     {
    47                         changeService.OnComponentChanged(oControl, nullnullnull);
    48                     }
    49                 }
    50             }
    51             finally
    52             {
    53                 if (transaction != null)
    54                 {
    55                     if (changed)
    56                     {
    57                         transaction.Commit();
    58                     }
    59                     else
    60                     {
    61                         transaction.Cancel();
    62                     }
    63                 }
    64             }
    65 
    66             return changed;
    67         }
    68     }
    69 
    70 

        
        这块功能的注释因为开发时间问题,以后会加进去,但这些代码因为存在很大的通用性,所以大家可以用在自己的控件设计中:)
        
        TabEditorForm.cs 这个窗体运行时的效果如下:


       
                里面的代码很好理解,这里就不多说什么了。
       
                其余的TabPage.cs,和TabPageCollection.cs文件都是相对简单的设计,其中主要看一下TabPage类中的Render函数即可
       
       
                下面再将相关的JS贴上,以便大家进行对照: 

     

      1 function tabpage_mouseover(e)
      2 {
      3     if(e.className == "CurrentTabSelect")
      4  {
      5   return ;
      6  }
      7  
      8  if(e.className != "OnTabSelect")
      9  {
     10   e.className = "OnTabSelect";
     11  }
     12 }
     13 
     14 function tabpage_mouseout(e)
     15 {
     16     if(e.className == "CurrentTabSelect")
     17  {
     18   return ;
     19  }
     20  if(e.className != "TabSelect")
     21  {
     22   e.className = "TabSelect";
     23     }
     24 }
     25 
     26 function tabpage_selectonserver(e,tabpageid)
     27 {
     28  e.parentNode.parentNode.childNodes[0].value = tabpageid;
     29 }
     30 
     31 function tabpage_selectonclient(e,tabpageid)
     32 {
     33  tabdiv = e.parentNode;
     34  
     35  var tabpagediv = getElementsByClassName('tab-page','div',document);
     36     var tabareas = getElementsByClassName('tabarea','div',document);
     37   
     38  for(i=0;i<tabdiv.childNodes.length;i++)
     39  {  
     40   tabdiv.childNodes[i].className = "TabSelect";
     41   tabdiv.childNodes[i].childNodes[0].className = "";
     42  }
     43    
     44  for(i=0;i<tabpagediv.length;i++)
     45  {
     46   if(tabpagediv[i].id.indexOf(e.id.split(':')[0])>=0)
     47      {
     48    tabpagediv[i].style.display = "none";
     49   }
     50     }
     51     
     52     //对当前结点的子结点(所有)设置属性
     53     for(i=0;i<tabareas.length;i++)
     54  {
     55         if(tabareas[i].id.indexOf(e.id.replace('_li',''))>=0)
     56      {
     57        tabareas[i].style.display = "block";
     58        tabareas[i].childNodes[0].style.display = 'block';
     59      }
     60     }
     61    
     62     //对当前结点的父节点(所有)设置属性
     63     var parentnode = document.getElementById(tabpageid);
     64     while(true)
     65     {
     66         parentnode = parentnode.parentNode;
     67         
     68         if(parentnode == null)
     69         {   
     70             break;
     71         }
     72        
     73         if((parentnode.className =="tab-page")||(parentnode.className =="tabarea"))
     74         {
     75             parentnode.style.display = 'block';
     76         }
     77     }
     78     
     79   document.getElementById(tabpageid).style.display = 'block';
     80  document.getElementById(tabpageid+"_li").className = 'CurrentTabSelect';
     81  document.getElementById(tabpageid+"_li").childNodes[0].className="current";
     82 }
     83 
     84 
     85 function getElementsByClassName(strClassName, strTagName, oElm)
     86 {
     87     var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
     88     var arrReturnElements = new Array();
     89     strClassName = strClassName.replace(/\-/g, "\\-");
     90     var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
     91     var oElement;
     92     for(var i=0; i<arrElements.length; i++){
     93         oElement = arrElements[i];      
     94         if(oRegExp.test(oElement.className)){
     95             arrReturnElements.push(oElement);
     96         }   
     97     }
     98     return (arrReturnElements)
     99 }
    100 
    101 


               好了,主要是东西就先交待到这里了。如果大家有什么问题或建议,欢迎与我交流,我的邮箱是:
               daizhj@gmail.com,
    daizhj617595@126.com 


                源码:点击下载


               本系列上一篇文件链接:
             Discuz!NT控件剖析 之 TextBox [原创: 附源码] http://www.cnblogs.com/daizhj/archive/2007/08/09/849041.html

     

  • 相关阅读:
    shell脚本按当前日期输出日志
    bat弹出确认或取消窗口
    bat脚本输出日志
    北京浩赢科技有限公司与好宝多多
    bat延迟执行脚本,利用choice实现定时执行功能
    centos下安装tunctl
    OpenStack Train版 简单部署流程(4)- octavia
    LVM基础
    OpenStack Train版 简单部署流程(3)- ceilometer
    openstack stein
  • 原文地址:https://www.cnblogs.com/daizhj/p/864281.html
Copyright © 2020-2023  润新知