如果DataSet包含时间戳或其他二进制值的列,则在显示该列中的任何数据时,其关联的DataGridView将抛出ArgumentException.也就是说,假设您有一些包含二进制列的表,例如:
CREATE TABLE [dbo].[DataTest]( [IdStuff] INT IDENTITY(1,1) NOT NULL, [ProblemColumn] TIMESTAMP NOT NULL )
在Visual Studio 2008中,添加指向可疑表的新数据源.将表从数据源资源管理器拖到新WinForm的可视化设计器表面上,以自动创建DataGridView,BindingSource等.执行应用程序,您将获得运行时异常.听起来像是一个缺陷,对吧?
如果检查DataGridView的Columns集合,您会发现它将列类型设置为DataGridViewImageColumn.为什么?因为,根据微软的说法,.NET假定二进制列是图像.事实上,微软肯定这种行为是设计的!请参阅Microsoft Connect上的此缺陷报告:http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx ?FeedbackID = 93639
可以通过处理DataGridView的DataError事件来抑制错误对话框,正如对话框礼貌地指出的那样,但这引出了问题.我想找到一种方法来避免首先出现错误.也就是说,我希望有一个DataGridViewTextColumn显示二进制数据的文本表示,例如"0x1234a8e9433bb2".我正在寻找一个通用的解决方案,因为我的实际代码不使用上面示例中的特定表.相反,我在dataAdapter.SelectCommand中添加了一些任意的查询,然后调用
dataAdapter.Fill(dataTable)
自动生成我的dataTable.由于DataGridView有(恕我直言)错误,我想我需要检查数据表的列(即dataTable.Columns [n] .DataType.Name.Equals("Byte []")?)并在将dataTable连接到DataGridView之前手动将任何字节数组转换为其文本形式
bindingSource.DataSource = dataTable;
那我的问题是:
是否有更简单或更优雅的方式在DataGridView中显示二进制列?
(请注意,VS 2005和VS 2008,.NET 2.0和.NET 3.5都存在此问题.)
为上述方法添加一些改进.#1处理空二进制列,#2在转换大量列时提高了性能(反复使用相同的字符串生成器),#3最大显示长度为8000,以避免将真正大的二进制列转换为字符串...#4创建临时列如果有一个名为"temp"的列,使用guid命名以避免名称冲突...
////// Maximum length of binary data to display (display is truncated after this length) /// const int maxBinaryDisplayString = 8000; ////// Accepts datatable and converts all binary columns into textual representation of a binary column /// For use when display binary columns in a DataGridView /// /// Input data table ///Updated data table, with binary columns replaced private DataTable FixBinaryColumnsForDisplay(DataTable t) { ListbinaryColumnNames = t.Columns.Cast ().Where(col => col.DataType.Equals(typeof(byte[]))).Select(col => col.ColumnName).ToList(); foreach (string binaryColumnName in binaryColumnNames) { // Create temporary column to copy over data string tempColumnName = "C" + Guid.NewGuid().ToString(); t.Columns.Add(new DataColumn(tempColumnName, typeof(string))); t.Columns[tempColumnName].SetOrdinal(t.Columns[binaryColumnName].Ordinal); // Replace values in every row StringBuilder hexBuilder = new StringBuilder(maxBinaryDisplayString * 2 + 2); foreach (DataRow r in t.Rows) { r[tempColumnName] = BinaryDataColumnToString(hexBuilder, r[binaryColumnName]); } t.Columns.Remove(binaryColumnName); t.Columns[tempColumnName].ColumnName = binaryColumnName; } return t; } /// /// Converts binary data column to a string equivalent, including handling of null columns /// /// String builder pre-allocated for maximum space needed /// Column value, expected to be of type byte [] ///String representation of column value private string BinaryDataColumnToString(StringBuilder hexBuilder, object columnValue) { const string hexChars = "0123456789ABCDEF"; if (columnValue == DBNull.Value) { // Return special "(null)" value here for null column values return "(null)"; } else { // Otherwise return hex representation byte[] byteArray = (byte[])columnValue; int displayLength = (byteArray.Length > maxBinaryDisplayString) ? maxBinaryDisplayString : byteArray.Length; hexBuilder.Length = 0; hexBuilder.Append("0x"); for(int i = 0; i> 4]); hexBuilder.Append(hexChars[(int)byteArray[i] % 0x10]); } return hexBuilder.ToString(); } }