JQuery 修改后的隐藏字段值在回发到服务器时为空

JQuery modified Hidden Field Value is empty when posted back to the server

本文关键字:服务器 修改 隐藏 字段 JQuery      更新时间:2023-09-26

摘要:我有一个动态添加到页面的 Web 控件。 该控件具有 HiddenField 子控件。 我正在将控件的 ClientID 传递给一个 jquery 小部件,该小部件将值设置为字符串(json 转换为字符串(。 当表单回发到服务器时,隐藏字段的值为空白字符串。 I 值位于 Request.Form[UniqueID] 对象中。 值是使其返回到服务器。 问题是,当我需要该值而不修改大量旧代码时,我无法访问 Request 对象。

奇怪的是,selectmany 控件是我遇到问题的控件,但它继承自正常工作的 SelectOne。我认为我在 selectmany 类中做错了什么,因为即使我尝试将一个值推送到 SelectOneHiddenValue 中,它也无法正常工作,但是当 SelectOne 使用它时它可以正常工作。

选择一项:

[ToolboxData("<{0}:SelectOne runat=server></{0}:SelectOne>")]
public class SelectOne : Panel, IControl,ISelectOne
{
    #region structure
    private readonly Panel _selectOneTextboxContainer = new Panel();
    protected readonly TextBox SelectOneTextbox = new TextBox();
    protected readonly HiddenField SelectOneHiddenValue = new HiddenField();
    private readonly Panel _selectOneDropdownImageContainer = new Panel();
    private readonly Image _selectOneDropDownImage = new Image();
    #endregion
    private readonly IList<LookupItem> _selectedItems = new List<LookupItem>();
    #region properties
    public IList<LookupItem> SelectedItems { get { return _selectedItems; } }
    public bool MultiSelect { get; set; }
    public DisplayOption Display { get; set; }
    public string Name { get; set; }
    [DefaultValue(0)]
    public int LookupValueOrgID
    {
        get
        {
            EnsureChildControls();
            return Convert.ToInt32(String.IsNullOrEmpty(SelectOneHiddenValue.Value) ? "0" : SelectOneHiddenValue.Value);
        }
        set
        {
            EnsureChildControls();
            SelectOneHiddenValue.Value = value.ToString();
        }
    }
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]
    public string Text
    {
        get
        {
            EnsureChildControls();
            return SelectOneTextbox.Text;
        }
        set
        {
            EnsureChildControls();
            SelectOneTextbox.Text = value;
        }
    }
    /// <summary>
    /// The minimum number of characters a user has to type before the autocompleter activates.
    /// </summary>
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue(1)]
    [Localizable(true)]
    public int MinChars
    {
        get
        {
            int b = (ViewState["MinChars"] == null ? 1 : (int)ViewState["MinChars"]);
            return b;
        }
        set
        {
            ViewState["MinChars"] = value;
        }
    }
    /// <summary>
    /// The number of backend query results to store in cache. If set to 1 (the current result), no caching will happen. Must be >= 1.
    /// </summary>
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue(10)]
    [Localizable(true)]
    public int CacheLength
    {
        get
        {
            int b = (ViewState["CacheLength"] == null ? 10 : (int)ViewState["CacheLength"]);
            return b;
        }
        set
        {
            ViewState["CacheLength"] = value;
        }
    }
    public string OuterMarkupClientID
    {
        get { return "SelectOne_Container" + ClientID; }
    }
    /// <summary>
    /// If true, target input text is appended to
    /// If false, target input text is replaced
    /// </summary>
    public bool AppendSelectedTextToInput { get; set; }
    public virtual string ContainerClass
    {
        get { return "SelectOneContainer"; }
    }
    #endregion
    #region constructor
    public SelectOne()
    {
        SetCssClasses();
    }
    #endregion
    #region lifecycle overrides
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        AddChildrenToControlCollection();
    }
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        SetupClientEvents();
        ControlHelper.AddRequiredControl(this);
        var resourceName = string.Empty;
        var cs = Page.ClientScript;
        resourceName = "UI.Controls.resources.images.DropDownButton.gif";
        _selectOneDropDownImage.ImageUrl = cs.GetWebResourceUrl(GetType(), resourceName);
        SelectOneTextbox.Attributes.Add("lookupOrgID", LookupOrgID.ToString());
        SelectOneTextbox.Attributes.Add("cacheLength", CacheLength.ToString());
        SelectOneTextbox.Attributes.Add("service", Service);
        SelectOneTextbox.Attributes.Add("selectOneTextboxId", SelectOneTextbox.ClientID);
        SelectOneTextbox.Attributes.Add("selectOneHiddenValueId",SelectOneHiddenValue.ClientID);
    }
    #endregion
    #region private helpers
    private void SetCssClasses()
    {
        this.CssClass = ContainerClass + " AutocompleteContainer";
        _selectOneDropDownImage.CssClass = "SelectOneDropDownImage";
        SelectOneTextbox.CssClass = "SelectOneTextbox QuantifiTextBox";
        _selectOneTextboxContainer.CssClass = "SelectOneTextboxContainer";
        _selectOneDropdownImageContainer.CssClass = "SelectOneDropDownImageContainer";
    }
    private void SetupClientEvents()
    {
        ControlHelper.RegisterAutoCompleteScript(this);
        var resourceName = "UI.Controls.resources.scripts.SelectOne.js";
        string js;
        using (var sr = new StreamReader(GetType().Assembly.GetManifestResourceStream(resourceName)))
        {
            js = sr.ReadToEnd();
            sr.Close();
        }
        ClientScriptProxy.Current.RegisterStartupScript(this, typeof(SelectOne), "SelectOneJS", js, true);
        _selectOneDropDownImage.Attributes.Add("onclick", "SelectOne_ImageClick('" + SelectOneTextbox.ClientID + "');");
    }
    private void AddChildrenToControlCollection()
    {
        _selectOneTextboxContainer.Controls.Add(SelectOneTextbox);
        this.Controls.Add(_selectOneTextboxContainer);
        _selectOneDropdownImageContainer.Controls.Add(_selectOneDropDownImage);
        this.Controls.Add(_selectOneDropdownImageContainer);
        this.Controls.Add(SelectOneHiddenValue);
    }
    #endregion
}

