在.NET中使用AJAX和ViewState的行为不一致

时间:2008-12-09 20:50:02

标签: c# .net ajax updatepanel viewstate

我发现点击浏览器上的“刷新”按钮会暂时搞砸UpdatePanel中控件的ViewState。

以下是我的情况:我制作了一个自定义WebControl,用于在ViewState中存储值。我将此控件放在UpdatePanel中。当我点击浏览器上的“刷新”按钮时,它会暂时消除ViewState中的值。但是,在下一个回发中,在我点击“刷新”之前在ViewState中的值神奇地重新出现。

这种行为搞砸了我的webcontrol。在我点击“刷新”之后,控件返回到其初始状态,因为ViewState为空并且IsPostBack设置为false。但是,当我单击我的WebControl中的一个回发控件时,WebControl将在我点击“刷新”之前使用ViewState中的相同值重新加载。

奇怪的是,这只发生在我使用AJAX时。当我的控件在UpdatePanel之外时,Firefox会给我标准消息,“要显示此页面,Firefox必须发送重复之前执行的任何操作(例如搜索或订单确认)的信息(重新发送)(取消) “。这很好,因为至少行为是一致的。但是,我绝对必须在这个项目中使用AJAX。

所以这就是我想做的事情 - 我想让“刷新”行为保持一致。如果点击“刷新”根本不影响ViewState,那将是最好的。但是如果它必须消灭ViewState,那就好了,只要ViewState STAYS消失了。这些东西都没有价值消失并再次出现。

哦,是的,这是我的示例代码:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

namespace TestControls
{
    public class TestControl : WebControl
    {
        int _clickCount;
        bool _mustUpdate;

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);

            _clickCount = ((int)ViewState["clickCount"]);
            _mustUpdate = ((bool)ViewState["mustUpdate"]);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Controls.Clear();
            ControlCreator();
        }

        private void ControlCreator()
        {
            Label tempLabel = new Label();
            LiteralControl tempLiteral = new LiteralControl("<br/><br/>");
            LinkButton tempLink = new LinkButton();

            tempLink.ID = "testLink";
            tempLink.Text = "Click me!";
            tempLink.Click += new EventHandler(tempLink_Click);

            tempLabel.ID = "testLabel";
            tempLabel.Text = _clickCount.ToString();

            Controls.Add(tempLabel);
            Controls.Add(tempLiteral);
            Controls.Add(tempLink);
        }

        void tempLink_Click(object sender, EventArgs e)
        {
            _clickCount++;
            _mustUpdate = true;
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (_mustUpdate)
            {
                Controls.Clear();
                ControlCreator();

                _mustUpdate = false;
            }
        }

        protected override object SaveViewState()
        {
            ViewState["clickCount"] = _clickCount;
            ViewState["mustUpdate"] = _mustUpdate;

            return base.SaveViewState();
        }
    }
}

3 个答案:

答案 0 :(得分:1)

尝试以下方法......

    protected override void LoadViewState(object savedState)
    {
        if (savedState != null)
        {
            object[] myState = (object[])savedState;

            if (myState[0] != null) base.LoadViewState(myState[0]);
            if (myState[1] != null) _clickCount = ((int)myState[1]);
            if (myState[2] != null) _mustUpdate = ((bool)myState[2]);
        }
    }

    protected override object SaveViewState()
    {
        object[] allStates = new object[3];

        allStates[0] = base.SaveViewState();
        allStates[1] = _clickCount;
        allStates[2] = _mustUpdate;

        return allStates;
    }

基本上来自MSDN的Control.LoadViewState MethodControl.SaveViewState Method上面的代码。

答案 1 :(得分:1)

我只是重新阅读你的问题并意识到我错过了一些东西......

您正在点击浏览器刷新按钮!

这是一个问题吗? 是<!/强>

点击浏览器上的刷新按钮会发生什么? 它会刷新当前页面。如果有回发,它将重新发送帖子数据。

就页面而言,AJAX回调可能会更新ViewState,但点击浏览器刷新按钮将重新发布旧的ViewState。

有关此问题的讨论很丰富,你可以谷歌。

一个非常简单的想法可能是将信息存储在会话状态中。当然,这也有其自身的问题。但它可能会实现您的直接目标。

用于擦除回发历史记录(以防止重新发布)的提示是重新定向到同一页面。

答案 2 :(得分:0)

您的ViewState未被保存。 SaveViewState覆盖用于保存OBJECTS,而不是用于将东西放入ViewState包中。 ViewState包已经超出了肮脏的东西,你所做的改变将不会被持久化。您需要创建一个对象数组来加载/查看ViewState信息。

执行BlackMael所显示的内容。