用户控件事件处理程序在回发时丢失

4
我有一个名为LeftMenu的菜单用户控件,其中包含链接项的项目符号列表。它在ascx页面上如下所示:
<asp:BulletedList ID="PublisherList" DisplayMode="LinkButton" OnClick="PublisherList_Click" cssClass="Menu" runat="server"></asp:BulletedList>

我在if(!isPostBack)中绑定了列表。 我遇到了一个页面加载控件的问题。 当页面首次加载时,事件处理程序会启动。 但是,当页面执行回发时,它不再触发,而在IE8中,在调试时,我会在Visual Studio中看到“Microsoft JScript运行时错误:期望对象”指向“__doPostBack('LeftMenu $ PublisherList','0')”。 在Firefox中,我没有得到任何错误,但什么也没有发生。我没有使用动态加载控件,而是在aspx页面上使用以下代码加载:

<%@ Register TagPrefix="Standards" TagName="LeftMenu" Src="LeftMenu.ascx" %>

<Standards:LeftMenu ID="LeftMenu" runat="server"/>

你有没有想法,我在哪里丢失了事件处理程序?

我刚意识到这也发生在另一个用户控件上。有一个文本框和一个按钮,我使用默认按钮来确保按下回车键时使用该按钮。 .Net会将其转换为以下html代码:

 <div id="SearchBarInclude_SearchBar" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'SearchBarInclude_QuickSearchButton')">

一旦我在文本框中输入一个键,就会在代码行上出现“对象期望”的JavaScript错误。似乎这两个问题有关。

再次编辑:我想我需要澄清。不是我点击菜单项,然后在postback时找不到所选项。我有一个带有左侧导航的搜索页面,然后页面的主要内容是引起postback的东西。这个postback很好。一旦页面被postback,现在如果我点击左侧导航中的项目列表,我会得到一个javascript错误并且失败。LeftMenu控件的page_init从未被调用。

6个回答

0

我遇到了类似的问题。原来是因为应用了一个不必要的设置,导致Akamai修改了用户代理字符串。

这意味着一些.NET控件无法正确渲染__doPostBack代码。关于这个问题已经在这里的博客中有记录。


0

听起来你可能因为没有在PostBack时进行数据绑定而失去了点击事件。因此,PostBack尝试引用一个不存在的控件(特定的项目列表项)。

你应该尝试在PostBack时重新绑定列表,以查看是否可以解决你的问题。但是,真正应该发生的是LeftMenu和BulletedList应该将它们的信息存储到ViewState中,这样你就可以确保在用户初始页面加载时显示给用户的数据与PostBack正在处理和使用的数据相同。


如果菜单和列表包含100或1000个项目,它们是否仍应存储在视图状态中? - Phaedrus
理想情况下,ViewState 永远消失,永远不会回来,这样 PostBack 的种种神秘就不会再次出现,我们的页面也能保持轻盈通透;-)
话虽如此,在网站上,这是一个左侧导航菜单,因此我怀疑其中只有几项。
显然,如果这是某种数据库调用,则需要将其缓存,这可以帮助保持页面调用的轻盈性并且不需要 ViewState,但是如果缓存过期,则不能保证 PostBack 所操作的列表与用户看到的原始列表是否相同。
- Tony Heupel
将if(!isPostBack){...}中的内容删除并不能解决问题。数据很少更改,我是否仍然应该将其存储在ViewState中? - user154008

0

如果您的UserControl及其内部所有控件都启用了EnableViewState=true,则一切都应该正常工作。启用ViewState后,ASP将在Init触发后从ViewState中重新填充您的控件。这意味着postback事件参数(指向控件列表中的索引)仍将在该列表位置找到控件。否则,在postback时列表为空。

然而,ViewState是魔鬼的杰作,只是为了营造您正在使用有状态环境的假象。对于小量数据,可以使用它,但通常不建议在像重复器和列表这样的模板控件中使用,因为您无法知道ViewState中会创建多少数据。

如果您处理静态或相对静态的数据,请将其存储在应用程序缓存中,并在每次Page.Init中重新绑定列表(请注意,必须在Init中进行,因为post-init是ASP从ViewState重新绑定的时间;如果您先进入那里,您的数据将被使用)。

如果您正在处理易变数据,那么您会面临一个问题,因为您重新绑定的数据必须与原始页面请求完全相同,否则后续事件将针对错误的行触发。在这种情况下,您需要将初始数据存储在会话中,或者您可以仅存储行ID列表(在隐藏变量或会话中),并且每次从ID重新创建数据以进行绑定。

更好的解决方案是根本不使用后续事件。尝试将所有事件转换为带有查询字符串ID的GET。第一次通过页面时仍可以使用绑定创建列表(正如您当前所做的那样),甚至可以使用新ID获取相同的页面。

如果您需要在同一页上保持状态但需要响应用户更改单选按钮选择(或其他内容),请考虑使用Ajax调用更新屏幕。您还可以使用传递给Ajax调用的ID执行此操作。

总的来说,越来越少地使用ASP的有状态方式,您的页面就会变得更轻、更具响应性。如果必要,您还可以更好地转向无状态MVC。您还可以节省大量时间,因为当您需要ViewState时它不可用而浪费时间调试模糊的问题。

我读过有关ViewState的最好分析是在下面的链接中。如果你完全理解它的工作原理,你可以继续使用它而不必担心成本。

http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/truly-understanding-viewstate.aspx


抱歉,我想我没有解释清楚。问题不在于我找不到 postback 中选定的项目,这在大多数情况下是可以的。问题是当我在一个提交到自身的页面上有这个控件,然后尝试单击列表中的项目时。我会收到一个 JavaScript 错误“对象预期”并且它无法工作。 - user154008

0

这可能与JavaScript有关,页面中早期加载的脚本发生错误,导致页面无法正确加载。

您的用户控件是否将任何JavaScript加载到页面上?您可以在页面最初加载时检查JavaScript错误吗?


0

我将代码移入了我们现有的项目中,但出现了一些奇怪的问题,我不再收到JavaScript错误,而是得到了以下信息:

"无效的回发或回调参数。事件验证已启用,使用配置文件中的<pages enableEventValidation="true"/>或页面中的<%@ Page EnableEventValidation="true" %>

出于安全考虑,此功能验证回发或回调事件的参数是否来自最初呈现它们的服务器控件。如果数据有效且符合预期,请使用ClientScriptManager.RegisterForEventValidation方法注册回发或回调数据以进行验证。"

我还没有完全弄清楚在用户控件中应该放置注册事件验证的位置,但与此同时,我只需设置enableeventvalidation=false,现在似乎可以正常工作了。


你是在本地机器上运行还是在开发/测试集群上运行?如果你在不同的机器之间跳转,可能会导致机器密钥没有正确设置以相互匹配。如果是在本地机器上遇到这个问题,那就算了 :-) - Tony Heupel

0

看起来doPostBack函数缺失,因为它的参数是文字常量,所以它们不可能是原因。那是你自己的函数还是你想调用ASP __doPostBack函数?

查看Firefox错误控制台或允许IE脚本调试,看看哪个对象找不到。更好的方法是下载Firebug进行调试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接