将输入值映射到复杂结构
本文关键字:复杂 结构 映射 输入 | 更新日期: 2023-09-27 18:08:20
假设我有这样一个类:
[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;
}
如何编写自定义控件的Data属性
到目前为止,我已经编写了以下代码: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;
}
}
}
然而,这段代码仅在第一次回发时按预期工作。如果我在页面上添加一个按钮,在这个按钮中我尝试读取值,那么第一个回发的值将被保留,第二个则不保留。
我认为我的问题与页面生命周期有关。
在Msdn的page: IPostBackDataHandler接口的帮助下,我找到了一个可行的解决方案。
我没有将存储嵌套到<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"
};
}
}
}