65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Microsoft Web TreeView 控件创建高度可管理的 TreeView 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.46/5 (11投票s)

2005年6月21日

CPOL

4分钟阅读

viewsIcon

147115

downloadIcon

3717

一篇关于如何实现可管理的树形结构的文章。

引言

我们都知道 Microsoft Management Console (MMC) 的强大之处。MMC 是 Microsoft 用于管理工具和系统管理工具的标准平台。MMC 允许您使用管理单元,通过同一个标准界面管理 Windows 的甚至其他应用程序的各个部分。本文的目的是在 Web 上提供一个类似 MMC 的界面(我称之为 MMC Web)。MMC Web 代表了对各种管理任务的通用视图,这将使生活更轻松。MMC Web 是建立在一个易于附加的框架上的,它允许用户添加/删除模块,并随着时间的推移以更少的麻烦重用它们。

要求

代码是使用 Microsoft Web TreeView 控件编写的,因此要运行以渲染树的脚本必须放置在正确的位置。脚本在下载的 tools 文件夹中提供。为了确保树形视图正常工作,您需要做的就是将 webctrl_client 文件夹复制到您的 IIS wwwroot 目录。

使用代码

现在,假设我们要表示一个简单的组织层次结构。为了更深入地了解,假设有一个公司,其下有部门,而每个部门又由一些科组成。更技术性地说,有三个实体:公司、部门和科,其中部门是公司的子级,科是部门的子级。现在,要在树中实现这种结构,最简单的步骤是:

  1. 实现 IProvider 接口:创建特定于对象的提供程序类(例如 CompanyProvider)。这些类将负责从数据源为特定 ID 获取数据。ID 将由框架根据 XML 架构中定义的层次结构在内部提供。
  2. 实现 IRenderer 接口:创建特定于对象的渲染器类(例如 CompanyRenderer)。这些类将为树提供渲染选项,例如树将如何渲染。
  3. 构建一个 XML,它将定义对象之间的关系及其行为类型。

    XML 格式如下所示

    <company assembly="TreeView.Objects" 
             provider="TreeView.Objects.Provider.CompanyProvider" 
             renderer="TreeView.Objects.Renderer.CompanyRenderer" 
             expanded = "true" >
        <department assembly="TreeView.Objects" 
               provider="TreeView.Objects.Provider.DepartmentProvider" 
               renderer="TreeView.Objects.Renderer.DepartmentRenderer" 
               expanded = "true" >
           <section assembly="TreeView.Objects" 
                provider="TreeView.Objects.Provider.SectionProvider" 
                renderer="TreeView.Objects.Renderer.SectionRenderer" 
                expanded = "false"/>
        </department>
    </company >

    每个 XML 节点包含几个属性,它们是

    1. assembly
      • 定义了渲染器、提供程序和对象可以找到的位置。
    2. 提供商
      • 定义了提供程序类的对象类型。
    3. renderer
      • 定义了渲染器类的对象类型。
    4. expanded
      • 定义了树节点的状​​态。

    所有这些属性都用于从 XML 动态构建对象模型。

  4. 最后,我们需要将 ExtendedTreeView 控件(神奇的控件)拖到一个网页上,并在页面加载时调用 LoadXml 函数,并提供正确的服务器路径。

加载完成后,我们需要在每次选择更改时获取正确的实体 ID,使用该 ID,我们将把实体信息加载到树的右侧。在构建过程中,每个树节点 ID 都由一个以 '_' 分隔的 ID 和一个由 treeview 框架格式化的对象名称在内部构建,这解决了我们的问题。在选择时,我们只需要设法从 '.' 分隔的字符串节点 ID 获取正确的树节点对象。

private void treeView_SelectedIndexChange(object sender, 
            Microsoft.Web.UI.WebControls.TreeViewSelectEventArgs e)
{
    // gets the node id in dot separated format.
    _NodeID = e.NewNode;
    // load
    LoadPage( _NodeID );
}

现在,要显示实体详细信息,我们可以创建实体名称的控件(例如:company.ascx)。为了以最统一的方式加载不同的实体,每个控件都需要扩展 BaseControl 类并实现 IHost 接口。该接口将使控件可插入 treeview 框架,因为在每次从节点 ID 的第一部分进行选择更改时,我们都会加载控件,并借助 IHost 接口使用第二部分字符串的实体信息。

