0

我有一个LinkBut​​ton的页面,点击时,我想添加一个UserControl到页面。我需要能够添加/删除尽可能多的用户喜欢的控件。 Usercontrol由三个下拉列表组成。第一个下拉列表将其auotpostback属性设置为true,并挂接OnSelectedIndexChanged事件,该事件在被触发时将使用适当的值加载剩余的两个下拉列表。保存状态动态用户控件...帮助!

我的问题是,无论在哪里我把代码在主机页面,用户控件没有正确加载。我知道我必须在每个回发中重新创建usercontrols,并且创建了一个在托管页面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 { 保护无效的Page_Load(对象发件人,EventArgs的) {

} 

    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

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

我修改了GetPostBackControl,以便不仅查找插入用户控件的linkbutton,还查找包含插入的用户控件的子控件的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事件,查找控制与LinkBut​​ton的的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中的通用列表中直接加载用户控件。我改变了这一切实际上是创建用户控制的新实例,分配一个新的实例匹配存储在会话中一个一个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事件的方法。现在我可以动态地加载用户控件的所有实例,并且用户控件中的所有事件都可以正确触发,并且状态在回发中保持不变!

希望这可以帮助别人!