介绍完基础类及WinPop控件后下面开始介绍第一个控件DropDownTree。首先我先对该控件的功能作个介绍:
其界面如下:

其功能如下:
1.支持从DataTable中载入数据
2.支持验证器控件
3.支持不同级别显示样式
4.支持仅针对叶子节点的数据选择验证
其开发原刑如下:

其中DropDownTree中含有两个集合属性,一个Items一个ItemStyles,Items中用来保存树状结构中的节点信息,而ItemStyles则保存不同级别的节点样式,在每一个Item中也会有一个ItemStyle属性,当Item的ItemStyle不为空时,系统才会取在DropDownTree中ItemStyles集合中的样式来绘制节点。而ItemStyles集合中根据集合中的索引来决定绘制级别的样式,如绘制根节点时将会取在ItemStyles[0]中的样式,而当节点级别大于ItemStyles集合中的条目时将取最后一个为绘制样式。另外在Item中也会有一个Items集合属性以此来实现树状结构。
以下是DropDownTreeItemStyle和DropDownTreeItemStyleCollection的源代码,他们的实现和WinPopItem和WinPopItemCollection的实现基本相同。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Drawing.Design;
using System.Drawing;

using System.ComponentModel;
using System.ComponentModel.Design;

namespace Keyss.WebControls
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public class DropDownTreeItemStyle:ViewStatePartBase
{
![]()
public const string ForeColorKey = "A";
public const string BackColorKey = "B";
#endregion
![]()
[
Bindable(true),
Category("Appearance"),
DefaultValue(typeof(System.Drawing.Color),""),
NotifyParentProperty(true),
TypeConverter(typeof(WebColorConverter))
]
public System.Drawing.Color ForeColor
{
get
{
object o = ViewState[ForeColorKey];
return(o==null)? System.Drawing.Color.Empty:(System.Drawing.Color)o;
}
set
{
ViewState[ForeColorKey] = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(typeof(System.Drawing.Color),""),
NotifyParentProperty(true),
TypeConverter(typeof(WebColorConverter))
]
public System.Drawing.Color BackColor
{
get
{
object o = ViewState[BackColorKey];
return(o==null)? System.Drawing.Color.Empty:(System.Drawing.Color)o;
}
set
{
ViewState[BackColorKey] = value;
}
}
#endregion
![]()
public virtual void AddAttributesToRender(HtmlTextWriter writer)
{
if(this.ForeColor!=Color.Empty)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.Color,ColorTranslator.ToHtml(this.ForeColor));
}
if(this.BackColor!=Color.Empty)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,ColorTranslator.ToHtml(this.BackColor));
}
}
#endregion
![]()
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void CopyFrom(DropDownTreeItemStyle s)
{
base.CopyFrom(s);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void MergeWith(DropDownTreeItemStyle s)
{
base.MergeWith(s);
}
#endregion
}
}
其中由于Style经常要作些Copy、Merge的操作因此重载了基类的MergeWith和CopyFrom方法,而为了方便样式的使用,系统定义了另外一个方法AddAttributesToRender,当在绘制Item时可以调用此方法来实现样式属性的输出。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Drawing.Design;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;

namespace Keyss.WebControls
{
[
PersistenceMode(PersistenceMode.InnerProperty),
]
public class DropDownTreeItemStyleCollection:ViewStatePartCollectionBase
{

public int Add(DropDownTreeItemStyle item)
{
return base.AddItem(item);
}
public DropDownTreeItemStyle this[int index]
{
get
{
if(index >= Count || index < 0)
{
return null;
}
return (DropDownTreeItemStyle)this.InnerList[index];
}
}
protected override ViewStatePartBase NewItem()
{
return new DropDownTreeItemStyle();
}

}
}
DropDownTreeItemStyleCollection的实现和WinPopItemCollection的实现基本一样。
以下是DropDownTreeItem的实现
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Drawing.Design;
using System.Drawing;

using System.ComponentModel;
using System.ComponentModel.Design;

