将输入值映射到复杂结构

本文关键字:复杂 结构 映射 输入 | 更新日期: 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"
            };
        }
    }
}