保存状态动态UserControls ...帮助!

时间:2011-01-12 16:18:30

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

我的页面上有一个LinkBut​​ton,点击后,我想在页面中添加一个Usercontrol。我需要能够添加/删除用户想要的控件。 Usercontrol由三个下拉列表组成。第一个下拉列表将auotpostback属性设置为true并挂起OnSelectedIndexChanged事件,该事件在被触发时将使用适当的值加载剩余的两个下拉列表。

我的问题是,无论我将代码放在主页中的哪个位置,都没有正确加载usercontrol。我知道我必须在每个回发上重新创建用户控件,并且我已经创建了一个在托管页面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;
        }
    }

这是usercontrol的代码:

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


namespace Insight.Website.Views

{     [ViewStateModeById]     public partial class 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; }
}

}

1 个答案:

答案 0 :(得分: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为linkbutton的控件或包含“options”的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匹配的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事件。现在我可以动态加载我想要的用户控件的多个实例,并且用户控件内的所有事件都正确地触发,并且状态在回发中保持不变!!

希望这有助于其他人!!