2

摘要:我有一个动态添加到页面的 web 控件。该控件有一个 HiddenField 子控件。我将控件的 ClientID 传递给将值设置为字符串(json 转换为字符串)的 jquery 小部件。当表单回传到服务器时,HiddenField 的值是一个空白字符串。我的值在 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);
    }


}
4

1 回答 1

1

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

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

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        EnsureChildControls();
    }
于 2013-10-09T18:21:20.183 回答