我已经构建了一个自定义服务器控件。基本上,这个自定义控件提供了一个文本框和一个帮助用户填充文本框的浏览器按钮。在幕后,我有一个复杂的数据结构来描述上下文和用户选择(下面的简化版本):
[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
};
}
}
然后,在我的控件中,我声明了一个这种类型的属性,保持在视图状态:
public PickerValue Value
{
get
{
var obj = ViewState["Value"];
return (PickerValue)(obj != null ? obj : ViewState["Value"] = PickerValue.Default());
}
set
{
ViewState["Value"] = value;
}
}
因为我的自定义控件持有这样的值并且应该引发回发事件,所以我IPostBackDataHandler
在我的控件中实现了转换和读取该值的 JSON 表示(使用 newtonsoft.json)(这将由 javascript 代码使用):
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);
}
而且我还自定义控件的呈现以生成<input type='hidden'>
与我的控件值相关的正确值:
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);
}
最后,我使用(我猜)正确的使用方式生成文本框和浏览按钮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);
}
这几乎可以工作了。我的内部输入值由代码正确填充,回发正确地重建了内部值,但我的文本框失去了它的价值。每次回发后,文本框都是空的。
为了维护子控件的状态,我需要更正代码中的哪些内容?