以编程方式添加UserControl与事件

时间:2009-12-14 14:33:39

标签: asp.net user-controls

我需要向面板添加多个用户控件,以便进一步编辑包含的数据。我的用户控件包含一些面板,下拉列表和输入元素,这些面板填充在用户控件的Page_Load事件中。

protected void Page_Load(object sender, EventArgs e)
{
  // populate comparer ddl from enum
  string[] enumNames = Enum.GetNames(typeof (SearchComparision));

  var al = new ArrayList();
  for (int i = 0; i < enumNames.Length; i++)
    al.Add(new {Value = i, Name = enumNames[i]});

  scOperatorSelection.DataValueField = "Value";
  scOperatorSelection.DataTextField = "Name";
  ...

要显示的数据作为字段添加到用户控件,在Page_Load上面定义。事件的签名如下:

public delegate void ControlStateChanged(object sender, SearchCriteriaEventArgs eventArgs);

public event ControlStateChanged ItemUpdated;
public event ControlStateChanged ItemRemoved;
public event ControlStateChanged ItemAdded;

用户控件上的更新按钮会触发以下方法:

protected void UpdateCriteria(object sender, EventArgs e)
{
  var searchCritCtl = (SearchCriteria) sender;

  var scEArgs = new SearchCriteriaEventArgs
  {
    TargetCriteria = searchCritCtl.CurrentCriteria.CriteriaId,
    SearchComparision = ParseCurrentComparer(searchCritCtl.scOperatorSelection.SelectedValue),
    SearchField = searchCritCtl.scFieldSelection.SelectedValue,
    SearchValue = searchCritCtl.scFilterValue.Text,
    ClickTarget = SearchCriteriaClickTarget.Update
  };
  if (ItemUpdated != null)
    ItemUpdated(this, scEArgs);
}

呈现页面从存储后端获取数据对象,并将其显示在其Page_Load事件中。这是它开始变得棘手的一点:我连接到自定义事件!

int idIt = 0;
foreach (var item in _currentSearch.Items)
{
  SearchCriteria sc = (SearchCriteria)LoadControl("~/content/controls/SearchCriteria.ascx");
  sc.ID = "scDispCtl_" + idIt;
  sc.ControlMode = SearchCriteriaMode.Display;
  sc.CurrentCriteria = item;
  sc.ItemUpdated += CriteriaUpdated;
  sc.ItemRemoved += CriteriaRemoved;
  pnlDisplayCrit.Controls.Add(sc);
  idIt++;
}

首次渲染页面时,一切都显示正常,我得到了所有数据。当我触发更新事件时,用户控件事件被正确触发,但用户控件的所有字段和控件都是 NULL 。经过一些研究后,我不得不得出结论,在控件初始化之前事件被触发了......

有什么方法可以防止这种行为/以某种方式覆盖页面生命周期?我无法在页面的Init-event中初始化用户控件,因为我必须访问Session-Store(未在Page_Init中初始化)。

欢迎任何建议......

修改

由于我们在存储后端保存所有标准信息(包括条件计数),并且该商店使用会话中的用户ID,因此我们无法使用Page_Init ...仅用于说明

编辑#2:

我设法解决了一些问题。由于我现在使用简单类型,我能够以声明方式绑定所有数据(使用带有简单ItemTemplate的转发器)。它受控制,它们以正确的方式呈现。在Postback上,所有数据都会反弹到用户控件,数据在OnDataBinding和OnLoad事件中可用,一切看起来都很好。

但是一旦它进入真实事件(绑定到用户控件的按钮控件),所有字段值都会以某种方式丢失...

有人知道,在数据绑定/加载后页面生命周期如何继续处理请求?我对这个问题发疯了......

2 个答案:

答案 0 :(得分:0)

动态控制可能是一场噩梦。诀窍是确保重新绑定回发上的所有内容。

答案 1 :(得分:0)

我想出了一个解决方案;)

如果我在usercontrol内的按钮上使用OnCommand事件,我可以传递一个CommandArgument。现在我将集合标识符绑定到按钮的CommandArgument参数,这使我能够处理usercontrol中的所有回发。

<asp:Button ID="scUpdate"
     runat="server"
     Text="Update"
     OnCommand="HandleCommand"
     CommandName="update"
     CommandArgument='<%# CriteriaId %>' />

此声明在整个回发中保留CriteriaId(一个Guid),并使我能够识别底层集合上的修改条目(在页面上管理)。以下代码段显示了如何触发订阅页面的事件。

scEArgs = new SearchCriteriaEventArgs
          {
                TargetCriteria = new Guid(e.CommandArgument.ToString()),
                SearchComparision = ParseCurrentComparer(),
                SearchField = scFieldSelection.SelectedValue,
                SearchValue = scFilterValue.Text,
                ClickTarget = SearchCriteriaClickTarget.Update
          };

if (ItemUpdated != null)
  ItemUpdated(this, scEArgs);

也许这个答案可以帮助某人,所以我会发布它;)