namespace Keyss.WebControls
{
public class DropDownTreeItem:ViewStatePartBase
{
![]()
public const string TextKey = "A";
public const string ValueKey = "B";
#endregion
![]()
[
NotifyParentProperty(true),
Bindable(true),
Category("Appearance"),
DefaultValue("")
]
public string Text
{
get
{
object o = ViewState[TextKey];
return (o == null)?string.Empty : (string)o;
}
set
{
ViewState[TextKey] = value;
}
}
[
NotifyParentProperty(true),
Bindable(true),
Category("Appearance"),
DefaultValue("")
]
public string Value
{
get
{
object o = ViewState[ValueKey];
return (o == null)?string.Empty:(string)o;
}
set
{
ViewState[ValueKey] = value;
}
}

#endregion
![]()
protected DropDownTreeItemStyle _style;
[
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.Attribute),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
TypeConverter(typeof(ExpandableObjectConverter))
]
public virtual DropDownTreeItemStyle Style
{
get
{
if(_style == null)
{
_style = new DropDownTreeItemStyle();
if(_isTrackingViewState)
_style.TrackViewState();
}
return _style; }
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
protected virtual DropDownTreeItemStyle RenderStyle
{
get
{
if(!DropDownTree.ItemStyles.IsEmpty)
{
DropDownTreeItemStyle tmpStyle = new DropDownTreeItemStyle();
int tmpLevel = this.Level;

if(tmpLevel < DropDownTree.ItemStyles.Count)
{
tmpStyle.CopyFrom(DropDownTree.ItemStyles[tmpLevel]);
}
else
{
tmpStyle.CopyFrom(this.DropDownTree.ItemStyles[DropDownTree.ItemStyles.Count - 1]);
}
if(!Style.IsEmpty)
{
tmpStyle.CopyFrom(this.Style);
}
return tmpStyle;
}
else
return this.Style;
}
}
#endregion
![]()
protected DropDownTree _dropDownTree;
protected DropDownTreeItem _owner;
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public DropDownTreeItem Owner
{
![]()
![]()
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public DropDownTree DropDownTree
{
![]()
![]()
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public int Level
{
get
{
int i = 0;
DropDownTreeItem tmpOwner = this._owner;
while(tmpOwner != null)
{
tmpOwner = tmpOwner.Owner;
i++;
}
return i;
}
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public int Index
{
get
{
if(this.Level != 0)
return this.Owner.Items.IndexOf(this);
else
return this.DropDownTree.Items.IndexOf(this);
}
}
#endregion
![]()
private DropDownTreeItemCollection _items;
[
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
]
public DropDownTreeItemCollection Items
{
get
{
if(_items == null)
{
_items = new DropDownTreeItemCollection();
if(this._isTrackingViewState)
_items.TrackViewState();
}
return _items;
}
}
#endregion
![]()
public virtual void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.WriteLine();
this.AddAttributesToRender(writer);
writer.RenderBeginTag(HtmlTextWriterTag.Option);
this.RenderContent(writer);
writer.RenderEndTag();
writer.WriteLine();
this.Items.Render(writer);
}
protected virtual void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
this.RenderStyle.AddAttributesToRender(writer);
string tvalue = this.Value;
if(this.DropDownTree.SelectLeafOnly&&(!this.Items.IsEmpty))
tvalue = string.Empty;
if(tvalue!= string.Empty)
writer.AddAttribute(HtmlTextWriterAttribute.Value,tvalue);
if(this.DropDownTree.SelectedValue == this.Value)
writer.AddAttribute(HtmlTextWriterAttribute.Selected,"true");
}
protected virtual void RenderContent(System.Web.UI.HtmlTextWriter writer)
{
writer.Write(string.Format("{0} {1}", this.GetTabText() + this.GetPreText(), this.Text));
}
protected virtual string GetTabText()
{
if(this.Level == 0) return string.Empty;
DropDownTreeItem pItem = this.Owner;
DropDownTreeItemCollection p_pItems;
if(this.Level > 1)
p_pItems = pItem.Owner.Items;
else
p_pItems = this.DropDownTree.Items;
if(pItem.Index == p_pItems.Count-1)
return string.Format("{0}{1}",pItem.GetTabText(), " " + this.DropDownTree.TabString);
else
return string.Format("{0}{1}",pItem.GetTabText(), "┃" + this.DropDownTree.TabString);
}
protected virtual string GetPreText()
{
int l = this.Level;
int i = this.Index;

DropDownTreeItemCollection pItems;
if(l == 0)
pItems = this.DropDownTree.Items;
else
pItems = this.Owner.Items;

if((l == 0)&&(pItems.Count == 1))
return "┣";

if((l == 0) && (i == 0) && (pItems.Count > 1))
return "┏";

if(i == (pItems.Count-1))
return "┗";
else
return "┣";
}
#endregion
![]()
![]()
public override void SetDirty()
{
base.SetDirty ();
Style.SetDirty();
Items.SetDirty();
}
#endregion
public override void TrackViewState()
{
base.TrackViewState();
Style.TrackViewState();
Items.TrackViewState();
}
public override object SaveViewState()
{
object[] savedState = new object[3];
savedState[0] = base.SaveViewState();
savedState[1] = Style.SaveViewState();
savedState[2] = Items.SaveViewState();
for(int i=0;i<savedState.Length;i++)
{
if(savedState[i] != null)
return savedState;
}
return null;
}
public override void LoadViewState(object state)
{
if(state !=null)
{
object[] savedState = (object[])state;

if(savedState[0] != null)
base.LoadViewState(savedState[0]);
if(savedState[1] != null)
Style.LoadViewState(savedState[1]);
if(savedState[2] != null)
Items.LoadViewState(savedState[2]);
}
}
#endregion
![]()
public virtual void Init()
{
this.Items.Owner = this;
this.Items.DropDownTree = this.DropDownTree;
this.Items.Init();
}
#endregion
![]()
public virtual void LoadFromDataRow(System.Data.DataRow row)
{
System.Data.DataTable table = row.Table;

if(table.Columns.Contains("Text"))
{
this.Text = row["Text"].ToString();
}
if(table.Columns.Contains("Value"))
{
this.Value = row["Value"].ToString();
}
}
#endregion
}
}
以下是DropDownTreeItemCollection的源代码
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Drawing.Design;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
namespace Keyss.WebControls
{
public class DropDownTreeItemCollection:ViewStatePartCollectionBase
{
![]()
protected DropDownTree _dropDownTree;
protected DropDownTreeItem _owner;
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public DropDownTreeItem Owner
{
![]()
![]()
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public DropDownTree DropDownTree
{
![]()
![]()
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public int Level
{
get
{
int i = 0;
DropDownTreeItem tmpOwner = this._owner;
while(tmpOwner != null)
{
tmpOwner = tmpOwner.Owner;
i++;
}
return i;
}
}
#endregion
![]()
public int Add(DropDownTreeItem item)
{
return this.AddItem(item);
}
protected override int AddItem(ViewStatePartBase item)
{
DropDownTreeItem mItem = (DropDownTreeItem)item;
mItem.DropDownTree = this.DropDownTree;
mItem.Owner = this.Owner;
mItem.Init();
return base.AddItem(mItem);
}
public DropDownTreeItem this[int index]
{
get
{
if(index >= Count || index < 0)
{
return null;
}
return (DropDownTreeItem)this.InnerList[index];
}
}
public int IndexOf(DropDownTreeItem item)
{
return this.InnerList.IndexOf(item);
}
public DropDownTreeItem GetItemByValue(string _value)
{
if(!IsEmpty)
{
foreach(DropDownTreeItem item in this.InnerList)
{
if(item.Value==_value)
return item;
else
{
DropDownTreeItem item1 = item.Items.GetItemByValue(_value);
if(item1!=null)
return item1;
}
}
}
return null;
}
#endregion
![]()
public virtual void Render(System.Web.UI.HtmlTextWriter writer)
{
if(!IsEmpty)
{
for(int i=0;i<this.Count;i++)
{
this[i].Render(writer);
}
}
}
#endregion
![]()
public virtual void Init()
{
for(int i = 0; i < this.Count; i ++)
{
this[i].DropDownTree = this.DropDownTree;
this[i].Owner = this.Owner;
this[i].Init();
}
}
#endregion
![]()
protected override ViewStatePartBase NewItem()
{
return new DropDownTreeItem();
}
#endregion
}
}
最后是DropDownTree的代码
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace Keyss.WebControls
{
[
ParseChildren(true),
ValidationPropertyAttribute("SelectedValue"),
PersistChildren(false),
DefaultProperty("Items"),
ToolboxData("<{0}:DropDownTree runat=server></{0}:DropDownTree>")]
public class DropDownTree : System.Web.UI.WebControls.WebControl,IPostBackDataHandler
{
![]()
public virtual void LoadFromTable(System.Data.DataTable table,bool isStr, string idField, string parentIDField)
{
try
{
this.Items.Clear();
System.Data.DataRow[] rows = table.Select(string.Format("{0} is null",parentIDField));
foreach(System.Data.DataRow row in rows)
{
Keyss.WebControls.DropDownTreeItem item = new Keyss.WebControls.DropDownTreeItem();
item.LoadFromDataRow(row);
this.Items.Add(item);
LoadItemsFromTable(item, row[idField], table, isStr, idField, parentIDField);
}
}
catch
{
throw new ArgumentException("Table or filed name error!",table.TableName);
}
}
protected virtual void LoadItemsFromTable(DropDownTreeItem item, object idValue, System.Data.DataTable table,bool isStr,string idField, string parentIDField)
{
string selectStr;
if(isStr)
{
selectStr = "{0} = '{1}'";
}
else
{
selectStr = "{0} = {1}";
}

try
{
System.Data.DataRow[] rows = table.Select(string.Format(selectStr,parentIDField,idValue));
foreach(System.Data.DataRow row in rows)
{
Keyss.WebControls.DropDownTreeItem item1 = new Keyss.WebControls.DropDownTreeItem();
item1.LoadFromDataRow(row);
item.Items.Add(item1);
LoadItemsFromTable(item1, row[idField], table, isStr, idField, parentIDField);
}
}
catch
{
throw new ArgumentException("Table or filed name error!",table.TableName);
}
}
#endregion
![]()
[
Bindable(true),
Category("Appearance"),
DefaultValue(" ")
]
public string TabString
{
get
{
object o = ViewState["tabString"];
return (o == null)?" ":(string)o;
}
set
{
ViewState["tabString"] = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue("")
]
public string SelectedValue
{
get
{
object o = ViewState["selectedValue"];
return (o == null)?"":(string)o;
}
set
{
ViewState["selectedValue"] = value;
}
}
[
DefaultValue(false),
NotifyParentProperty(true),
]
public bool AutoPostBack
{
get
{
object o = ViewState["autoPostBack"];
return (o == null)?false:(bool)o;
}
set
{
ViewState["autoPostBack"] = value;
}
}
[
DefaultValue(false),
NotifyParentProperty(true),
]
public bool SelectLeafOnly
{
get
{
object o = ViewState["selectLeafOnly"];
return (o == null)?false:(bool)o;
}
set
{
ViewState["selectLeafOnly"] = value;
}
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
]
public DropDownTreeItem SelectedItem
{
![]()
}
#endregion
![]()
private DropDownTreeItemStyleCollection _itemStyles;
[
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
]
public DropDownTreeItemStyleCollection ItemStyles
{
get
{
if(_itemStyles==null)
{
_itemStyles = new DropDownTreeItemStyleCollection();
if(this.IsTrackingViewState)
_itemStyles.TrackViewState();
}
return _itemStyles;
}
}
#endregion
![]()
private DropDownTreeItemCollection _items;
[
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
]
public DropDownTreeItemCollection Items
{
get
{
if(this._items ==null)
{
_items = new DropDownTreeItemCollection();
if(this.IsTrackingViewState)
_items.TrackViewState();
}
return _items;
}
}
#endregion
![]()
protected override void Render(HtmlTextWriter writer)
{
if(Page != null)
Page.VerifyRenderingInServerForm(this);

if(!Items.IsEmpty)
{
base.Render(writer);
}
else
{
if((this.Site!=null)&&this.Site.DesignMode)
writer.WriteLine(this.ID);
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
foreach(DropDownTreeItem item in this.Items)
{
item.Render(writer);
}

}

protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Select;
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender (writer);
writer.AddAttribute(HtmlTextWriterAttribute.Name,this.UniqueID);
if(this.AutoPostBack)
{
writer.AddAttribute("language","javascript");
writer.AddAttribute("onchange",this.Page.GetPostBackClientEvent(this,string.Empty));
}

}

#endregion
![]()
protected override void LoadViewState(object state)
{
if(state !=null)
{
object[] savedState = (object[])state;
if(savedState[0] != null)
base.LoadViewState(savedState[0]);
if(savedState[1] != null)
ItemStyles.LoadViewState(savedState[1]);
if(savedState[2] != null)
Items.LoadViewState(savedState[2]);
}

}
protected override object SaveViewState()
{
object[] savedState = new object[3];
savedState[0] = base.SaveViewState ();
savedState[1] = this.ItemStyles.SaveViewState();
savedState[2] = this.Items.SaveViewState();
for(int i=0;i<savedState.Length;i++)
{
if(savedState[i] != null)
return savedState;
}
return null;
}
protected override void TrackViewState()
{
base.TrackViewState();
ItemStyles.TrackViewState();
Items.TrackViewState();
}
#endregion
![]()
protected override void OnInit(EventArgs e)
{
base.OnInit (e);
this.Items.Owner = null;
this.Items.DropDownTree = this;
this.Items.Init();
}
#endregion
![]()
protected static readonly object EventSelectedIndexChanged = new object();
public event System.EventHandler SelectedIndexChanged
{
add
{
Events.AddHandler(EventSelectedIndexChanged, value);
}
remove
{
Events.RemoveHandler(EventSelectedIndexChanged, value);
}
}
protected virtual void OnSelectedIndexChanged(System.EventArgs e)
{
EventHandler selectedIndexChangedHandler = (EventHandler)Events[EventSelectedIndexChanged];
if(selectedIndexChangedHandler!=null)
{
selectedIndexChangedHandler(this,e);
}
}
#endregion
![]()

public void RaisePostDataChangedEvent()
{
OnSelectedIndexChanged(System.EventArgs.Empty);
}
public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
String presentValue = this.SelectedValue;
String postedValue = postCollection[this.UniqueID];

if (presentValue == null || !presentValue.Equals(postedValue))
{
this.SelectedValue = postedValue;
return true;
}
return false;
}
#endregion
}
}
由于时间有限,今天先把代码贴上以后有空再加注解:),你们如果哪些看不懂可以帮我留言:)