I created a really simple control that contains a list of filter option controls in much the same way that a listbox has a list of listitems.
I'm having some trouble tring to get it to serialize in to viewstate as the serializer appears to be trying to serialize the base class properties and basically i end up with errors like - cannot serialize property "page" What do you think is my problem?
The Code:
[Serializable]
public class FilterOption : Control, ISerializable
{
public event EventHandler Checkchanged;
CheckBox _chk = new CheckBox();
Label _lbl = new Label();
public string Text
{
get { return _lbl.Text; }
set { _lbl.Text = value; }
}
public bool Checked
{
get { return _chk.Checked; }
set { _chk.Checked = value; }
}
public FilterOption()
{
Controls.Add(new LiteralControl("<li>"));
_chk.AutoPostBack = true;
_chk.CssClass = "checkbox";
Controls.Add(_chk);
Controls.Add(_lbl);
_chk.CheckedChanged += new EventHandler(_chk_CheckedChanged);
Controls.Add(new LiteralControl("</li>"));
}
public FilterOption(string Text, bool Checked)
{
Controls.Add(new LiteralControl("<li>"));
_chk.CssClass = "checkbox";
_lbl.Text = Text;
_chk.Checked = Checked;
Controls.Add(_chk);
Controls.Add(_lbl);
_chk.CheckedChanged += new EventHandler(_chk_CheckedChanged);
Controls.Add(new LiteralControl("</li>"));
}
public FilterOption(SerializationInfo info, StreamingContext context)
{
Controls.Add(new LiteralControl("<li>"));
_chk.CssClass = "checkbox";
_lbl.Text = (string)info.GetValue("Text", typeof(string));
_chk.Checked = (bool)info.GetValue("Text", typeof(bool));
Controls.Add(_chk);
Controls.Add(_lbl);
_chk.CheckedChanged += new EventHandler(_chk_CheckedChanged);
Controls.Add(new LiteralControl("</li>"));
}
void _chk_CheckedChanged(object sender, EventArgs e)
{
if (Checkchanged != null)
Checkchanged(this, new EventArgs());
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if(info == null)
throw new System.ArgumentNullException("info");
info.AddValue("Text开发者_如何学JAVA", _lbl.Text);
info.AddValue("Checked", _chk.Checked);
}
}
I literally only need to serialize the properties added to the serialization info in the GetObjectData method.
I'm using the following code to perform the serialization ...
List<FilterOption> options = new List<FilterOption>();
... add some items to the collection ...
StringWriter writer = new StringWriter();
XmlSerializer ser = new XmlSerializer(typeof(List<FilterOption>));
ser.Serialize(writer, options);
ViewState["Options"] = writer.ToString();
Oh yeh ... i forgot to add ... i got the information from here ... http://msdn.microsoft.com/en-us/library/ms973893.aspx
(in case it matters)
...
Thx Wardy
First of all you should split your control and serializable data. Second, .net framework contains several serialization types:
- Serialization utilities from
System.Runtime.Serialization
([BinaryFormatter][1]
and[SoapFormatter][2]
). Both of this foratters requires[SerializationAttribute][3]
for your class or implementing[ISerializable][4]
interface (if you need more flexible way controlling serialization process). Those serializers serialize all private fields for current class and all it descendants if that fields does not marked with[NonSerialializedAttribute][5]
.
Note: this serialization uses during .net remoting.
Xml serialization with
[XmlSerializer][6]
class. In this case your class should have parameterless constructor and this serializer serialize all public read/write properties for current class and all descendants that does not mark with[XmlIgnoreAttribute][7]
.[DataContractSerializer][8]
. This serializer requires that you entity should be marked with[DataContractAttribute][9]
and all properties should be marked with[DataMemberAttribute][10]
. Also this serializer could serialize classes serializable in two previous ways.
In general it's very bad practice try to serialize user control, because it definitely would contains non-serializable fields (that not marked with NonSerializedAttribute
). So you'll definitely receive error message during runtime.
The easiest way (and more appropriate from design point of view) is separate serializable data into separate class and choose right serialization technique.
I.e. if you want to use Xml-serialization you should create parameterless constructor for your class and use read/write properties:
public class FilterOption
{
public FilterOption() {}
public string MyLabel{get;set;}
public bool IsChecked{get;set;}
}
and now you could use your previous code:
var options = new List<FilterOption>
{
new FilterOption {MyLabel = "label", IsChecked = false},
new FilterOption {MyLabel = "label2", IsChecked = true}
};
StringWriter writer = new StringWriter();
XmlSerializer ser = new XmlSerializer(typeof(List<FilterOption>));
ser.Serialize(writer, options);
Apparently you cannot serialize a type that inherits a non serializable type even ifyou do not wish to serialize the non-serializable properties of your derived type.
I think this should be classed as a bug since the who point of interfaces like ISerializable is to specify exactly what it is you inted to serialize by manually implementing the method that handles the serialization.
In any case the solution to my particular scenario was to not bother serializing at all and simply save the information of interest in to viewstate which would then be reused on postbacks to rebuild controls in the exact same state ready for the page based postback events to occur.
Shame this isnt better documented somewhere because although microsoft does document the SaveViewState and LoadViewState methods of the page lifecycle they are very vague about how these events might be used, i'm guessing they are hoping someone in the community might provide an example.
I would post my code but its a nasty hack to get everything working so i don't thing it should be mainstream msdn code.
Ok for a small internal app though :)
You should take a look at this link, for XML Serialization
http://msdn.microsoft.com/en-us/library/ms950721.aspx
considering your comments. I have searched again and now I think that you have forgot to add this code in your GetObjectData()
function.
base.GetObjectData(si,context);
You cannot serialize your object because it contains objects which aren't serializable. ASP.NET controls (like CheckBox
and Label
are) are not serializable.
You should create a list of objects instead which contain just the data you really need, which will certainly a boolean
value and a string
.
You must then recreate the controls from this state on each Post request, but there is no other way I know of.
[Serializable]
public class FilterOption
{
public string MyLabel{get;set;}
public bool IsChecked{get;set}
}
EDIT:
You can put the attribute [NonSerialized]
above members you do not want to get serialized.
精彩评论