private void LoadPage( string nodeID  )
{
    BaseControl control = null;
    // this line does all tricks of geting  real from dot separated node ID
    TreeNode node = treeView.GetNodeFromIndex( nodeID );
    // make the id
    string[] nodeParts =  node.ID.Split( '_' );
    //save the ids
    _PropertyID = Int32.Parse(  nodeParts[ 1 ] );
    _ControlID = nodeParts[ 0 ];

    control = ( BaseControl ) pnlRenderer.FindControl( _ControlID );

    if( control == null )
    {
        // get the control name
        string controlName = "Controls/" + nodeParts [ 0 ] + ".ascx";
        //Control control =  LoadControl( controlName );
        control = ( BaseControl ) LoadControl( controlName );
        control.ID = _ControlID; 

        if ( control != null )
        {
            pnlRenderer.Controls.Clear();
            pnlRenderer.Controls.Add( control );
            // bind the events
            control.PreRender +=new EventHandler(control_PreRender);
            control.OnChange+=new OnChangeEvent(control_OnChange);
        }
    }//if( control == null )

    IHost loader = ( IHost ) control; 
    // load the module
    if ( nodeID != String.Empty )
    {
        loader.LoadTab( _PropertyID );
    }
}

关于框架

到目前为止,我们已经看到,treeview 使用一个简单的 XML 文件来构建其对象模型。现在,让我们更深入地了解一下它是如何真正完成工作的。treeview 框架使用一个名为 extendedTreeView 的控件,该控件构建在 Microsoft Web TreeView 控件之上。它扩展了现有 TreeView 控件的所有功能。此外,它还提供了一个函数,这是以最友好的方式构建树的核心。

public void LoadTree( string ServerPath );

正如您所看到的,该函数需要一个 XML 文件的服务器路径,该文件包含树结构的定义。一旦提供了路径,它就会从 XML 中递归地加载一个对象模型。

部分源代码如下

private Defination FillObject( XmlNode rootNode )
{
    Assembly ass =  Assembly.Load(  rootNode.Attributes["assembly"].Value );

    Defination def = new Defination();
    // create the provider object
    object providerObject = 
      Activator.CreateInstance( ass.GetType( 
      rootNode.Attributes["provider"].Value, true ) );
    def.Provider = ( Interface.IProvider ) providerObject;
    // create the renderer object
    object rendererObject = 
      Activator.CreateInstance( ass.GetType( 
      rootNode.Attributes["renderer"].Value, true ) );
    def.Renderer = ( Interface.IRenderer ) rendererObject;
    // will the node be expanded
    def.IsExpanded = bool.Parse( rootNode.Attributes["expanded"].Value );
    return def; 
}

在它完成从 XML 文件构建对象之后,它会使用该模型来构建树结构。过程是从根节点开始构建树,然后从最高级别向下,直到遇到叶节点。

public void LoadTree( string serverPath )
{
    Schema schema = new Schema( serverPath );
    Defination defination = schema.RootNode;
    ExecuteDef( defination, 0 , null );
}
private void ExecuteDef( Defination defination, 
                         int parentID, TreeNode parentNode  )
{
    IProvider provider = defination.Provider;
    IList list =  provider.GetAll( parentID );
    LoadList( list, defination, parentID, parentNode );
}

private void LoadList( IList list, Defination def, 
                       int parentNodeID, TreeNode parentNode  )
{
    foreach( object obj in list )
    {
        IRenderer renderer = def.Renderer;
        renderer.Set( obj );
        TreeNode node = ConstructNode( renderer, parentNodeID );
        PopulateNode( node, parentNodeID, parentNode );
        if( def.IsExpanded )
        {
            LoadNode( renderer, def, node );
        }
    }// end foreach
}

最后

MMC Web 将通过重用最常见的模块集(例如:密码更改、添加新注册等等)来帮助用户减少代码行数,这些模块已经由其他人编写。因此,它将帮助 ISV 更好地成长。

© . All rights reserved.