问题
I want to do something like (Updated example):
<uc:Tabs>
<Tab Name="A handy tab">
<Node Url="~/Default.aspx" />
<Node Url="~/Node2.aspx" />
</Tab>
<Tab Name="Another handy tab">
<Node Url="~/Neato.aspx" />
<Node Url="~/Node3.aspx" />
<Node Url="~/Node4.aspx" />
</Tab>
<uc:Tabs>
Possible? Any tutorials or how-to's? I'm not sure what to even search on or what this is called so haven't found anything so far. Inner controls? Inner collection something something...?
回答1:
Use the ParseChildrenAttribute and PersistChildrenAttribute attributes:
[ParseChildren(false)]
[PersistChildren(true)]
public class MyControl : UserControl { }
This will cause any controls you put inside the reference:
<uc:MyControl runat="server">
<asp:TextBox runat="server" />
<uc:MyControl>
To be appended to the end of the Controls collection of your UserControl contents.
However, if you want to have a collection of controls, you should probably use a server control and not a user control. For a control that works like this:
<foo:TabControl runat="server">
<Tabs>
<foo:Tab CssClass="myclass" Title="Hello World" />
</Tabs>
</foo:TabControl>
You need a Control class that has a Tabs property; the Tabs property should be a Collection; and it should contain objects of type Tab. I've created the three classes here:
[ParseChildren(true, "Tabs")]
public class TabControl: WebControl, INamingContainer
{
private TabCollection _tabs;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public TabCollection Tabs
{
get
{
if (_tabs == null)
{
_tabs = new TabCollection();
}
return _tabs;
}
}
protected override void Render(HtmlTextWriter writer)
{
foreach (Tab tab in Tabs)
{
writer.WriteBeginTag("div");
writer.WriteAttribute("class", tab.CssClass);
writer.Write(HtmlTextWriter.TagRightChar);
writer.Write("this is a tab called " + tab.Title);
writer.WriteEndTag("div");
}
}
}
And the tab class:
public class Tab
{
public string CssClass { get; set; }
public string Title { get; set; }
}
And the tab collection:
public class TabCollection : Collection<Tab> { }
回答2:
Follow up
Rex M provided the answer but just wanted to follow up on what I've also found for posterity.
It seems like you can do either:
<ui:Tabs runat="server">
<ui:Tab TabText="Blah">
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/More.aspx" />
<ui:Node Url="~/Another.aspx" />
</ui:Tab>
<ui:Tab TabText="Nanner">
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/More.aspx" />
<ui:Node Url="~/Another.aspx" />
</ui:Tab>
<ui:Tab TabText="High There">
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/More.aspx" />
<ui:Node Url="~/Another.aspx" />
</ui:Tab>
</ui:Tabs>
OR
<ui:Tabs runat="server">
<TabItems>
<ui:Tab InnerHeading="Big Huge Heading" TabText="Big">
<NodeItems>
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
</NodeItems>
</ui:Tab>
</TabItems>
<TabItems>
<ui:Tab InnerHeading="Hi ya" TabText="Hi">
<NodeItems>
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
<ui:Node Url="~/Default.aspx" />
</NodeItems>
</ui:Tab>
</TabItems>
</ui:Tabs>
Then within code:
namespace Controls
{
[ToolboxData("<{0}:Tabs runat=server></{0}:Tabs>"), ParseChildren(true, "TabItems")]
public class Tabs : BaseControl, INamingContainer
{
private TabCollection tabItems;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public TabCollection TabItems
{
get
{
if (tabItems == null)
{
tabItems = new TabCollection();
}
return tabItems;
}
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<div id=\"tabs\" class=\"pane\" style=\"display: none\"><ul>");
int tabNumber = 1;
foreach (Tab tab in TabItems)
{
string li = string.Format("<li id=\"tab_{0}\"><a href=\"#tab{0}\"><span>{1}</span></a></li>", tabNumber, tab.TabText);
tabNumber++;
writer.Write(li);
}
writer.Write("</ul>");
tabNumber = 1;
foreach (Tab tab in TabItems)
{
string div = string.Format("<div id=\"tab{0}\" class=\"pane\"><h1>{1}</h1>", tabNumber, tab.InnerHeading);
tabNumber++;
writer.Write(div);
foreach (Node node in tab.NodeItems)
{
string a = string.Format("<a href='{0}'>{1}</a>", node.Url, "Text holder");
writer.Write(a);
}
writer.Write("</div>");
}
writer.Write("</div>");
}
}
public class TabCollection : List<Tab> { }
[ParseChildren(true, "NodeItems")]
public class Tab
{
private string tabText = string.Empty;
private string innerHeading = string.Empty;
private string showOn = string.Empty;
public string TabText
{
get { return tabText; }
set { tabText = value; }
}
public string InnerHeading
{
get { return innerHeading; }
set { innerHeading = value; }
}
public string ShowOn
{
get { return showOn; }
set { showOn = value; }
}
private NodeCollection nodeItems;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public NodeCollection NodeItems
{
get
{
if (nodeItems == null)
{
nodeItems = new NodeCollection();
}
return nodeItems;
}
}
}
public class NodeCollection : List<Node> { }
public class Node
{
private string url = string.Empty;
public string Url
{
get { return url; }
set { url = value; }
}
}
}
This will obviously be changing (mine's going to be reading from the web.sitemap among other changes), but this should get anyone with the same needs well under their way.
回答3:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Web.UI.HtmlControls;
namespace Gui.Controls
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:GPMenu runat=server></{0}:GPMenu>")]
[ParseChildren(false)]
public class GPMenu : WebControl
{
private void CreateDynamicControls()
{
//some code for Creating Dynamic Controls
} //eof method
#region FieldsAndProps
#region ActiveTab
protected int _ActiveTab;
[Bindable(true)]
[Category("Appearance")]
public int ActiveTab // Public properties
{
get { return _ActiveTab; }
set { _ActiveTab = value; }
}
#endregion ActiveTab
#region Caption
protected string _Caption = "";
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Caption // Public properties
{
get { return _Caption; }
set { _Caption = value; }
}
#endregion Caption
#region MenuId
protected string _MenuId = "0";
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string MenuId // Public properties
{
get { return _MenuId; }
set { _MenuId = value; }
}
#endregion MenuId
#region Text
protected string _Text = "";
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text // Public properties
{
get { return _Text; }
set { _Text = value; }
}
#endregion Text
#region UserObj
private FB.User userObj;
public FB.User UserObj
{
get
{
return userObj;
} //eof get
set
{
userObj = value;
} //eof set
} //eof prop
#endregion UserObj
#region ListTabWizard
private List<App.Models.TabWizard> _ListWizard;
[Bindable(true)]
[Category("Appearance")]
[Description(" The data structure used for databinding the menu ")]
public List<App.Models.TabWizard> ListWizard
{
get { return _ListWizard; }
set { _ListWizard = value; }
}
#endregion ListWizard
#endregion FieldsAndProps
#region Constructors
public GPMenu()
{
//Statement to run while initialize of control
}
#endregion Constructors
#region Overrides
public override void RenderControl(HtmlTextWriter writer)
{
RenderContents(writer);
}
protected override void RenderContents(HtmlTextWriter output)
{
//Codes for rendering html to be written here
output.WriteBeginTag("div");
output.WriteAttribute("class", _Caption);
output.WriteAttribute("ID", this.ID);
RenderChildren(output); // Render Child Control is Exists
output.WriteEndTag("div");
}
public override void DataBind()
{
this.Controls.Clear();
base.DataBind();
#region Debug
//old configure the logger
//logger.Debug("Custom GPMenu DataBind called ");
#endregion Debug
#region AddTheTopDiv
Panel panTabMenuTop = new Panel();
panTabMenuTop.ID = "panTabMenuTop";
panTabMenuTop.CssClass = "CssClassPanTabMenuTop";
this.Controls.Add(panTabMenuTop);
#endregion AddTheTopDiv
#region AddTheUlOpenTag
HtmlGenericControl conGenUi = new HtmlGenericControl("ul");
conGenUi.ID = "paakallo";
#endregion AddTheUlOpenTag
#region ForEachMenuItemInTheListAddTheLinks
if (this.ListWizard == null)
throw new Exception(" The List of menu items is null for " + this.ID);
#region ForEachWizardItem
for (int iListMenuItem = 0; iListMenuItem < this.ListWizard.Count; iListMenuItem++)
{
App.Models.TabWizard objMenuItem = this.ListWizard[iListMenuItem];
#region AddTheLiOpenTag
PlaceHolder objPlaceHolderLiOpen = new PlaceHolder();
objPlaceHolderLiOpen.Controls.Add(new LiteralControl("<li>"));
conGenUi.Controls.Add(objPlaceHolderLiOpen);
#endregion AddTheLiOpenTag
#region BuildTheLocalizedLink
#region Check that the whole MenuItem data structure is not null
if (objMenuItem == null)
throw new Exception(
"The building of the GPMenu failed since \n: " +
" null MenuItem at " + iListMenuItem.ToString() + " for " + this.ID);
#endregion Check that the whole MenuItem data structure is not null
//the variant with LinkButton does PostBack == BAD !!!
PlaceHolder objPlaceHolderLink = new PlaceHolder();
#region BuildTheLinkId_with_MenuItemId
if (String.IsNullOrEmpty(objMenuItem.Link_Id.ToString()))
{
throw new Exception(
"The building of the GPMenu failed since \n: " +
" null or empty MenuItemId for " + iListMenuItem.ToString() + " for " + this.ID);
}
#endregion BuildTheLinkId_with_MenuItemId
#region AddTheTextForTheLink_with_GuiPageLinkURL
//check that this LinkItem points to a registered page
if (objMenuItem.Link_Id == null)
{
throw new Exception(
"The building of the GPMenu failed since \n: " +
" null GuiPage for " + iListMenuItem.ToString() + " for " + this.ID);
}
string strActiveLinkCssClass = String.Empty;
string strTabTxt = String.Empty;
try
{
strTabTxt = objMenuItem.TabTitle;
}
catch (System.Exception ex)
{
continue;
}
#region BuildTheActualLink
string strLinkTxt = String.Empty;
strLinkTxt += "<a " + strActiveLinkCssClass + " href=\"";
string strLinkUrl = Http.UrlHandler.ExpandUrl(objMenuItem.LinkURL);
#endregion BuildTheActualLinks
#region AddTheColorForTheLinkAndRemoveTheBorderOfActiveTab
if (this.ActiveTab != null && strLinkUrl.Contains("tabid=" + this.ActiveTab.ToString()))
strActiveLinkCssClass = "class=\"CssClassGPMenuActiveLink\"";
#endregion AddTheColorForTheLinkAndRemoveTheBorderOfActiveTab
strLinkTxt += strLinkUrl + "\"" + strActiveLinkCssClass;
#endregion AddTheTextForTheLink_with_GuiPageLinkURL
#region AddTheToolTip
string strVisibleToolTipTxt = String.Empty;
try
{
strVisibleToolTipTxt = objMenuItem.ItemButtonToolTip;
}
catch (System.Exception ex)
{
continue;
}
strLinkTxt += "\" title=\"" + strVisibleToolTipTxt +
"\"><span>" + strTabTxt + "</span></a>";
#endregion AddTheToolTip
#region AddTheLabel_used_in_The_TabMenu
objPlaceHolderLink.Controls.Add(new LiteralControl(strLinkTxt));
conGenUi.Controls.Add(objPlaceHolderLink);
#endregion AddTheLabel_used_in_The_TabMenu
#endregion BuildTheLocalizedLink
#region AddTheLiCloseTag
PlaceHolder objPlaceHolderLiClose = new PlaceHolder();
objPlaceHolderLiClose.Controls.Add(new LiteralControl("</li>"));
conGenUi.Controls.Add(objPlaceHolderLiClose);
#endregion AddTheLiCloseTag
} //eof foreach MenuItem in List
#endregion ForEachWizardItem
#endregion ForEachMenuItemInTheListAddTheLinks
#region AddTheUlCloseTag
this.Controls.Add(conGenUi);
#region AddTheBottomDiv
Panel panTabMenuBottom = new Panel();
panTabMenuBottom.ID = "panTabMenuBottom";
panTabMenuBottom.CssClass = "CssClassPanTabMenuBottom";
this.Controls.Add(panTabMenuBottom);
#endregion AddTheBottomDiv
#endregion AddTheUlCloseTag
} //eof method
#region TemplateMethods
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
} //eof method
protected override void CreateChildControls()
{
base.CreateChildControls();
this.CreateDynamicControls();
} //eof method
protected override object SaveViewState()
{
return new Pair(base.SaveViewState(), null);
} //eof method
protected override void LoadViewState(object savedState)
{
base.LoadViewState(((Pair)savedState).First);
EnsureChildControls();
} //eof method
#endregion TemplateMethods
#endregion Overrides
} //eof class
} //eof namespace
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Collections.Specialized;
namespace App.Models
{
/// <summary>
/// Serves as the model for the tabwizard page
/// </summary>
public class TabWizard
{
#region Properties
#region TabWizardId
public long tbGuiTabWizardId { get; set; }
#endregion TabWizardId
#region TabId
public int TabId { get; set; }
#endregion TabId
#region Link_Id
public int Link_Id { get; set; }
#endregion Link_Id
#region WizardId
public int WizardId { get; set; }
#endregion WizardId
#region TabOrder
public int TabOrder { get; set; }
#endregion TabOrder
#region TabTitle
public string TabTitle { get; set; }
#endregion TabTitle
#region TabHasManyButtons
public bool TabHasManyButtons { get; set; }
#endregion TabHasManyButtons
#region ButtonTitle
public string ButtonTitle { get; set; }
#endregion ButtonTitle
#region Description
public string Description { get; set; }
#endregion Description
#region ProcToStart
public string ProcToStart { get; set; }
#endregion ProcToStart
#region ProcId
public string ProcId { get; set; }
#endregion ProcId
#region ItemMetaId
public string ItemMetaId { get; set; }
#endregion ItemMetaId
#region ItemId
public string ItemId { get; set; }
#endregion ItemId
#region ItemStartProc
public string ItemStartProc { get; set; }
#endregion ItemStartProc
#region ItemButtonToolTip
public string ItemButtonToolTip { get; set; }
#endregion ItemButtonToolTip
#region ItemButtonText
public string ItemButtonText { get; set; }
#endregion ItemButtonText
#region TypeOfTab
public string TypeOfTab { get; set; }
#endregion TypeOfTab
#region WizardHasStepping
public bool WizardHasStepping { get; set; }
#endregion WizardHasStepping
#region RunProcOnTabClick
public bool RunProcOnTabClick { get; set; }
#endregion RunProcOnTabClick
#region TabIsPRS
public bool TabIsPRS { get; set; }
#endregion TabIsPRS
#region ItemIsPRS
public bool ItemIsPRS { get; set; }
#endregion ItemIsPRS
#region FlagPresentAreYouSurePrompt
public bool FlagPresentAreYouSurePrompt { get; set; }
#endregion FlagPresentAreYouSurePrompt
#region PromptAreYouSureText
public string PromptAreYouSureText { get; set; }
#endregion PromptAreYouSureText
#region PageId
public int PageId { get; set; }
#endregion PageId
#region MenuId
public int MenuId { get; set; }
#endregion MenuId
#endregion Properties
#region Props
#region Constructor
public TabWizard(System.Data.DataRow dr)
{
if (dr["tbGuiTabWizardId"] != null && !(dr["tbGuiTabWizardId"] is DBNull))
this.tbGuiTabWizardId = System.Convert.ToInt64(dr["tbGuiTabWizardId"]);
if (dr["TabId"] != null && !(dr["TabId"] is DBNull))
this.TabId = System.Convert.ToInt32(dr["TabId"]);
if (dr["Link_Id"] != null && !(dr["Link_Id"] is DBNull))
this.Link_Id = System.Convert.ToInt32(dr["Link_Id"]);
if (dr["WizardId"] != null && !(dr["WizardId"] is DBNull))
this.WizardId = System.Convert.ToInt32(dr["WizardId"]);
if (dr["TabOrder"] != null && !(dr["TabOrder"] is DBNull))
this.TabOrder = System.Convert.ToInt32(dr["TabOrder"]);
if (dr["TabTitle"] != null && !(dr["TabTitle"] is DBNull))
this.TabTitle = System.Convert.ToString(dr["TabTitle"]);
if (dr["TabHasManyButtons"] != null && !(dr["TabHasManyButtons"] is DBNull))
this.TabHasManyButtons = System.Convert.ToBoolean(dr["TabHasManyButtons"]);
if (dr["ButtonTitle"] != null && !(dr["ButtonTitle"] is DBNull))
this.ButtonTitle = System.Convert.ToString(dr["ButtonTitle"]);
if (dr["Description"] != null && !(dr["Description"] is DBNull))
this.Description = System.Convert.ToString(dr["Description"]);
if (dr["ProcToStart"] != null && !(dr["ProcToStart"] is DBNull))
this.ProcToStart = System.Convert.ToString(dr["ProcToStart"]);
if (dr["ProcId"] != null && !(dr["ProcId"] is DBNull))
this.ProcId = System.Convert.ToString(dr["ProcId"]);
if (dr["ItemMetaId"] != null && !(dr["ItemMetaId"] is DBNull))
this.ItemMetaId = System.Convert.ToString(dr["ItemMetaId"]);
if (dr["ItemStartProc"] != null && !(dr["ItemStartProc"] is DBNull))
this.ItemStartProc = System.Convert.ToString(dr["ItemStartProc"]);
if (dr["ItemButtonToolTip"] != null && !(dr["ItemButtonToolTip"] is DBNull))
this.ItemButtonToolTip = System.Convert.ToString(dr["ItemButtonToolTip"]);
if (dr["ItemButtonText"] != null && !(dr["ItemButtonText"] is DBNull))
this.ItemButtonText = System.Convert.ToString(dr["ItemButtonText"]);
if (dr["TypeOfTab"] != null && !(dr["TypeOfTab"] is DBNull))
this.TypeOfTab = System.Convert.ToString(dr["TypeOfTab"]);
if (dr["WizardHasStepping"] != null && !(dr["WizardHasStepping"] is DBNull))
this.WizardHasStepping = System.Convert.ToBoolean(dr["WizardHasStepping"]);
if (dr["RunProcOnTabClick"] != null && !(dr["RunProcOnTabClick"] is DBNull))
this.RunProcOnTabClick = System.Convert.ToBoolean(dr["RunProcOnTabClick"]);
if (dr["TabIsPRS"] != null && !(dr["TabIsPRS"] is DBNull))
this.TabIsPRS = System.Convert.ToBoolean(dr["TabIsPRS"]);
if (dr["ItemIsPRS"] != null && !(dr["ItemIsPRS"] is DBNull))
this.ItemIsPRS = System.Convert.ToBoolean(dr["ItemIsPRS"]);
if (dr["FlagPresentAreYouSurePrompt"] != null && !(dr["FlagPresentAreYouSurePrompt"] is DBNull))
this.FlagPresentAreYouSurePrompt = System.Convert.ToBoolean(dr["FlagPresentAreYouSurePrompt"]);
if (dr["PromptAreYouSureText"] != null && !(dr["PromptAreYouSureText"] is DBNull))
this.PromptAreYouSureText = System.Convert.ToString(dr["PromptAreYouSureText"]);
if (dr["PageId"] != null && !(dr["PageId"] is DBNull))
this.PageId = System.Convert.ToInt32(dr["PageId"]);
if (dr["LinkURL"] != null && !(dr["LinkURL"] is DBNull))
this.LinkURL = System.Convert.ToString(dr["LinkURL"]);
if (dr["MenuId"] != null && !(dr["MenuId"] is DBNull))
this.MenuId = System.Convert.ToInt16(dr["MenuId"]);
} //eof constructor
#endregion Constructor
#region LinkURL
private string _LinkURL = String.Empty;
public string LinkURL
{
get { return _LinkURL; }
set { _LinkURL = value; }
}
#endregion LinkURL
#endregion Props
} //eof class
} //eof namespace
来源:https://stackoverflow.com/questions/604620/is-there-a-way-to-put-inner-controls-inside-a-asp-net-custom-control