【问题标题】:ItemCommand not firing on first click in Repeater or GridViewItemCommand 在 Repeater 或 GridView 中首次单击时未触发
【发布时间】:2010-10-27 14:59:36
【问题描述】:

这已经让我发疯 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 页面上那样触发。我认为这将是重新绑定控件的正确部分。

【问题讨论】:

    标签: c# asp.net itemcommand


    【解决方案1】:

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

    解决您的问题:
    令人惊讶的是,您的代码中只缺少一行。
    当你加载控件的时候,给它的 ID 分配一些东西,像这样:

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

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

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

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

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

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

    【讨论】:

    • 哈 - Beemer 做得很棒 - 当然已经解决了,非常感谢你的帮助 - 我以后一定会看那个的 :-D
    • 这对我帮助很大!你不知道我今天因为这个问题而遭受的挫折!我喜欢你。你让我快乐。你完成了我... :)
    • 我很高兴一年半后我仍然从这个答案中得到爱 =) 没问题,伙计们。
    • 太棒了...很好的答案..帮助了我很多:)
    【解决方案2】:

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

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

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

    【讨论】:

    • 感谢您的回复。我在帖子底部添加了一些可能相关的更多信息:!IsPostback。
    • 尝试将重新绑定代码从 Page_Load 移动到控件的 Page_PreRender
    • 那里没有欢乐。顺便说一句,控件和页面的视图状态已打开。
    • btw.... 如果我错了,请纠正我,但 GridViews 没有 ItemCommand;他们有 RowCommand.. 除非我缺少更大的图景。
    • 你是对的,我发现无论控制如何,行为都是相同的。为了让事情更清楚一点,我整理了一个行为的准系统解决方案,可在 202.53.7.235/PostBackTest 获得。 rar,欢迎任何想法或建议:-)\
    【解决方案3】:

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

    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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-09
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多