ViewState连续部分回发之间丢失了吗?

时间:2012-06-18 14:35:56

标签: javascript asp.net postback viewstate

背景

我有一个页面,我用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. 或许有更好的方法可以做到这一点吗?

3 个答案:

答案 0 :(得分:2)

我对此进行了测试,并且查看状态确实会对部分请求进行更新。 2个连续的部分请求可能存在问题。第一个请求必须在第二个请求激活之前返回才能生效。

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

更新面板响应如下所示:

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

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

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

答案 1 :(得分:1)

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

我想页面模型的设计是围绕人类交互构建的 - 人类只会点击一个按钮,因此只能触发一个服务器端点击事件。你的方法非常狡猾 - 基本上颠覆了页面模型(按下2个按钮),因此模型停止表现。

虽然我的头顶但是对我来说很有意义。

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

  1. 在表单上放置隐藏字段
  2. 当JavaScript触发时,JSON将您希望在对象结构中持久存储(或对象)的控件状态序列化为您有意义
  3. 当页面重新加载然后使用JavaScript(或JQuery等..)来挑选持久化的JSON字符串。将其转回一个对象(如果你愿意,可以使用JSON解析器或eval),然后使用它来重置页面状态。
  4. 如果您使用pageLoad() javaScript方法,则会触发完整和部分回发,这可能对您的情况有用。

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

答案 2 :(得分:1)

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

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

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

    • Crab Bucket建议将JSON对象序列化为隐藏的表单字段。虽然不完全是我正在寻找的,但我认为值得一提,以防其他人偶然遇到类似的问题。更多详情here
  3. Daniel建议使用页面方法,我已经(简要)看了一下,看起来它可能会起作用。暂时离开更新面板并将页面重新组合在一起并提供他的建议,但由于页面上已经存在的内容,这将需要相当多的工作。我可能会在将来回到这个问题并尝试一下(或者将其用于其他东西)。有关using jQuery to call page methodsconsume web services的详细信息。