【发布时间】:2014-12-08 15:04:28
【问题描述】:
我正在尝试创建 ASP.NET 服务器控件(纯代码,没有 ascx 模板 - 因为控件必须完全包含在 .dll 中,并且不能依赖外部 .ascx 文件),我在动态添加时遇到了问题转发器的项目。
我想将项目添加到转发器以响应 SelectedIndexChanged 事件,但是当我在该事件中执行第二个 DataBind() 时,我会丢失 ViewModel 中的数据(例如,文本框包含默认数据而不是用户输入的文本)。
我的代码的简化版本(大部分来自 MS 复合控件示例 - http://msdn.microsoft.com/en-us/library/3257x3ea%28v=vs.100%29.aspx):
[ToolboxData("<{0}:FilterControl runat=server />")]
public class FilterControl : CompositeControl, IPostBackDataHandler
{
private List<FilteringProperty> elements = new List<FilteringProperty>();
private DropDownList filteringElementsDropDownList;
private Repeater usedFiltersRepeater;
[Bindable(true), DefaultValue(null), Description("Active filters")]
public List<FilteringProperty> UsedElements
{
get
{
EnsureChildControls();
if (ViewState["UsedElements"] == null)
{
ViewState["UsedElements"] = new List<FilteringProperty>();
}
return (List<FilteringProperty>)ViewState["UsedElements"];
}
set
{
EnsureChildControls();
ViewState["UsedElements"] = value;
}
}
protected override void RecreateChildControls()
{
EnsureChildControls();
}
protected override void CreateChildControls()
{
Controls.Clear();
filteringElementsDropDownList = new DropDownList { AutoPostBack = true };
usedFiltersRepeater = new Repeater();
foreach (var element in elements)
{
filteringElementsDropDownList.Items.Add(new ListItem(element.DisplayName));
}
filteringElementsDropDownList.SelectedIndexChanged += (sender, e) =>
{
string selectedText = filteringElementsDropDownList.SelectedValue;
FilteringProperty condition = elements.First(x => x.DisplayName == selectedText);
var toRemove = filteringElementsDropDownList.Items.Cast<ListItem>().FirstOrDefault(x => x.Text == condition.DisplayName);
if (toRemove != null)
{
filteringElementsDropDownList.Items.Remove(toRemove);
}
UsedElements.Add(condition);
// ======> A <========
};
usedFiltersRepeater.ItemDataBound += (sender, args) =>
{
FilteringProperty dataItem = (FilteringProperty)args.Item.DataItem;
Control template = args.Item.Controls[0];
TextBox control = (TextBox)template.FindControl("conditionControl");
control.Text = dataItem.DisplayName;
// ======> C <========
};
usedFiltersRepeater.ItemTemplate = // item template
usedFiltersRepeater.DataSource = UsedElements;
usedFiltersRepeater.DataBind();
// ======> B <========
Controls.Add(filteringElementsDropDownList);
Controls.Add(usedFiltersRepeater);
}
}
我用 (A)、(B) 和 (C) 标记了代码的重要部分
问题是,(A) 是在 DataBinding(B 和 C)之后执行的,所以 UsedElements 中的更改直到下一次回发时才可见。
可以在 (A) 之后添加 usedFiltersRepeater.DataBind();,但是所有控件都在没有来自视图状态的数据的情况下重新创建(即为空)
有没有办法在数据绑定后动态改变repeater,从而保留包含控件的数据?
Tl;dr - 我有一个 DropDownList,我想在 SelectedIndexChanged 上向 Repeater 添加可编辑项目(不丢失视图状态)。
【问题讨论】: