将输入值映射到复杂结构

时间:2013-04-09 13:44:29

标签: c# asp.net

让我们假设我有以下课程:

[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;
        }
    }        
}

但是,此代码仅在第一次回发时按预期工作。如果我在页面上添加一个按钮,我尝试读取值,第一个回发值将保留,第二个,不是。

我认为我的问题与页面生命周期有关。我不能确定后期阅读已经完成。

1 个答案:

答案 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"
            };
        }
    }
}