By way of background to this question, I want to bind a "code made" DataTable
to an aspx:GridView
. To persist this table I implement the ISerializable
interface. The table is displayed correct, but in postback for sorting the rows, a InvalidCastExcpetion
is thrown because elements in the row.ItemArray changed from type double
to type string
.
This is the class. Note: two constructors, one for constructing the DataTable initialy and one for constructing the table in the deserialisation process:
[global::System.Serializable()]
[global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedTableSchema")]
public partial class HeatMapVisualisationDataTable : DataTable, System.Runtime.Serialization.ISerializable
{
#region members
public double _valueMin { get; private set; }
public double _valueMax { get; private set; }
#endregion membders
public HeatMapVisualisationDataTable(XemlExperimentHeatMapDataTable data)
: base("result", "http://gmd.mpimp-golm.mpg.de/HeatMap")
{
this.Columns.Add(new DataColumn("metabolite", typeof(Guid)));
this.Columns.Add(new DataColumn("name", typeof(string)));
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = this.Columns["metabolite"];
this.PrimaryKey = PrimaryKeyColumns;
SortedDictionary<int, DataColumn> headers = new SortedDictionary<int, DataColumn>();
foreach (var item in data.AsParallel().AsEnumerable().Select(x => x.ObservationPointId).Distinct().OrderBy(x => x))
{
DataColumn dc = this.Columns.Add(item.ToString(), typeof(Double));
headers.Add(item, dc);
}
foreach (var item in data)
{
DataRow tmpRow = base.Rows.Find(item.MetaboliteId);
if (tmpRow == null)
{
tmpRow = base.Rows.Add(new object[] { item.MetaboliteId });
tmpRow["name"] = item.MetaboliteName;
}
tmpRow[headers[item.ObservationPointId]] = item.value;
}
this.AcceptChanges();
_valueMax = data.AsParallel().AsUnordered().Max(x => x.value);
_valueMin = data.AsParallel().AsUnordered().Min(x => x.value);
}
public HeatMapVisualisationDataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt) :
base(info, ctxt)
{
_valueMin = (double)info.GetValue("valueMin", typeof(double));
_valueMax = (double)info.GetValue("valueMax", typeof(double));
}
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)
{
base.GetObjectData(info, ctxt);
info.AddValue("valueMin", _valueMin);
info.AddValue("valueMax", _valueMax);
}
}
As I can observe by reading the schema in the SerializationInfo
in the constructor HeatMapVisualisationDataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)
, the table is correct serialised and is comming correct from the "store" in terms of the serilaised xml schema. However, looking at the constructed base class in this constructor, all columns of type double
befor serialsation are now of type string
. What am I doing wrong?
Update 1: I could also reproduce this issue by changing the the numeric datatype from double
to float
or decimal
. The primary key column of type Guid
is deserialised in to the correct type.
Update 2: To my opinion the described behavior is a follow up of some DataTable.ReadXml()
issues where DataTypes of columns get replaced by String.
Thanks, Jan