I have an xml file which acts as a data table. It holds various types of data. The data types could be different in any of the columns. An example would be: row(1)String, int, date; row(2)Binary, int, date; row(3)String, binary, int.
Which leads me to the problem i am trying to solve, how can I parse the cell contents and place a button in cells where the data type is binary or byte type.
This has been tricky because not only are all the cell contents of different types but the cells are not assigned to columntypes automatically, it must be done manually.
Any ideas on how to accomplish this?
P.S. I think that using the CellValidating event I might be able to get the behavior I want, however I am at a loss for how to validate that a string is actually binary data...
EDIT: Ok so I have decided that the easiest way to get to the desired result is to make the user choose the data type they wish to record. And then later check for that data type in each column and then place a button if that data type exists in a column.
I have a "TableFactory" class which makes the table that will be serialized and stored in xml. In this class I have added a "ColumnDataTypes" enum and a section to handle the types I want to allow, only 3 right now, Integer, String, and File(byte[]). The problem with this new approach is that in order to properly store the byte array I have to convert it to a Base64String. This however changes the data type to a string instead of a byte, which places me back at the beginning again...How do I parse the column data and logically determine that it is a byte array and not just a string. Once I know it is a byte array I can place a button in the cell that contains the byte array. Does anyone have any ideas as to how to accomplish this?
Table Factory Class:
using System.Data;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using XML_Database.usrctrls;
namespace XML_Database.data
{
public class TableFactory
{
//string _tableName;
DataTable _dt;
//public string TableName { get { return _tableName; } set { _tableName = value; } }
public TableFactory(string tableName)
{
if (this._dt == null)
{
this._dt = new DataTable(tableName);
}
}
public DataTable Table
{
get { return this._dt; }
set { this._dt = value; }
}
public void NewColumn(string ColumnName, ColumnTypes colType)
{
if (!this._dt.Columns.Contains(ColumnName))
{
switch (colType)
{
case ColumnTypes.String:
this._dt.Columns.Add(ColumnName, typeof(String));
break;
case ColumnTypes.Integer:
this._dt.Columns.Add(ColumnName, typeof(Int32));
break;
case ColumnTypes.Binary:
this._dt.Columns.Add(ColumnName, typeof(Byte[]));
break;
}
}
}
public void DeleteColumn(string ColumnName)
{
if (_dt.Columns.Contains(ColumnName))
{
_dt.Columns.Remove(ColumnName);
}
}
public void SaveTable(string Path)
{
data.encryptFiles._SALT = data.dboptions.Salt();
data.encryptStrings._SALT = data.dboptions.Salt();
string tablePath = Path + "\\" + _dt.TableName + ".xml";
DataSet ds = new DataSet();
XmlDocument xDoc = new XmlDocument();
ds.Tables.Clear();
ds.Tables.Add(_dt.Copy());
XmlElement xE = (XmlElement)Serialize(ds);
string strXml = xE.OuterXml.ToString();
xDoc.LoadXml(strXml);
xDoc.Save(tablePath);
if (data.dboptions.DBEncryptionOptions())
{
File.Delete(Path + "\\" + _dt.TableName + "_enc.xml");
data.encryptFiles.EncryptFile(tablePath, tablePath.Replace(".xml", "_enc.xml"), data.encryptStrings.Decrypt(data.dboptions.Pwd(), data.dboptions.Salt()));
}
}
public void LoadTable(string Path)
{
string tablePath = Path + "\\" + _dt.TableName + ".xml";
XmlDocument xDoc = new XmlDocument();
if (File.Exists(tablePath))
{
if (_dt.TableName.Contains("_enc"))
{
MemoryStream ms = new MemoryStream();
data.encryptFiles._SALT = data.dboptions.Salt();
data.encryptStrings._SALT = data.dboptions.Salt();
data.encryptFiles.DecryptToMemory(tablePath, out ms, data.encryptStrings.Decrypt(data.dboptions.Pwd(), data.dboptions.Salt()));
using (ms)
{
xDoc.Load(ms);
}
DataSet ds = (DataSet)Deserialize(xDoc.DocumentElement, typeof(DataSet));
_dt = ds.Tables[0];
}
else
{
xDoc.Load(tablePath);
DataSet ds = (DataSet)Deserialize(xDoc.DocumentElement, typeof(DataSet));
_dt = ds.Tables[0];
}
}
}
private object Deserialize(XmlElement xmlElement, System.Type type)
{
Object transformedObject = null;
try
{
Stream memStream = StringToStream(xmlElement.OuterXml);
XmlSerializer serializer = new XmlSerializer(type);
transformedObject = serializer.Deserialize(memStream);
}
catch (Exception)
{
}
return transformedObject;
}
private Stream StringToStream(string p)
{
MemoryStream memStream = null;
try
{
byte[] buffer = Encoding.UTF8.GetBytes(p);
memStream = new MemoryStream(buffer);
}
catch (Exception)
{
}
finally
{
memStream.Position = 0;
}
return memStream;
}
private XmlElement Serialize(object TransformObject)
{
XmlElement serializedElement = null;
try
{
MemoryStream memStream = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(TransformObject.GetType());
serializer.Serialize(memStream, TransformObject);
memStream.Position = 0;
XmlDocument xDoc = new XmlDocument();
xDoc.Load(memStream);
serializedElement = xDoc.DocumentElement;
}
catch (Exception)
{
}
return serializedElement;
}
}
}
Any help is greatly appreciated! :)
EDIT: I am able to add Images but not regular files. Ideally adding both files and images is the desirable functionality. But so far only images will go into my Byte array column. I can store files if I change the column data type to string and store converted Base64String, but I still can't figure out how to parse the data to confirm that it is a file and not just text...
EDIT: Ok I am closer to solving this problem, but not sure how to get over the hump...I can get a button to show up but not in the correct cell. Here is some more code to assist anyone in helping me answer this question...
private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
button1.ForeColor = Color.Red;
try
{
for (int i = 0; i < dataGridView1.RowCount; i++)
{
foreach (DataGridViewCell cell in dataGridView1.Rows[i].Cells)
{
if (cell.Value != null)
{
if (TryParseBinary(cell.Value.ToString()))
{
var buttonCell = new DataGridViewButtonCell();
buttonCell.Value = "Export File";
buttonCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
dataGridView1.Rows[i].Cells[cell.ColumnIndex] = buttonCell;
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Grid Validation Error: " + ex.Message);
}
}
private bool TryParseBinary(string p)
{
try
{
string path = "C:\\Temp\\" + DateTime.Now.Ticks.ToString() + ".test";
byte[] bytes = Convert.FromBase64String(p);
File.WriteAllBytes(path, bytes);
//File.Delete(path);
return true;
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
return false;
}
}
The "TryParseBinary" is the problem. It needs to create a valid file to return "true", but I'm not sure how to make it smart enough to tell if what it just wrote is a valid file...