【问题标题】:Saving State Dynamic UserControls...Help!保存状态动态用户控件...帮助!
【发布时间】:2011-06-07 22:50:48
【问题描述】:

我有一个带有 LinkBut​​ton 的页面,当单击它时,我想在页面中添加一个用户控件。我需要能够根据用户的需要添加/删除尽可能多的控件。 Usercontrol 由三个下拉列表组成。第一个下拉列表的 auotpostback 属性设置为 true 并连接 OnSelectedIndexChanged 事件,该事件在触发时将加载剩余的两个下拉列表和适当的值。

我的问题是,无论我将代码放在主机页面的哪个位置,用户控件都没有正确加载。我知道我必须在每次回发时重新创建用户控件,并且我创建了一个在托管页面 OnPreInit 方法中执行的方法。我仍然收到以下错误: 在 DataBind、Init、Load、PreRender 或 Unload 阶段不能修改控件集合。

这是我的代码: 谢谢!!!!

bool createAgain = false;
    IList<FilterOptionsCollectionView> OptionControls
    {
        get
        {
            if (SessionManager.Current["controls"] != null)
                return (IList<FilterOptionsCollectionView>)SessionManager.Current["controls"];
            else
                SessionManager.Current["controls"] = new List<FilterOptionsCollectionView>();
            return (IList<FilterOptionsCollectionView>)SessionManager.Current["controls"];
        }
        set
        {
            SessionManager.Current["controls"] = value;
        }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        Master.Page.Title = Title;
        LoadViewControls(Master.MainContent, Master.SideBar, Master.ToolBarContainer);
    }

    protected override void OnPreInit(EventArgs e)
    {
        base.OnPreInit(e);
        System.Web.UI.MasterPage m = Master;
        Control control = GetPostBackControl(this);
        if ((control != null && control.ClientID ==
                        (lbAddAndCondtion.ClientID) || createAgain))
        {
            createAgain = true;
            CreateUserControl(control.ID);
        }
    }

    protected void AddAndConditionClicked(object o, EventArgs e)
    {
        var control = LoadControl("~/Views/FilterOptionsCollectionView.ascx");
        OptionControls.Add((FilterOptionsCollectionView)control);
        control.ID = "options" + OptionControls.Count.ToString();
        phConditions.Controls.Add(control);
    }



    public event EventHandler<Insight.Presenters.PageViewArg> OnLoadData;



    private Control FindControlRecursive(Control root, string id)
    {
        if (root.ID == id)
        {
            return root;
        }
        foreach (Control c in root.Controls)
        {
            Control t = FindControlRecursive(c, id);
            if (t != null)
            {
                return t;
            }
        }
        return null;
    }

    protected Control GetPostBackControl(System.Web.UI.Page page)
    {
        Control control = null;
        string ctrlname = Page.Request.Params["__EVENTTARGET"];
        if (ctrlname != null && ctrlname != String.Empty)
        {
            control = FindControlRecursive(page, ctrlname.Split('$')[2]);
        }
        else
        {
            string ctrlStr = String.Empty;
            Control c = null;
            foreach (string ctl in Page.Request.Form)
            {
                if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
                {
                    ctrlStr = ctl.Substring(0, ctl.Length - 2);
                    c = page.FindControl(ctrlStr);
                }
                else
                {
                    c = page.FindControl(ctl);
                }
                if (c is System.Web.UI.WebControls.CheckBox ||
                c is System.Web.UI.WebControls.CheckBoxList)
                {
                    control = c;
                    break;
                }
            }
        }
        return control;
    }


    protected void CreateUserControl(string controlID)
    {
        try
        {
            if (createAgain && phConditions != null)
            {
                if (OptionControls.Count > 0)
                {
                    phConditions.Controls.Clear();
                    foreach (var c in OptionControls)
                    {
                        phConditions.Controls.Add(c);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

这是用户控件的代码:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="FilterOptionsCollectionView.ascx.cs" Inherits="Insight.Website.Views.FilterOptionsCollectionView" %>


namespace Insight.Website.Views

{ [ViewStateModeById] 公共部分类 FilterOptionsCollectionView : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) {

    }

    protected override void OnInit(EventArgs e)
    {
        LoadColumns();
        ddlColumns.SelectedIndexChanged += new RadComboBoxSelectedIndexChangedEventHandler(ColumnsSelectedIndexChanged);
        base.OnInit(e);
    }

    protected void ColumnsSelectedIndexChanged(object o, EventArgs e)
    {
        LoadCriteria();
    }

    public void LoadColumns()
    {
        ddlColumns.DataSource = User.GetItemSearchProperties();
        ddlColumns.DataTextField = "SearchColumn";
        ddlColumns.DataValueField = "CriteriaSearchControlType";
        ddlColumns.DataBind();
        LoadCriteria();
    }

    private void LoadCriteria()
    {
        var controlType = User.GetItemSearchProperties()[ddlColumns.SelectedIndex].CriteriaSearchControlType;

        var ops = User.GetItemSearchProperties()[ddlColumns.SelectedIndex].ValidOperators;
        ddlOperators.DataSource = ops;
        ddlOperators.DataTextField = "key";
        ddlOperators.DataValueField = "value";
        ddlOperators.DataBind();

        switch (controlType)
        {
            case ResourceStrings.ViewFilter_ControlTypes_DDL:
                criteriaDDL.Visible = true;
                criteriaText.Visible = false;

                var crit = User.GetItemSearchProperties()[ddlColumns.SelectedIndex].SearchCriteria;
                ddlCriteria.DataSource = crit;
                ddlCriteria.DataBind();
                break;
            case ResourceStrings.ViewFilter_ControlTypes_Text:
                criteriaDDL.Visible = false;
                criteriaText.Visible = true;
                break;
        }
    }

    public event EventHandler OnColumnChanged;
    public ISearchCriterion FilterOptionsValues { get; set; }
}

}

【问题讨论】:

    标签: asp.net architecture user-controls domain-driven-design mvp


    【解决方案1】:

    我想通了。这是我的解决方案:

    我修改了 GetPostBackControl 以不仅查找插入用户控件的链接按钮,还查找包含所插入用户控件的子控件 ID 的控件(以捕获从我的用户控件内部触发的 OnSelectedIndexChanged) .

    protected Control GetPostBackControl(System.Web.UI.Page page)
        {
            Control control = null;
            string ctrlname = Page.Request.Params["__EVENTTARGET"];
            if (ctrlname != null && ctrlname != String.Empty)
            {
                //if it contains options then it's a control inside my usercontrol
                if (ctrlname.Split('$')[2].Contains("options"))
                {
                    var c = new Control();
                    c.ID = ctrlname;
                    return c;
                }
                else
                {
                    control = FindControlRecursive(page, ctrlname.Split('$')[2]);
                }
            }
            else
            {
                string ctrlStr = String.Empty;
                Control c = null;
                foreach (string ctl in Page.Request.Form)
                {
                    if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
                    {
                        ctrlStr = ctl.Substring(0, ctl.Length - 2);
                        c = page.FindControl(ctrlStr);
                    }
                    else
                    {
                        c = page.FindControl(ctl);
                    }
                    if (c is System.Web.UI.WebControls.CheckBox ||
                    c is System.Web.UI.WebControls.CheckBoxList)
                    {
                        control = c;
                        break;
                    }
                }
            }
            return control;
        }
    

    然后我修改 OnPreInit 事件以查找具有链接按钮 id 或包含“选项”的 id 的控件:

    protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
            System.Web.UI.MasterPage m = Master;
            Control control = GetPostBackControl(this);
            if (control != null)
            {
                if ((control.ClientID == (lbAddAndCondtion.ClientID) || createAgain) || control.ID.Contains("options"))
                {
                    createAgain = true;
                    CreateUserControl(control.ID);
                }
            }
        }
    

    关键修复在 CreateUserControl 方法中。在我的原始代码中,我试图从存储在 Session 中的通用列表中直接加载用户控件。我将其更改为实际创建用户控件的新实例,为该新实例分配一个与 Session 中存储的匹配的 id,然后将其添加到占位符:

    protected void CreateUserControl(string controlID)
        {
            try
            {
                if (createAgain && phConditions != null)
                {
                    if (OptionControls.Count > 0)
                    {
                        phConditions.Controls.Clear();
                        foreach (var c in OptionControls)
                        {
                            FilterOptionsCollectionView foc = new FilterOptionsCollectionView();
                            foc = Page.LoadControl("~/Views/FilterOptionsCollectionView.ascx") as FilterOptionsCollectionView;
                            foc.ID = c.ID;
                            phConditions.Controls.Add(foc);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    

    我在用户控件中唯一更改的是将加载下拉列表的方法移动并将 OnSelectedIndexChanged 事件连接到 OnInit 事件中。现在我可以动态加载我想要的任意数量的用户控件实例,并且用户控件内的所有事件都可以正确触发,并且状态在回发中保持不变!!

    希望这对其他人有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 2021-07-03
      相关资源
      最近更新 更多