前言 :
ASP.NET 3.5提供了,网页上常使用到的树状选单TreeView。
可是TreeView的数据系结,并没有支持ObjectDataSource。
这篇文章分享如何实做ObjectDataSource,来支持TreeView的数据系结功能。
分析设计 :
TreeView的DataSource只支持实做IHierarchicalDataSource接口的对象。
IHierarchicalDataSource这个看似简单的接口,里面却包含了很多子界面。
将整个IHierarchicalDataSource拆解开来,并且经过分析设计之后的对象图如下 :
每个对象的职责就不赘述了,大多为符合IHierarchicalDataSource所规范的功能而实做。
整个设计比较特别的只有IHierarchicalObjectDataFactory接口。
这个接口其实是多余的,只是为了不让HierarchicalObjectDataEnumerable及HierarchicalObjectData有循环相依。
执行结果 :
使用范例 :
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CLK.Web.UI.WebApplication._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:TreeView ID="TreeView1" runat="server"> <DataBindings> <asp:TreeNodeBinding TextField="Name" ValueField="Id" /> </DataBindings> </asp:TreeView> </div> </form> </body> </html>
namespace CLK.Web.UI.WebApplication
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack == false)
{
List<IHierarchicalObject> demoDataList = new List<IHierarchicalObject>();
demoDataList.Add(new DemoData(null, "AAA", "Id_AAA", "Name_AAA"));
demoDataList.Add(new DemoData(null, "BBB", "Id_BBB", "Name_BBB"));
demoDataList.Add(new DemoData(null, "CCC", "Id_CCC", "Name_CCC"));
demoDataList.Add(new DemoData("BBB", "DDD", "Id_DDD", "Name_DDD"));
demoDataList.Add(new DemoData("DDD", "EEE", "Id_EEE", "Name_EEE"));
demoDataList.Add(new DemoData(null, "FFF", "Id_FFF", "Name_FFF"));
HierarchicalObjectDataSource dataSource = new HierarchicalObjectDataSource(demoDataList);
TreeView1.DataSource = dataSource;
TreeView1.DataBind();
}
}
}
public class DemoData : IHierarchicalObject
{
// Properties
private readonly string _parentPath;
private readonly string _path;
private readonly string _id;
private readonly string _name;
// Construction
public DemoData(string parentPath, string path, string id, string name)
{
#region Require
if (path == null) throw new ArgumentNullException();
if (string.IsNullOrEmpty(id) == true) throw new ArgumentNullException();
if (string.IsNullOrEmpty(name) == true) throw new ArgumentNullException();
#endregion
_parentPath = parentPath;
_path = path;
_id = id;
_name = name;
}
// Member
public string ParentPath
{
get { return _parentPath; }
}
public string Path
{
get { return _path; }
}
public string Id
{
get { return _id; }
}
public string Name
{
get { return _name; }
}
}
}
实作 :
namespace CLK.Web.UI
{
public class HierarchicalObjectDataSource : IHierarchicalDataSource
{
// Properties
private readonly IEnumerable<IHierarchicalObject> _objectEnumerable;
// Construction
public HierarchicalObjectDataSource(IEnumerable<IHierarchicalObject> objectEnumerable)
{
#region Require
if (objectEnumerable == null) throw new ArgumentNullException();
#endregion
_objectEnumerable = objectEnumerable;
}
// Member
public HierarchicalDataSourceView GetHierarchicalView(string viewPath)
{
return new HierarchicalObjectDataSourceView(_objectEnumerable, viewPath);
}
// Event
public event EventHandler DataSourceChanged;
protected void OnDataSourceChanged(object sender, EventArgs e)
{
if (this.DataSourceChanged != null)
{
this.DataSourceChanged(sender, e);
}
}
}
public class HierarchicalObjectDataSourceView : HierarchicalDataSourceView
{
// Properties
private readonly IEnumerable<IHierarchicalObject> _objectEnumerable;
private readonly IHierarchicalObject _currentObject;
private readonly IHierarchicalObjectDataFactory _objectFactory;
// Construction
public HierarchicalObjectDataSourceView(IEnumerable<IHierarchicalObject> objectEnumerable, string path)
{
#region Require
if (objectEnumerable == null) throw new ArgumentNullException();
if (path == null) throw new ArgumentNullException();
#endregion
_objectFactory = new HierarchicalObjectDataFactory();
_objectEnumerable = objectEnumerable;
_currentObject = null;
foreach (IHierarchicalObject currentObject in _objectEnumerable)
{
if (currentObject.Path == path)
{
_currentObject = currentObject;
break;
}
}
}
// Member
public override IHierarchicalEnumerable Select()
{
return _objectFactory.CreateHierarchicalEnumerable(_objectEnumerable, _currentObject);
}
}
public class HierarchicalObjectDataFactory : IHierarchicalObjectDataFactory
{
// Member
public IHierarchicalEnumerable CreateHierarchicalEnumerable(IEnumerable<IHierarchicalObject> objectEnumerable, IHierarchicalObject currentObject)
{
return new HierarchicalObjectDataEnumerable(objectEnumerable, currentObject, this);
}
public IHierarchyData CreateHierarchyData(IEnumerable<IHierarchicalObject> objectEnumerable, IHierarchicalObject currentObject)
{
return new HierarchicalObjectData(objectEnumerable, currentObject, this);
}
}
public interface IHierarchicalObjectDataFactory
{
IHierarchicalEnumerable CreateHierarchicalEnumerable(IEnumerable<IHierarchicalObject> objectEnumerable, IHierarchicalObject currentObject);
IHierarchyData CreateHierarchyData(IEnumerable<IHierarchicalObject> objectEnumerable, IHierarchicalObject currentObject);
}
public class HierarchicalObjectDataEnumerable : IHierarchicalEnumerable
{
// Properties
private readonly IEnumerable<IHierarchicalObject> _objectEnumerable;
private readonly IHierarchicalObject _currentObject;
private readonly IHierarchicalObjectDataFactory _objectFactory;
// Construction
public HierarchicalObjectDataEnumerable(IEnumerable<IHierarchicalObject> objectEnumerable, IHierarchicalObject currentObject, IHierarchicalObjectDataFactory objectFactory)
{
#region Require
if (objectEnumerable == null) throw new ArgumentNullException();
//if (currentObject == null) throw new ArgumentNullException();
if (objectFactory == null) throw new ArgumentNullException();
#endregion
_objectEnumerable = objectEnumerable;
_currentObject = currentObject;
_objectFactory = objectFactory;
}
// Member
public IHierarchyData GetHierarchyData(object enumeratedItem)
{
#region Require
if (enumeratedItem == null) throw new ArgumentNullException();
#endregion
if (enumeratedItem is IHierarchicalObject)
{
return _objectFactory.CreateHierarchyData(_objectEnumerable, enumeratedItem as IHierarchicalObject);
}
return null;
}
public System.Collections.IEnumerator GetEnumerator()
{
return new HierarchicalObjectDataEnumerator(_objectEnumerable.GetEnumerator(), _currentObject);
}
}
public class HierarchicalObjectDataEnumerator : IEnumerator<IHierarchicalObject>
{
// Properties
private readonly IEnumerator<IHierarchicalObject> _objectEnumerator;
private readonly IHierarchicalObject _currentObject;
private IHierarchicalObject _currentChildrenObject = null;
// Construction
public HierarchicalObjectDataEnumerator(IEnumerator<IHierarchicalObject> objectEnumerator, IHierarchicalObject currentObject)
{
#region Require
if (objectEnumerator == null) throw new ArgumentNullException();
//if (currentObject == null) throw new ArgumentNullException();
#endregion
_objectEnumerator = objectEnumerator;
_currentObject = currentObject;
}
public void Dispose()
{
_objectEnumerator.Dispose();
}
// Member
public IHierarchicalObject Current
{
get
{
return _currentChildrenObject;
}
}
object System.Collections.IEnumerator.Current
{
get
{
return this.Current;
}
}
public bool MoveNext()
{
while (_objectEnumerator.MoveNext() == true)
{
if (_currentObject != null)
{
if (_objectEnumerator.Current.ParentPath == _currentObject.Path)
{
_currentChildrenObject = _objectEnumerator.Current;
return true;
}
}
else
{
if (_objectEnumerator.Current.ParentPath == null)
{
_currentChildrenObject = _objectEnumerator.Current;
return true;
}
}
}
_currentChildrenObject = null;
return false;
}
public void Reset()
{
_objectEnumerator.Reset();
_currentChildrenObject = null;
}
}
public class HierarchicalObjectData : IHierarchyData
{
// Properties
private readonly IEnumerable<IHierarchicalObject> _objectEnumerable;
private readonly IHierarchicalObject _currentObject;
private readonly IHierarchicalObjectDataFactory _objectFactory;
// Construction
public HierarchicalObjectData(IEnumerable<IHierarchicalObject> objectEnumerable, IHierarchicalObject currentObject, IHierarchicalObjectDataFactory objectFactory)
{
#region Require
if (objectEnumerable == null) throw new ArgumentNullException();
if (currentObject == null) throw new ArgumentNullException();
if (objectFactory == null) throw new ArgumentNullException();
#endregion
_objectEnumerable = objectEnumerable;
_currentObject = currentObject;
_objectFactory = objectFactory;
}
// Member
public IHierarchicalEnumerable GetChildren()
{
return _objectFactory.CreateHierarchicalEnumerable(_objectEnumerable, _currentObject);
}
public IHierarchyData GetParent()
{
if (_currentObject.ParentPath != null)
{
foreach (IHierarchicalObject parentObject in _objectEnumerable)
{
if (parentObject.Path == _currentObject.ParentPath)
{
return _objectFactory.CreateHierarchyData(_objectEnumerable, parentObject);
}
}
}
return null;
}
public bool HasChildren
{
get
{
foreach (object childrenObject in this.GetChildren())
{
return true;
}
return false;
}
}
public object Item
{
get { return _objectFactory.CreateHierarchyData(_objectEnumerable, _currentObject); }
}
public string Path
{
get { return _currentObject.Path; }
}
public string Type
{
get { return _currentObject.GetType().ToString(); }
}
}
public interface IHierarchicalObject
{
string Path { get; }
string ParentPath { get; }
}
}