Вот что я хочу:
Я хочу разместить элемент управления на странице, чтобы другие разработчики могли размещать внутри него элементы формы для отображения сущностей, которые ищет мой элемент управления. У меня логика поиска все работает. Элемент управления создает пользовательские поля поиска и выполняет поиск на основе декларативных классов C #, реализующих мой интерфейс SearchSpec
.
Вот что я пытался:
Я пытался использовать ITemplate в WebControl, который реализует INamingContainer.
Я пытался реализовать CompositeControl
Самое близкое, что я могу получить к работе - это ниже.
ОК. У меня есть собственный WebControl
[
AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("SearchSpecName"),
ParseChildren(true),
ToolboxData("<{0}:SearchPage runat=\"server\"> </{0}:SearchPage>")
]
public class SearchPage : WebControl, INamingContainer
{
[Browsable(false),
PersistenceMode(PersistenceMode.InnerProperty),
DefaultValue(typeof(ITemplate), ""),
Description("Form template"),
TemplateInstance(TemplateInstance.Single),
TemplateContainer(typeof(FormContainer))]
public ITemplate FormTemplate { get; set; }
public class FormContainer : Control, INamingContainer{ }
public Control MyTemplateContainer { get; private set; }
[Bindable(true), Category("Behavior"), DefaultValue(""),
Description("The class name of the SearchSpec to use."), Localizable(false)]
public virtual string SearchSpecName
{
get;
set;
}
[Bindable(true), Category("Behavior"), DefaultValue(true),
Description("True if this is query mode."), Localizable(false)]
public virtual bool QueryMode
{
get;
set;
}
private SearchSpec _spec;
private SearchSpec Spec
{
get
{
if (_spec == null)
{
Type type = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Name == SearchSpecName).First();
_spec = (SearchSpec)Assembly.GetExecutingAssembly().CreateInstance(type.Namespace + "." + type.Name);
}
return _spec;
}
}
protected override void CreateChildControls()
{
if (FormTemplate != null)
{
MyTemplateContainer = new FormTemplateContainer(this);
FormTemplate.InstantiateIn(MyTemplateContainer);
Controls.Add(MyTemplateContainer);
}
else
{
Controls.Add(new LiteralControl("blah"));
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
// <snip>
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
public class FormTemplateContainer : Control, INamingContainer
{
private SearchPage parent;
public FormTemplateContainer(SearchPage parent)
{
this.parent = parent;
}
}
тогда использование:
<tster:SearchPage ID="sp1" runat="server" SearchSpecName="TestSearchSpec" QueryMode="False">
<FormTemplate>
<br />
Test Name:
<asp:TextBox ID="testNameBox" runat="server" Width="432px"></asp:TextBox>
<br />
Owner:
<asp:TextBox ID="ownerBox" runat="server" Width="427px"></asp:TextBox>
<br />
Description:
<asp:TextBox ID="descriptionBox" runat="server" Height="123px" Width="432px"
TextMode="MultiLine" Wrap="true"></asp:TextBox>
</FormTemplate>
</tster:SearchPage>
Проблема в том, что в CodeBehind на странице есть элементы descriptionBox, ownerBox и testNameBox. Тем не менее, они все нулевые. Кроме того, FindControl("ownerBox")
возвращает ноль, как и this.sp1.FindControl("ownerBox")
. Я должен сделать this.sp1.MyTemplateContainer.FindControl("ownerBox")
, чтобы получить контроль.
Как я могу сделать так, чтобы в коде C # Behind были сгенерированы элементы управления, а не нуль в моем событии Page_Load, чтобы разработчики могли просто сделать это:
testNameBox.Text = "foo";
ownerBox.Text = "bar";
descriptionBox.Text = "baz";