我已经构建了一个自定义服务器控件。基本上,这个自定义控件提供了一个文本框和一个浏览器按钮,可以帮助用户填充文本框。在幕后,我有一个复杂的数据结构,描述了上下文和用户选择(下面的简化版本):
[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);
}
这几乎正常。我的内部输入值由代码正确填充,回发正确地重建了内部值,但我的文本框失去了它的值。每次回发后,文本框仍为空。
我有什么要在代码中纠正以维护子控件的状态?