【问题标题】:Dynamically adding rows to ASP.NET repeater in reaction to event动态添加行到 ASP.NET 转发器以响应事件
【发布时间】: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 添加可编辑项目(不丢失视图状态)。

【问题讨论】:

    标签: c# asp.net repeater


    【解决方案1】:

    我终于解决了我的问题。 我的解决方案很脏,但似乎可以正常工作。

    而不是简单的数据绑定:

    • 我使用我的函数 GetState() 从转发器中的所有控件获取状态并将其保存在临时变量中(每个控件的状态包括所有内容,例如下拉列表的选定索引)
    • 以任何我想要的方式修改此状态
    • 使用我的函数 SetState() 恢复完整状态

    例如:

    FilterState state = GetState();
    state.Conditions.Add(new ConditionState { Item = condition });
    SetState(state);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-01
      • 2021-08-15
      • 2012-11-11
      • 2013-11-17
      • 2012-04-04
      • 1970-01-01
      • 1970-01-01
      • 2013-10-18
      相关资源
      最近更新 更多