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事件的方法。現在我可以動態地加載用戶控件的所有實例,並且用戶控件中的所有事件都可以正確觸發,並且狀態在回發中保持不變!

希望這可以幫助別人!