0

I have build a custom server control. Basically, this custom control is providing a textbox and a browser button that help users to fill the textbox. Behind the scene, I have a complex data structure that is describing the context and the user selection (simplified version below):

    [Serializable]
    public class PickerValue
    {
        public PickerType Type { get; set; }
        public string TargetUrl { get; set; }
        public static PickerValue Default()
        {
            return new PickerValue
            {
                TargetUrl = "/",
                Type = PickerType.Value1
            };
        }
    }

Then, in my control I declare a property of this type, maintaining in the view state:

    public PickerValue Value
    {
        get
        {
            var obj = ViewState["Value"];
            return (PickerValue)(obj != null ? obj : ViewState["Value"] = PickerValue.Default());
        }
        set
        {
            ViewState["Value"] = value;
        }
    }

Because my custom control hold such value and should raise postback events, I implemented IPostBackDataHandler in my control to convert and read the JSON representation (using newtonsoft.json) of this value (this will be used by the javascript code):

    public event EventHandler ValueChanged;

    protected virtual void OnValueChanged(EventArgs e)
    {
        if (ValueChanged != null) ValueChanged(this, e);
    }
    public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
    {
        var presentValue = JsonConvert.SerializeObject(Value);
        var postedValue = postCollection[postDataKey];



        if (!string.IsNullOrEmpty(presentValue) && !presentValue.Equals(postedValue))
        {
            Value = JsonConvert.DeserializeObject<PickerValue>(postedValue);
            return true;
        }
        else
        {
            return false;
        }
    }

    public void RaisePostDataChangedEvent()
    {
        OnValueChanged(EventArgs.Empty);
    }

And I also customize the rendering of the control to generate the proper <input type='hidden'> related to my control's value:

    protected override void RenderContents(HtmlTextWriter writer)
    {
        writer.AddAttribute(HtmlTextWriterAttribute.Type, "hidden");
        writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + "_data");
        writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
        writer.AddAttribute(HtmlTextWriterAttribute.Value, JsonConvert.SerializeObject(Value));
        writer.RenderBeginTag(HtmlTextWriterTag.Input);
        writer.RenderEndTag();
        RenderChildren(writer);
    }

Finally, I generate the textbox and the browse button using the (I guess) the proper way of using CreateChildControls:

    protected TextBox txtTargetUrl;
    protected Button btnBrowse;
    protected override void CreateChildControls()
    {
        this.txtTargetUrl = new TextBox();
        this.Controls.Add(this.txtTargetUrl);

        this.btnBrowse = new Button
        {
            Text = BrowseButtonText
        };
        this.Controls.Add(this.btnBrowse);
    }

This is nearly working. My internal input value is populated properly by the code, the postbacks rebuild properly the internal value, but my textbox lose its value. After each postback, the textbox is remaining empty.

What have I to correct in my code to maintain child controls' state?

Brian Mains
  • 50,520
  • 35
  • 148
  • 257
Steve B
  • 36,818
  • 21
  • 101
  • 174
  • What is the relationship of the hidden field to the textbox? Why is there a hidden field, which has the Value property? – Brian Mains Apr 22 '13 at 15:45
  • The user will be able to type the url of an item. For example `/pathto/something`. The actual control's value is a JSON string that contains a lot more data. Here is a very simplified version of the value `{"Type":3,"SelectedType":2,"TargetUrl":"/Documents","RootUrl":"/"}`. This value will be read/written by some javascript code that will display a dialog to help the user choose the correct url. But the user may still have the opportunity to paste the url if desired. Actually, the textbox will reflect one of the subproperty of the full value (TargetUrl for instance) – Steve B Apr 22 '13 at 15:52

0 Answers0