为了答谢大家对无须迭代两个循环完成树结构构建的支持特公布这两天新写的部门选择控件源代码,该控件最早是用一个用户控件实现数据调用采用Linq界面采用AtlasControlToolkit PopupControl实现,但后来发现效率非常低,最近对其进行了很大的优化,数据调用优化,控件形式优化.
该控件采用了Nikhil Kothari的Atlas M2.2 - Dynamic UpdatePanels (finally)的UpdatePanels within Composite Controls原型 here.并对其进行了部分改动,在这里谢谢了.
web页面截图如下:
IPartialRenderingCompositeControl接口没动
public interface IPartialRenderingCompositeControl |
{ |
void RenderUpdatePanel(CompositionUpdatePanel updatePanel, HtmlTextWriter writer); |
} |
CompositionUpdatePanel修改了内嵌类Template的代码
public class CompositionUpdatePanel : UpdatePanel |
{ |
private IPartialRenderingCompositeControl _compositeControl; |
private ContentControl _content; |
public CompositionUpdatePanel(IPartialRenderingCompositeControl compositeControl) |
{ |
_compositeControl = compositeControl; |
_content = new ContentControl(); |
ContentTemplate = new Template(_content); |
} |
public Control Content |
{ |
get |
{ |
return _content; |
} |
} |
protected override void OnInit(EventArgs e) |
{ |
base.OnInit(e); |
Controls.Clear(); |
Controls.Add(_content); |
} |
private class Template : ITemplate |
{ |
private ContentControl _ContentControl; |
public Template(ContentControl content) |
{ |
_ContentControl = content; |
} |
public void InstantiateIn(Control container) |
{ |
container.Controls.Add(_ContentControl); |
} |
} |
private class ContentControl : Control |
{ |
protected override void Render(HtmlTextWriter writer) |
{ |
CompositionUpdatePanel updatePanel = (CompositionUpdatePanel)Parent; |
if (updatePanel._compositeControl != null) |
{ |
updatePanel._compositeControl.RenderUpdatePanel(updatePanel, writer); |
} |
else |
{ |
base.RenderChildren(writer); |
} |
} |
} |
} |
树图代码:
[ToolboxData("<{0}:DepartmentTreeView runat=server></{0}:DepartmentTreeView>")] |
public class DepartmentTreeView : CompositeControl, IPartialRenderingCompositeControl |
{ |
private CompositionUpdatePanel _Container; |
private TreeView _DepartmentTreeView; |
public event EventHandler DepartmentIDChanged; |
public Nullable<Guid> DepartmentID |
{ |
get |
{ |
return (Nullable<Guid>)this.ViewState["DepartmentID"]; |
} |
set |
{ |
if ((Nullable<Guid>)this.ViewState["DepartmentID"] != value) |
{ |
this.ViewState["DepartmentID"] = value; |
if (value.HasValue) |
{ |
AIO.Web.Utils.TreeViewUtils.TreeViewSelectValue(_DepartmentTreeView, value.Value.ToString()); |
this.ViewState["DepartmentName"] = _DepartmentTreeView.SelectedNode.Text; |
} |
else |
{ |
if (_DepartmentTreeView.SelectedNode != null) |
{ |
_DepartmentTreeView.SelectedNode.Selected = false; |
this.ViewState["DepartmentName"] = String.Empty; |
} |
} |
} |
} |
} |
public string DepartmentName |
{ |
get |
{ |
return (string)this.ViewState["DepartmentName"]; |
} |
} |
public void ClearSelected() |
{ |
if(_DepartmentTreeView.SelectedNode != null) |
{ |
_DepartmentTreeView.SelectedNode.Selected = false; |
} |
} |
protected void BuildTree() |
{ |
_DepartmentTreeView.Nodes.Clear(); |
_DepartmentTreeView.Nodes.Add(new TreeNode("Null")); |
DataSet ds = AIO.WIT.Data.DepartmentDataObject.ReadCore(); |
int |
TreeNode[] Nodes = new TreeNode[Count + 1]; |
Nullable<int>[] ParentSQNs = new Nullable<int>[Count + 1]; |
foreach (DataRow dr in ds.Tables[0].Rows) |
{ |
Nodes[((int)dr["DepartmentSQN"])] = new TreeNode((string)dr["DepartmentName"], ((Guid)dr["DepartmentID"]).ToString()); |
if (dr["ParentSQN"].GetType() == typeof(DBNull)) |
{ |
ParentSQNs[(int)dr["DepartmentSQN"]] = null; |
} |
else |
{ |
ParentSQNs[(int)dr["DepartmentSQN"]] = (int)dr["ParentSQN"]; |
} |
} |
for (int i = 1; i < Count + 1; i++) |
{ |
if (ParentSQNs[i].HasValue) |
{ |
Nodes[ParentSQNs[i].Value].ChildNodes.Add(Nodes[i]); |
} |
else |
{ |
_DepartmentTreeView.Nodes.Add(Nodes[i]); |
} |
} |
} |
protected override void OnInit(EventArgs e) |
{ |
base.OnInit(e); |
} |
protected override void CreateChildControls() |
{ |
_Container = new CompositionUpdatePanel(this); |
_Container.Mode = UpdatePanelMode.Conditional; |
_Container.RenderMode = UpdatePanelRenderMode.Inline; |
_Container.ID = "Container"; |
Controls.Add(_Container); |
_DepartmentTreeView = new TreeView(); |
_DepartmentTreeView.ID = "DepartmentTreeView"; |
BuildTree(); |
_DepartmentTreeView.SelectedNodeChanged += delegate(object sender, EventArgs e) |
{ |
if (_DepartmentTreeView.SelectedNode.Text == "Null") |
{ |
this.ViewState["DepartmentID"] = null; |
this.ViewState["DepartmentName"] = String.Empty; |
} |
else |
{ |
this.ViewState["DepartmentID"] = new Guid(_DepartmentTreeView.SelectedNode.Value); |
this.ViewState["DepartmentName"] = _DepartmentTreeView.SelectedNode.Text; |
} |
if (DepartmentIDChanged != null) |
{ |
DepartmentIDChanged(this, new EventArgs()); |
} |
}; |
_Container.Content.Controls.Add(_DepartmentTreeView); |
} |
void IPartialRenderingCompositeControl.RenderUpdatePanel(CompositionUpdatePanel updatePanel, HtmlTextWriter writer) |
{ |
_DepartmentTreeView.RenderControl(writer); |
} |
} |
部门选择代码:
[ToolboxData("<{0}:DepartmentSelect runat=server></{0}:DepartmentSelect>")] |
public class DepartmentSelect : CompositeControl, IPartialRenderingCompositeControl |
{ |
private CompositionUpdatePanel _Container; |
private TextBox _DepartmentTextBox; |
private Panel _DepartmentTreeViewPanel; |
private DepartmentTreeView _DepartmentTreeView; |
private PopupControlExtender _PopupControlExtender; |
private PopupControlProperties _PopupControlProperties; |
public Nullable<Guid> DepartmentID |
{ |
get |
{ |
return _DepartmentTreeView.DepartmentID; |
} |
set |
{ |
_DepartmentTreeView.DepartmentID = value; |
} |
} |
protected override void OnInit(EventArgs e) |
{ |
base.OnInit(e); |
} |
protected override void CreateChildControls() |
{ |
_Container = new CompositionUpdatePanel(this); |
_Container.Mode = UpdatePanelMode.Conditional; |
_Container.RenderMode = UpdatePanelRenderMode.Inline; |
_Container.ID = "Container"; |
Controls.Add(_Container); |
_DepartmentTextBox = new TextBox(); |
_DepartmentTextBox.ID = "DepartmentTextBox"; |
_Container.Content.Controls.Add(_DepartmentTextBox); |
_DepartmentTreeViewPanel = new Panel(); |
_DepartmentTreeViewPanel.ID = "DepartmentTreeViewPanel"; |
_DepartmentTreeViewPanel.CssClass = "PopupControl"; |
_DepartmentTreeView = new DepartmentTreeView(); |
_DepartmentTreeView.ID = "DepartmentTreeView"; |
_DepartmentTreeView.DepartmentIDChanged += delegate(object sender, EventArgs e) |
{ |
_DepartmentTextBox.Text = _DepartmentTreeView.DepartmentName; |
_DepartmentTreeView.ClearSelected(); |
_PopupControlExtender.Commit(_DepartmentTreeView.DepartmentName); |
}; |
_DepartmentTreeViewPanel.Controls.Add(_DepartmentTreeView); |
_Container.Content.Controls.Add(_DepartmentTreeViewPanel); |
_PopupControlProperties = new PopupControlProperties(); |
_PopupControlProperties.ID = "PopupControlProperties"; |
_PopupControlProperties.TargetControlID = "DepartmentTextBox"; |
_PopupControlProperties.PopupControlID = "DepartmentTreeViewPanel"; |
_PopupControlProperties.Position = PopupControlPopupPosition.Bottom; |
_PopupControlExtender = new PopupControlExtender(); |
_PopupControlExtender.ID = "PopupControlExtender"; |
_PopupControlExtender.TargetProperties.Add(_PopupControlProperties); |
Controls.Add(_PopupControlExtender); |
} |
void IPartialRenderingCompositeControl.RenderUpdatePanel(CompositionUpdatePanel updatePanel, HtmlTextWriter writer) |
{ |
_DepartmentTextBox.RenderControl(writer); |
_DepartmentTreeViewPanel.RenderControl(writer); |
_PopupControlExtender.RenderControl(writer); |
} |
} |
TreeViewUtils代码:
public class TreeViewUtils |
{ |
public static void TreeViewExpandToSelected(TreeView tv) |
{ |
TreeNode tmp = tv.SelectedNode; |
if (tmp != null) |
{ |
while (tmp.Parent != null) |
{ |
tmp = tmp.Parent; |
tmp.Expand(); |
} |
} |
} |
public static Boolean TreeViewSelectValue(TreeView tv, string value) |
{ |
Boolean bResult = false; |
foreach (TreeNode tr in tv.Nodes) |
{ |
if (TreeViewSelectValue(tr, value)) |
{ |
bResult = true; |
break; |
} |
} |
if (bResult) |
{ |
TreeViewExpandToSelected(tv); |
} |
else |
{ |
if (tv.SelectedNode != null) |
{ |
tv.SelectedNode.Selected = false; |
} |
} |
return bResult; |
} |
protected static Boolean TreeViewSelectValue(TreeNode tr, string value) |
{ |
if (tr.Value == value) |
{ |
tr.Selected = true; |
return true; |
} |
foreach (TreeNode test in tr.ChildNodes) |
{ |
if (TreeViewSelectValue(test, value)) |
{ |
return true; |
} |
} |
return false; |
} |
} |
数据库访问代码:
[DataObject(true)] |
public class DepartmentDataObject |
{ |
[DataObjectMethod(DataObjectMethodType.Select, true)] |
public static DataSet ReadCore() |
{ |
Database db = DatabaseFactory.CreateDatabase("WorkItemTrack"); |
string sqlCommand = "Department_SelectCore"; |
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand); |
db.AddReturnValueParameter(dbCommand); |
return db.ExecuteDataSet(dbCommand); |
} |
} |
存储过程代码:
ALTER PROCEDURE dbo.Department_SelectCore |
AS |
SET NOCOUNT ON |
SELECT |
Department.DepartmentID, |
Department.DepartmentSQN, |
Department.DepartmentName, |
Department.ParentID, |
Parent.DepartmentSQN AS ParentSQN |
FROM Department |
LEFT OUTER JOIN Department AS Parent ON Parent.DepartmentID = Department.ParentID |
ORDER BY Department.DepartmentSQN |
RETURN |
表格:
DepartmentID uniqueidentifier, |
DepartmentSQN int, |
DepartmentName nvarchar(32), |
ParentID uniqueidentifier |
完整代码下载DepartmentSelect.rar