1

背景:

我有一个页面,其中有各种使用 JavaScript 处理的客户端事件。我想将其中一些事件与服务器端事件“同步”,或者从代码隐藏中调用函数。

我想用 JavaScript 调用的一些函数可能会更改我在页面上的表单中的控件(例如更改文本框值)。它们还可能更改我存储在 ViewState 中的一些值,因为我希望一些值通过回发保持不变。我不想进行完整的回发,并且拥有可以在更新面板中更改的控件。

我目前正在使用 JavaScript 在我的代码隐藏中“调用”函数,方法是单击通过更新面板中的异步回发触发器触发我页面上的部分回发的不可见按钮。

问题:

我的一个客户端事件调用了一个 JavaScript 函数,该函数单击了多个不可见按钮(客户端事件发生在单击之间,这可能会影响代码隐藏函数的行为方式)。当我让 JavaScript 单击多个按钮时,对 ViewState 所做的更改似乎不会持续存在,并且只观察到上次单击后的更改。

例子:

我可能没有很好地解释这一点,所以这是我所拥有的简化版本(我可以用它来重现问题)。

标记:

<asp:Button ID="btnA" runat="server" style="display: none;" />
<asp:Button ID="btnB" runat="server" style="display: none;" />
<div style="background: red; width: 100px; height: 100px;" onclick="AB();"></div>

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:UpdatePanel runat="server" ID="upForm" UpdateMode="Conditional">
    <Triggers>
            <asp:AsyncPostBackTrigger ControlID="btnA" EventName="Click" />
            <asp:AsyncPostBackTrigger ControlID="btnB" EventName="Click" />
    </Triggers>
    <ContentTemplate>
    </ContentTemplate>
</asp:UpdatePanel>

JavaScript:

function AB() {
    $('#<%= btnA.ClientID %>').click();
    $('#<%= btnB.ClientID %>').click();
}

代码隐藏:

Protected Sub btnA_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnA.Click
    ViewState("AB") += "A"
End Sub
Protected Sub btnB_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnB.Click
    ViewState("AB") += "B"
End Sub

问题:

  1. 为什么部分回发之间对 ViewState 的更改会丢失?
  2. 如何保存部分回发之间的更改?会话变量很好用,但我宁愿不必使用它们。我也无法将值保存在不可见的控件中,因为我实际上正在更改 ViewState 中的序列化对象。
  3. 有没有更好的方法可以做到这一点?
4

3 回答 3

2

我对此进行了测试,并且视图状态确实会根据部分请求进行更新。2 个连续的部分请求可能存在问题。第一个请求必须在第二个请求触发之前返回才能工作。

viewstate 的工作方式是有一个名为 __VIEWSTATE 的隐藏字段,它会在每个请求上发布。ASP.NET 使用这些数据来维护它需要的任何状态。因此,如果第一个请求没有返回到浏览器,并且浏览器的视图状态没有更新,则不会在第二个请求中发送。

更新面板响应如下所示:

248|updatePanel|ctl00_ContentPlaceHolder1_up|
.......
__VIEWSTATE|/wEPDwUKLTM1OTc4......

然后在客户端更新视图状态。我会在第二个请求之前检查它是否正在更新。

话虽如此,我认为使用更新面板有点过时了。如果我是你,我会使用 javascript 和 webmetods。看看这个。当然,这将取决于确切的情况。在我看来,您使用的方法是肮脏和不清楚的。

于 2012-06-18T15:57:09.860 回答
1

我想如果您使用 Javascript 和页面回发“按下”两个按钮 - 那么只有一个服务器端事件处理程序将注册,因此您只会触发一个点击事件。

我猜页面模型的设计是围绕人类交互构建的——人类只会点击一个按钮,因此只有一个服务器端点击事件能够被触发。您的方法虽然非常狡猾 - 基本上已经颠覆了页面模型(按下 2 次按钮),因此模型停止了行为。

虽然只是在我的脑海中 - 但对我来说很有意义。

当我需要让 JavaScript 事件以 ViewState 类型的方式持久存在时 - 我推出了自己的持久性方法,例如

  1. 在表单上放置一个隐藏字段
  2. 当 JavaScript 触发时,JSON 将您想要在对您有意义的对象结构中持久化(或对象)的控制状态序列化
  3. 当页面重新加载时,然后使用 JavaScript(或 JQuery 等)来挑选出持久的 JSON 字符串。将其转回一个对象(如果您愿意,可以使用 JSON 解析器或 eval),然后使用它来重置页面状态。

如果您使用pageLoad() javaScript 方法,那么这将触发完整和部分回发,这可能对您的情况有用。

只是我的经验。也许对你相关/有帮助

于 2012-06-18T14:53:42.957 回答
1

我已经设法让它适用于我的案例,但我认为其他用户建议的一些选项也可能对我有用。由于我的案例看起来非常独特(部分原因是它是一种黑客方法),因此我在此答案中包含了一些其他建议以供将来参考。

  1. 由于 JavaScript 正在模拟两个按钮被单击,因此会进行两次连续的部分回发。第二个请求在第一个请求返回之前被触发,因此第二个服务器事件从第一个事件中获取旧的 ViewState 而不是更新的 ViewState。

  2. 由于我的客户端和服务器事件不必完全同步(它只需要与用户同步),我重新组织了函数背后的代码,以便每个客户端事件只需要一个部分回发,同时仍然保持逻辑事件流。需要明确的是,这与其说是真正的解决方案,不如说是一种解决方法。

    • Crab Bucket建议将 JSON 对象序列化为隐藏的表单字段。虽然不完全是我正在寻找的东西,但我认为值得一提,以防其他人偶然发现类似的问题。更多细节在这里
  3. Daniel建议使用页面方法,我已经(简要地)看了一下,似乎它可能有效。在这一点上为我离开更新面板并再次将页面与他的建议重新组合在一起,尽管由于页面上已经存在的内容,这需要相当多的工作。不过,我将来可能会回到这一点并尝试一下(或者将其用于其他用途)。有关使用 jQuery 调用页面方法使用 Web 服务的更多详细信息。

于 2012-06-18T21:12:44.057 回答