2

这已经让我发疯了 2 天 - 希望有人以前见过。

我有这个问题,第一次单击中继器或网格视图中的控件无法触发 ItemCommand 事件,所有后续单击都有效。控件被加载到 Base.aspx 上的占位符中,如下所示

    private void LoadUserControl()
    {
        string controlPath = LastLoadedControl;

        if (!string.IsNullOrEmpty(controlPath))
        {
            ph.Controls.Clear();

            UserControl uc = (UserControl)LoadControl(controlPath);
            ph.Controls.Add(uc);
        }

    }

我想知道这是否是一个视图状态问题,以及我应该在哪些页面事件中使用 DataBind()。我已经在不同的页面事件中尝试了数据绑定,在页面和控件上启用视图状态,而不会改变结果。

这是 GridView 模板,但我对中继器控件也有相同的行为,所以我不相信它是这个问题的控件。

<ItemTemplate>
       <asp:RadioButton ID="rbEnable" GroupName="MyGroup" runat="server" Text="Enabled" Checked="<%# ((EducateMe.BaseTypes.AbstractLink)Container.DataItem).IsActive == true %>" />
       <asp:RadioButton ID="rbDisable" runat="server" GroupName="MyGroup" Text="Disabled" Checked="<%# ((EducateMe.BaseTypes.AbstractLink)Container.DataItem).IsActive != true %>" />
       <asp:Button ID="btnEnable" runat="server" CommandArgument="<% # Container.DataItemIndex %>" CommandName="Enable" ToolTip="Enable" Text="Save" />
       <asp:Button ID="btnDisable" runat="server" CommandArgument="<% # Container.DataItemIndex %>" Visible="false" CommandName="Disable" ToolTip="Disable" Text="Disable" />
    </ItemTemplate>

一些可能相关的进一步信息:

我注意到在用户控件的 Page_Load 事件中是我重新绑定控件的地方。这可能是控件状态被重写的原因,但是如果我在 ascx 中的该区域添加 if(!IsPostback),则此代码部分根本不会像在 aspx 页面上那样触发。我认为那将是重新绑定控件的正确部分。

4

3 回答 3

8

MikeW,
经过数小时的摆弄,我找到了问题的根源。
它与转发器或网格视图无关。
这只是一个动态控制回发问题。

解决您的问题:
令人惊讶的是,您的代码中只缺少一行。
当您加载控件时,为其 ID 分配一些内容,如下所示:

UserControl uc = (UserControl)LoadControl(controlPath);
uc.ID = "mycontrol";
ph.Controls.Add(uc);

这样,当您回发时,页面知道哪个控件是哪个。

为了更容易解释这一点,让我们简化问题。
这是一个连续单击一个按钮两次动态创建另一个按钮的场景:

  • 制作一个按钮 Button1,单击该按钮将动态加载另一个按钮 Button2。假设 Button2 的操作与显示当前时间一样简单。
  • 现在,单击 Button1。
  • 要保留 Button2,您必须利用ViewState告诉页面有一个动态控件。和你一样,我们可以记住控件的路径,或者它的类名。
  • 就在页面回发时,在 中Page_Load,我们查看ViewState是否有一个我们试图保留的控件,所以我们就在那里加载它(这相当于你LoadUserControl()上面的函数)。
  • 至此,Button2 是可见的,当点击它时,它会执行它的动作就好了。
  • 不要点击Button2,再点击一次Button1即可(相当于你的case在两个不同的动态控件之间切换)。
  • 猜猜现在会发生什么: Page_Load将从ViewState. 并且ClickButton1 的事件将在清除占位符后加载另一个 Button2 实例。
  • 由于您没有为其分配 ID,因此它将为自己分配一个 in UniqueID,并且这两个 Button2 将具有类似ctl02ctl03
  • 现在单击 Button2。
  • 你会说“没关系,我们正在覆盖旧的”。是的,但不是没有身份证。
  • 由于您没有在回发时给它一个 ID 来识别它,因此它将使用UniqueID顺序生成的 .
  • 现在页面正在寻找ctl03,它不存在,所以Click不会触发。
  • 但是,现在,我们有了一个全新的 Button2,带有UniqueID ctl02
  • 单击这个新的 Button2 就可以了,因为在回发时,它是唯一的 Button2,所以它碰巧有UniqueID一个ctl02

那么,分配 ID 是如何使其工作的呢?
这样,生成的每个新控件都将具有相同的 ID,因此在回发时,它可以找到它要查找的内容,无论它是在另一个按钮的事件中Page_Load还是在另一个按钮的Click事件中生成的。

希望这能解释它为什么起作用,但就您而言,只需为其分配一个 ID,一切都会好起来的。
我认为分享它背后的机制以及为什么会这样会很有趣。=)

于 2010-10-28T22:41:53.897 回答
1

我不确定您的其余代码,但通常当我看到“第一个操作的行为不同于后续操作”的问题时,是因为我在该IsPostBack部分的错误一侧放置了一些东西。

例如,我发现自己在回发时绑定,所以我的事件直到第二次回发才起作用,因为第一次回发是它们出生的时候,而初始页面加载从未完成那部分。

我认为你在正确的轨道上;确保您在正确的时刻绑定和连接您的事件。

于 2010-10-27T19:14:18.687 回答
1

我想通了,但我不明白为什么。
原始代码是:

Me.rpAgreementContractors.DataSource = dtContractors
Me.rpAgreementContractors.DataBind()
Me.tblAgreementContractors.Visible = True
Me.phDataPane.Controls.Add(Me.tblAgreementContractors)

在设置数据源并绑定它之前,我对其进行了更改以使表格可见并将其添加到占位符中。问题解决了。

Me.tblAgreementContractors.Visible = True
Me.phDataPane.Controls.Add(Me.tblAgreementContractors)
Me.rpAgreementContractors.DataSource = dtContractors
Me.rpAgreementContractors.DataBind()
于 2012-03-13T12:15:08.710 回答