选择多个:

[ToolboxData("<{0}:SelectMany runat=server></{0}:SelectMany>")]
public class SelectMany : SelectOne, ISelectMany
{
    #region structure
    private readonly Panel _selectedItemsPanel = new Panel();
    private readonly HiddenField _selectManyHiddenField = new HiddenField();
    public override string ContainerClass
    {
        get
        {
            return "SelectManyControlContainer";
        }
    }
    #endregion
    public SelectMany()
    {
        MultiSelect = true;
    }
    #region lifecycle overrides
    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        _selectManyHiddenField.ID = "SelectedItemsHiddenValue";
        this.Controls.Add(_selectedItemsPanel);
        this.Controls.Add(_selectManyHiddenField);
        SelectOneTextbox.Attributes.Add("data-multiselect", MultiSelect.ToString());
    }
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        var resourceName = "jquery.SelectedItemCollection.js";
        ClientScriptProxy.Current.RegisterClientScriptInclude(this, Page.ClientScript.GetWebResourceUrl(this.GetType(),resourceName));
        var serializer = new JavaScriptSerializer();
        var startupScript = String.Format("'n$('#{0}').each(function(){{" +
                                          "var selectedPlugin = $(this).SelectedItemCollection(" +
                                          "       {{" +
                                          "          itemData: {1}," +
                                          "          deleteImageUrl: '{2}'," +
                                          "          selectedTextId: '{3}', " +
                                          "          hiddenTextFieldId: '{4}' " +
                                          "       }});}});'n",
            this.ClientID, 
            serializer.Serialize(SelectedItems),
            GetDeleteImageUrl(),
            SelectOneTextbox.ClientID,
            _selectManyHiddenField.ClientID
            );
        ClientScriptProxy.Current.RegisterStartupScript(this,this.GetType(),"SelectedItemsJs_" + this.ClientID,startupScript,true);
    }
    #endregion
    #region public api
    public void BindForm()
    {
        EnsureChildControls();
        this.DataBind();
        var jsonString = _selectManyHiddenField.Value;
        SelectedItems.Clear();
        if (!jsonString.IsNullOrEmpty())
        {
            Json.Decode<IEnumerable<LookupItem>>(jsonString).ForEach(li => SelectedItems.Add(li));    
        }
    }
    #endregion
    private string GetDeleteImageUrl()
    {
        var cs = Page.ClientScript;
        const string resourceName = "UI.Controls.resources.images.close.gif";
        return cs.GetWebResourceUrl(this.GetType(), resourceName);
    }

}

嗯,这是一件愚蠢的事情。 我花了很长时间才找到。 基本上,不要滥用EnsureChildControls((方法。 基类在访问它的某些属性之前调用它。 这在恢复 ViewState 之后调用了 RecreateChildControls((,但在我检查值之前。

为了纠正这个问题,我在 OnInit 覆盖中添加了基类和派生类的 EnsureChildControls((。 这样,我的所有控件都将正确创建,ViewState 将在创建后还原。

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        EnsureChildControls();
    }