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






4.46/5 (11投票s)
一篇关于如何实现可管理的树形结构的文章。
引言
我们都知道 Microsoft Management Console (MMC) 的强大之处。MMC 是 Microsoft 用于管理工具和系统管理工具的标准平台。MMC 允许您使用管理单元,通过同一个标准界面管理 Windows 的甚至其他应用程序的各个部分。本文的目的是在 Web 上提供一个类似 MMC 的界面(我称之为 MMC Web)。MMC Web 代表了对各种管理任务的通用视图,这将使生活更轻松。MMC Web 是建立在一个易于附加的框架上的,它允许用户添加/删除模块,并随着时间的推移以更少的麻烦重用它们。
要求
代码是使用 Microsoft Web TreeView
控件编写的,因此要运行以渲染树的脚本必须放置在正确的位置。脚本在下载的 tools 文件夹中提供。为了确保树形视图正常工作,您需要做的就是将 webctrl_client 文件夹复制到您的 IIS wwwroot 目录。
使用代码
现在,假设我们要表示一个简单的组织层次结构。为了更深入地了解,假设有一个公司,其下有部门,而每个部门又由一些科组成。更技术性地说,有三个实体:公司、部门和科,其中部门是公司的子级,科是部门的子级。现在,要在树中实现这种结构,最简单的步骤是:
- 实现
IProvider
接口:创建特定于对象的提供程序类(例如CompanyProvider
)。这些类将负责从数据源为特定 ID 获取数据。ID 将由框架根据 XML 架构中定义的层次结构在内部提供。 - 实现
IRenderer
接口:创建特定于对象的渲染器类(例如CompanyRenderer
)。这些类将为树提供渲染选项,例如树将如何渲染。 - 构建一个 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 节点包含几个属性,它们是
assembly
- 定义了渲染器、提供程序和对象可以找到的位置。
提供商
- 定义了提供程序类的对象类型。
renderer
- 定义了渲染器类的对象类型。
expanded
- 定义了树节点的状态。
所有这些属性都用于从 XML 动态构建对象模型。
- 最后,我们需要将
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 更好地成长。