String *I am String* (自由大过天) 路漫漫其修远兮,吾以上下而求索

(道,可道,非常道)-----天之道,利而不害。圣人之道,为而不争。信言不美,美言不信。善者不辩,辩者不善。知者不博,博者不知。

导航

静态和动态控件回递数据的处理差别

Posted on 2005-06-01 20:39  goodbaby  阅读(537)  评论(0)    收藏  举报

关于asp.net回递数据和视图的讨论在去年的joycdoe上如火如涂,我也从中学习了很多知识,这是由动态控件所引发的讨论,对学习asp.net受益非浅。其实在两年前的joycode上从那篇动态用户控件就开始,之后在今年的msdn上一篇很热的,讨论ViewState和动态控件的文章(作者Scott(也是.Text的作者同时也是MVP))),几乎都是动态控件引发然后就分析asp.net的页面模型。我想讨论的也是这个,是我在学习时遇到的问题,同时在这些文章中我没遇到类似的讨论。我用asp.net 2.0时候学习时是发现一个有趣的现象。
private void RefreshAvailableRolesListBox()
    {
        lbxAvailableRoles.SelectedIndex = -1;
        lbxAvailableRoles.DataSource = Roles.GetAllRoles();
        lbxAvailableRoles.DataBind();

        if (lbxAvailableRoles.Items.Count == 0)
        {
            lblRoleInfoText.Text = "当前没有角色";
            lbxAvailableRoles.Visible = false;
            btnDeleteRole.Visible = false;
        }
        else
        {
            lblRoleInfoText.Text = "角色列表";
            lbxAvailableRoles.Visible = true;
            btnDeleteRole.Visible = true;
        }
    }
protected void Page_Init(object sender, EventArgs e)
    {
        RefreshAvailableRolesListBox();
    } 
protected void btnDeleteRole_Click(object sender, EventArgs e)
    {
        lblResults.Text = "fire";
        if (lbxAvailableRoles.SelectedIndex != -1)
        {
            try
            {
                Roles.DeleteRole(lbxAvailableRoles.SelectedValue);

                lblResults.Text = null;
                lblResults.Visible = true;
            }
            catch (Exception ex)
            {
                lblResults.Text = "不能删除角色 " + Server.HtmlEncode(ex.Message);
                lblResults.Visible = true;
            }
        }
程序可以正确执行,当删除一 个角色的时候lbxAvailableRoles.SelectedIndex != -1为false,说明在 Page_Init(object sender, EventArgs e)后lbxAvailableRoles.SelectedIndex 静态控件的postdata被处理了,这是没问题的。但我这样
protected void Page_Load(object sender, EventArgs e)
    {
        RefreshAvailableRolesListBox();
    } 
将RefreshAvailableRolesListBox();放在这里,执行结果是lbxAvailableRoles.SelectedIndex != -1为true,我以为是asp.net 2.0的原因,但我在2003上试也是同样的结果,我们知道在Page_Load后有一次PostData处理请看下面的.net源代码。
         this.Trace.Write("aspx.page", "Begin ProcessPostData");
                  }
                  this.ProcessPostData(this._requestValueCollection, true);
                  if (context1.TraceIsEnabled)
                  {
                        this.Trace.Write("aspx.page", "End ProcessPostData");
                  }
            }
            base.LoadRecursive();
            if (this.IsPostBack)
            {
                  if (context1.TraceIsEnabled)
                  {
                        this.Trace.Write("aspx.page", "Begin ProcessPostData Second Try");
                  }
                  this.ProcessPostData(this._leftoverPostData, false);
                  if (context1.TraceIsEnabled)
                  {
                        this.Trace.Write("aspx.page", "End ProcessPostData Second Try");
                        this.Trace.Write("aspx.page", "Begin Raise ChangedEvents");
                  }
去掉跟踪可以看出进行了两次PostData处理,但现在为什么不对呢。然后我把静态控件换成动态控件
private void Page_Load(object sender, System.EventArgs e)
  {
   // 在此处放置用户代码以初始化页面
   RefreshAvailableRolesListBox();
   Form1.Controls.Add(lbxAvailableRoles1);
   RefreshAvailableRolesListBoxDy();
  }
好,work了,在Page_Load后动态控件的PostData被正确设置,为什么动态控件被正确设置了而静态控件不对呢。看下面的.net源代码片段:

            foreach (string text1 in postData)
            {
                  if ((text1 == null) || Page.s_systemPostFields.Contains(text1))
                  {
                        continue;
                  }
                  Control control1 = this.FindControl(text1);
                  if (control1 == null)
                  {
                        if (!fBeforeLoad)
                        {
                              continue;
                        }
                        if (this._leftoverPostData == null)
                        {
                              this._leftoverPostData = new NameValueCollection();
                        }
                        this._leftoverPostData.Add(text1, null);
                        continue;
                  }
                  if (!(control1 is IPostBackDataHandler))
                  {
                        if (control1 is IPostBackEventHandler)
                        {
                              this.RegisterRequiresRaiseEvent((IPostBackEventHandler) control1);
                        }
                        continue;
                  }
                  IPostBackDataHandler handler1 = (IPostBackDataHandler) control1;
                  if (handler1.LoadPostData(text1, this._requestValueCollection))
                  {
                        this._changedPostDataConsumers.Add(handler1);
                  }
                  if (this._controlsRequiringPostBack != null)
                  {
                        this._controlsRequiringPostBack.Remove(text1);
                  }
            }
            ArrayList list1 = null;
   }

找了半天,原因我分析得出的就是,静态控件在第一次PostData处理的时候注意这句this._controlsRequiringPostBack.Remove(text1);text1是控件名称,这意思就是说PostData处理了你就该不再被下一次处理所以从controlsRequiringPostBack里删除,也就是说在之后的Page_Load后处理过的静态控件不再不处理,好了问题解决了,当然如果你的动态控件放在其他地方又是另一会事,这里真对这种情况。也许你有更好的解释,我们一起讨论。下次我想讨论可复用的对象模型,谈一点体会,学习心得。
6-1祝所有的小朋友节日快乐,也祝大家天天开心。