让我们假设我有以下课程:
[Serializable]
public class Data{
public string Prop1 { get; set;}
public int Prop2 { get; set; }
}
我正在构建一个自定义服务器控件,它将其值存储到input type=hidden
字段中,该字段包含此类的json序列化版本(由客户端的某种javascript使用)。此值可能会被javascript代码修改,并且应始终在客户端和服务器端都是准确的。
首次启动时预期的Html输出:
<input type="hidden" value="{ Prop1:'zzz', Prop2: 42 }" />
为了简化开发人员的使用,我想在我的服务器控件中发布一个这种类型的属性,可以直接编写,包括嵌套属性:
public class MyControl : WebControl {
public Data Data {
get; // correct implementation to be found
}
}
// somewhere else
void foo(){
var myControl = (MyControl)FindControl("my");
myControl.Data.Prop1 = "some value";
myControl.Data.Prop2 = 1234;
}
我应该如何编写自定义控件的数据属性?
到现在为止,我已经写了这段代码:
public class MyControl : Control
{
protected HiddenField inputInternalValue;
protected override void CreateChildControls()
{
this.inputInternalValue = new HiddenField();
this.Controls.Add(this.inputInternalValue);
}
private void inputInternalValue_ValueChanged(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(inputInternalValue.Value))
{
// use of Newtonsoft's Json convert
m_Value = JsonConvert.DeserializeObject<MyControlValue>(inputInternalValue.Value);
}
}
protected override void OnPreRender(System.EventArgs e)
{
base.OnPreRender(e);
inputInternalValue.Value = JsonConvert.SerializeObject(Value);
}
[Serializable]
public class MyControlValue
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
public static MyControlValue Default()
{
return new MyControlValue
{
Prop1 = "some default value",
Prop2 = "999"
};
}
}
private MyControlValue m_Value;
public MyControlValue Value
{
get
{
EnsureChildControls();
if (m_Value == null)
{
if (!string.IsNullOrEmpty(inputInternalValue.Value))
{
// use of Newtonsoft's Json convert
m_Value = JsonConvert.DeserializeObject<MyControlValue>(
inputInternalValue.Value
);
}
else
{
m_Value = MyControlValue.Default();
}
}
return m_Value;
}
}
}
但是,此代码仅在第一次回发时按预期工作。如果我在页面上添加一个按钮,我尝试读取值,第一个回发值将保留,第二个,不是。
我认为我的问题与页面生命周期有关。我不能确定后期阅读已经完成。
答案 0 :(得分:0)
在Msdn's page: IPostBackDataHandler Interface的帮助下,我找到了一个可行的解决方案。
我没有将存储嵌套到<asp:hidden>
控件中,而是手动编写了回发处理。
结果如下:
public class MyControl : Control
{
protected override void CreateChildControls()
{
// other controls
}
public MyControlValue Value
{
get
{
var obj = ViewState["Value"];
return (MyControlValue )(obj != null ? obj : ViewState["Value"] = MyControlValue .Default());
}
set
{
ViewState["Value"] = value;
}
}
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<MyControlValue>(postedValue);
return true;
}
else
{
return false;
}
}
public void RaisePostDataChangedEvent()
{
OnValueChanged(EventArgs.Empty);
}
#region Event
public event EventHandler ValueChanged;
protected virtual void OnValueChanged(EventArgs e)
{
if (ValueChanged != null) ValueChanged(this, e);
}
#endregion Event
[Serializable]
public class MyControlValue
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
public static MyControlValue Default()
{
return new MyControlValue
{
Prop1 = "some default value",
Prop2 = "999"
};
}
}
}