在datagridview中显示二进制内容的按钮

时间:2013-01-14 21:29:49

标签: c# xml datagridview binary-data

我有一个xml文件,它充当数据表。它包含各种类型的数据。任何列中的数据类型都可能不同。一个例子是:row(1)String,int,date; row(2)二进制,整数,日期; row(3)String,binary,int。

这引出了我想解决的问题,如何解析单元格内容并在数据类型为二进制或字节类型的单元格中放置一个按钮。

这很棘手,因为不仅所有细胞内容都是不同类型,而且细胞没有自动分配到columntypes,必须手动完成。

关于如何实现这一目标的任何想法?

P.S。我认为使用CellValidating事件我可能能够获得我想要的行为,但是我对如何验证字符串实际上是二进制数据感到茫然......

编辑:好的,所以我已经确定获得所需结果的最简单方法是让用户选择他们想要记录的数据类型。然后在每列中检查该数据类型,如果该数据类型存在于列中,则放置一个按钮。

我有一个“TableFactory”类,它将生成将被序列化并存储在xml中的表。在这个类中,我添加了一个“ColumnDataTypes”枚举和一个处理我想要允许的类型的部分,现在只有3个,Integer,String和File(byte [])。这种新方法的问题是,为了正确存储字节数组,我必须将其转换为Base64String。然而,这会将数据类型更改为字符串而不是字节,这使我再次回到开头...如何解析列数据并从逻辑上确定它是字节数组而不仅仅是字符串。一旦我知道它是一个字节数组,我可以在包含字节数组的单元格中放置一个按钮。有没有人对如何做到这一点有任何想法?

表工厂类:

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

非常感谢任何帮助! :)

编辑:我可以添加图片但不能添加常规文件。理想情况下,添加文件和图像是理想的功能。但到目前为止,只有图像会进入我的Byte数组列。如果我将列数据类型更改为字符串并存储已转换的Base64String,我可以存储文件,但我仍然无法弄清楚如何解析数据以确认它是文件而不仅仅是文本......

编辑:好的我更接近于解决这个问题,但不知道如何克服困难...我可以得到一个按钮显示但不在正确的单元格中。这里有一些代码可以帮助任何人帮我回答这个问题...

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

“TryParseBinary”是问题所在。它需要创建一个有效的文件来返回“true”,但我不知道如何使它足够聪明,以告诉它刚才写的是一个有效的文件......

1 个答案:

答案 0 :(得分:0)

好的,所以我能够为我的问题创建一个解决方案。这不是我想要的,但它完成了这项工作。我为我的datagridview检查了“DragDrop”方法,检查数据表中是否存在“File”和“MIME”列。然后我创建那些列,如果它们不存在,如果他们这样做,我将转换为Base64String的文件字节添加到“文件”列,文件扩展名添加到“MIME”列。然后我将“RowsAdded”事件更改为“文件”单元格到按钮。但是目前它没有保留文本“导出文件”,但我会继续研究那部分,这似乎是一个简单的修复。以下是我的代码:

    private void dataGridView1_DragDrop(object sender, DragEventArgs e)
    {
        try
        {
            Point cursorPosition = dataGridView1.PointToClient(Cursor.Position);
            DataGridView.HitTestInfo info = dataGridView1.HitTest(cursorPosition.X, cursorPosition.Y);
            tableFactory = new data.TableFactory(TablesDropDown.SelectedValue.ToString());
            tableFactory.LoadTable(dbPath);

            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

                foreach (DataColumn col in tableFactory.Table.Columns)
                {
                    if (col.ColumnName != "MIME" && col.ColumnName != "File")
                    {
                        tableFactory.NewColumn("MIME", ColumnTypes.String);
                        tableFactory.NewColumn("File", ColumnTypes.String);
                        tableFactory.SaveTable(dbPath);
                        ColumnsDataGrid();

                        dataGridView1.Rows[info.RowIndex].Cells["File"].Value = Convert.ToBase64String(GetFile(files));
                        FileInfo f = new FileInfo(files[0]);
                        dataGridView1.Rows[info.RowIndex].Cells["MIME"].Value = f.Extension;
                    }
                    else
                    {
                        dataGridView1.Rows[info.RowIndex].Cells["File"].Value = Convert.ToBase64String(GetFile(files));
                        FileInfo f = new FileInfo(files[0]);
                        dataGridView1.Rows[info.RowIndex].Cells["MIME"].Value = f.Extension;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("This was not a valid file to store in the database. Error Msg: " + ex.Message);
        }
    }


    private byte[] GetFile(string[] files)
    {
        byte[] bytes = null;
        foreach (string file in files)
        {
            FileInfo fileInfo = new FileInfo(file);
            if (File.Exists(file))
            {
                bytes = File.ReadAllBytes(file);
            }
        }
        return bytes;
    }


    private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
    {
        button1.ForeColor = Color.Red;
        try
        {
            for (int i = 0; i < dataGridView1.RowCount; i++)
            {
                foreach (DataGridViewColumn col in dataGridView1.Columns)
                {
                    if (col.Name == "File")
                    {
                        var buttonCell = new DataGridViewButtonCell();
                        buttonCell.Value = "Export File";
                        buttonCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
                        dataGridView1.Rows[i].Cells[col.Index] = buttonCell;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Grid Validation Error: " + ex.Message);
        }
    }

如果你看到需要调整或可以做得更好的事情,我愿意接受建议! :)