代码之家  ›  专栏  ›  技术社区  ›  David

ASP.NET自定义控件:何时调用LoadPostData()?

  •  7
  • David  · 技术社区  · 14 年前

    我开发了一个扩展ListBox的自定义控件。其思想是,控件“记住”客户端对其元素所做的修改(例如,由于AJAX请求)。

    它的工作方式是,控件还呈现一个隐藏的输入,AJAX请求的结果存储在隐藏的输入中。这被发回,控件的LoadPostData()方法查找隐藏的输入,如果隐藏的输入有数据,则从中创建ListItem集合。

    这个很好用 只要用户从列表框中进行了选择

    我假设LoadPostData方法只有在POST数据集合包含与控件的UniqueID(即HTML中的“name”属性)相对应的数据时才被调用。如果用户没有从列表框中进行选择,则列表框的UniqueID的post数据中不包含任何内容,并且不会调用LoadPostData()。对吗?

    有谁能建议我如何确保每次回发时都调用自定义ListBox的LoadPostData()方法,而不管用户是否进行了选择?

    大卫

    3 回复  |  直到 14 年前
        1
  •  8
  •   Rozwel    14 年前

    我对此有点晚了,但为了将来的参考,下面是我如何完成类似的事情的…

    我的控件是一个使用节点模板的树。我处理的问题是如何捕获客户端对节点展开/折叠状态的更改。最终奏效的是:

    在CreateChildControls中,将隐藏字段添加到我的根控件的控件集合中。

    protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
    {
        ...
        _cdExpanded = new HiddenField();
        _cdExpanded.ID = "cdExpanded";
        this.Controls.Add(_cdExpanded);
        ...
    }
    

    在OnInit呼叫中

    protected override void OnInit(EventArgs e)
    {
        ...
        Page.RegisterRequiresPostBack(this);
        ...
    }
    

    在LoadPostData中,在post集合中查找与隐藏字段的UniqueID(而不是ClientID)匹配的值:

    public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
    {
        ...
        string cdExpanded = postCollection[_cdExpanded.UniqueID];
        ...
    }
    

        string ToggleScript
        {
            get
            {
                return "ToggleNode('" + this.ClientID + "', '" + _TreeRoot.ClientID + "');";
            }
        }
        protected override void Render(HtmlTextWriter writer)
        {
            ...
            if (this.HasChildren)
            {
                writer.AddAttribute("onclick", ToggleScript);
            }
            ...
        }
    

    这使得通过getElementById查找隐藏字段相当容易:

    function ToggleNode(nodeID, treeID) {
    var cdExpanded = document.getElementById(treeID + "_cdExpanded");
    ...
    }
    

    然后JavaScript根据所发生事件的需要修改隐藏字段的值。当我们回到服务器时,我能够解析出这个字段的内容,并在再次呈现之前根据需要修改控件状态(注意:我实际上使用了3个隐藏字段来跟踪不同的事件,但概念是相同的)

    希望这对以后的人有帮助

        2
  •  3
  •   Martin Clarke    14 年前

    只在选中一个项目时才工作听起来很奇怪。一种快速检查是否调用了LoadPostData的方法是启用跟踪并将以下内容放入IPostBackDataHandler.LoadPostData(…)。

    Page.Trace.Write("My control", "LoadPostData");
    

    如果是这样的话,你应该确保你有以下几点:

    Page.RegisterRequiresPostBack(this) in OnInit
    

    这是一个完整的样本控制。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.ComponentModel.Design;
    using System.ComponentModel;
    using System.Web.UI.Design;
    
    namespace Controls
    {
        public sealed class ExtendedListBoxDesigner : ControlDesigner
        {
    
            public override string GetDesignTimeHtml()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<div>My designer</div>");
                return sb.ToString();
            }
    
        }
    
        [DesignerAttribute(typeof(ExtendedListBoxDesigner), typeof(IDesigner))]
        public class ExtendedListBox : ListBox, INamingContainer, IPostBackDataHandler 
        {
            bool IPostBackDataHandler.LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
            {
                Page.Trace.Write("ExtendedListBox", "LoadPostData");
                return true;
            }
    
    
            protected override void OnInit(EventArgs e)
            {
                Page.RegisterRequiresPostBack(this);
                base.OnInit(e);
            }
    
            protected override void RenderContents(HtmlTextWriter writer)
            {
                base.RenderContents(writer);
                writer.Write(string.Format("<input type=\"hidden\" name=\"{0}_dummy\" value=\"alwaysPostBack\">", this.ID));
            }
    
        }
    }
    

    页面看起来像这样。

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ControlSamlpe._Default" Trace="true" %>
    <%@ Register Assembly="Controls" Namespace="Controls" TagPrefix="sample" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
        <sample:ExtendedListBox runat="server" ID="extListBox"></sample:ExtendedListBox>
        <asp:Button runat="server" ID="go" />
        </div>
        </form>
    </body>
    </html>
    

        3
  •  1
  •   David    14 年前

    我已经确定,除非post数据包含与控件的UniqueID同名的项,否则不会调用LoadPostData()方法[编辑:在Init()期间调用Page.registerrequirepostback可以克服这个问题。]我可以理解原因,但这是非常有限的。

    我克服了这个问题,在LoadPostData()方法中根本不处理它。相反,我在一个方法中处理它,而我在OnLoad()中调用它。

    使用此方法时需要记住两件事:

    2) 由于OnLoad()发生在ViewState处理代码之后,因此在创建ListItems之后需要手动设置SelectedValue。否则,如果列表框是通过AJAX填充的,并且用户进行了选择,那么选择将丢失。

    我希望这对将来的人有帮助。