我正在设置由XML配置驱动的用户控件。通过示例更容易解释。请查看以下配置代码段:
<node>
<text lbl="Text:"/>
<checkbox lbl="Check me:" checked="true"/>
</node>
我正在尝试将该代码段转换为单个文本框和复选框控件。当然,如果代码段包含更多节点,则会自动生成更多控件。
给出任务的迭代性质,我选择使用Repeater。在其中我放置了两个(更多,见下图)控件,一个CheckBox和一个Editbox。为了选择激活哪个控件,我使用了内联切换命令,检查当前配置节点的名称。
可悲的是,这不起作用。问题在于,在数据绑定发生很久之后,交换机在渲染时间内运行。仅此一点不会成为问题,不是因为配置节点可能会向数据绑定提供所需的信息。考虑如果复选框控件将尝试绑定到上面代码段中的文本节点会发生什么,拼命地寻找它的“已检查”属性。
任何想法如何使这成为可能?
谢谢, 波阿斯
这是我目前的代码:
这是我的代码(使用比上面更复杂的语法运行):
<asp:Repeater ID="settingRepeater" runat="server">
<ItemTemplate>
<%
switch (((XmlNode)Page.GetDataItem()).LocalName)
{
case "text":
%>
<asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("@lbl") %>' runat="server" />
<asp:TextBox ID="settingsLabelText" Text='<%# SettingsNode.SelectSingleNode(XPath("@xpath").ToString()).InnerText %>'
runat="server" AutoPostBack="true" Columns='<%# XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"@width",20) %>'
/>
<% break;
case "checkbox":
%>
<asp:CheckBox ID="settingsCheckBox" Text='<%# XPath("@lbl") %>' runat="server"
Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("@xpath").ToString())).HasAttribute(XPath("@att").ToString()) %>'
/>
<% break;
} %>
</ItemTemplate>
</asp:Repeater>
答案 0 :(得分:4)
一个周末之后,这就是我作为解决方案所带来的。我的主要目标是找到既能工作又能让你在标记中指定项目模板的确切内容的东西。从代码中做事情会起作用,但仍然很麻烦。
代码应该直接遵循,但问题的要点分为两部分。
第一个是使用Repeater项目创建的事件来过滤掉模板中不需要的部分。
第二种是存储在ViewState中做出的决定,以便在回发期间重新创建页面。后者是至关重要的,因为您会注意到我使用了Item.DataItem。在回发期间,控制娱乐在页面生命周期的早期发生。触发ItemCreate时,DataItem为空。
这是我的解决方案:
控制标记
<asp:Repeater ID="settingRepeater" runat="server"
onitemcreated="settingRepeater_ItemCreated"
>
<ItemTemplate>
<asp:PlaceHolder ID="text" runat="server">
<asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("@lbl") %>' runat="server" />
<asp:TextBox ID="settingsLabelText" runat="server"
Text='<%# SettingsNode.SelectSingleNode(XPath("@xpath").ToString()).InnerText %>'
Columns='<%# XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"@width",20) %>'
/>
</asp:PlaceHolder>
<asp:PlaceHolder ID="att_adder" runat="server">
<asp:CheckBox ID="settingsAttAdder" Text='<%# XPath("@lbl") %>' runat="server"
Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("@xpath").ToString())).HasAttribute(XPath("@att").ToString()) %>'
/>
</asp:PlaceHolder>
</ItemTemplate>
</asp:Repeater>
注意:为了更加轻松,我添加了PlaceHolder控件来对事物进行分组,并决定删除哪些控件更容易。
代码
下面的代码建立在每个转发器项都属于某种类型的概念之上。该类型从配置xml中提取。在我的特定场景中,我可以通过ID将该类型设置为单个控件。如果需要,可以很容易地修改它。
protected List<string> repeaterItemTypes
{
get
{
List<string> ret = (List<string>)ViewState["repeaterItemTypes"];
if (ret == null)
{
ret = new List<string>();
ViewState["repeaterItemTypes"] = ret;
}
return ret;
}
}
protected void settingRepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
string type;
if (e.Item.DataItem != null)
{
// data binding mode..
type = ((XmlNode)e.Item.DataItem).LocalName;
int i = e.Item.ItemIndex;
if (i == repeaterItemTypes.Count)
repeaterItemTypes.Add(type);
else
repeaterItemTypes.Insert(e.Item.ItemIndex, type);
}
else
{
// restoring from ViewState
type = repeaterItemTypes[e.Item.ItemIndex];
}
for (int i = e.Item.Controls.Count - 1; i >= 0; i--)
{
if (e.Item.Controls[i].ID != type) e.Item.Controls.RemoveAt(i);
}
}
答案 1 :(得分:1)
你需要看起来更像这样的东西:
<ItemTemplate>
<%# GetContent(Page.GetDataItem()) %>
</ItemTemplate>
然后在代码隐藏中生成所有控件。