Pregunta

Si un conjunto de datos contiene una columna que es una marca de tiempo u otro valor binario, su DataGridView asociado lanza una excepción ArgumentException, cuando se muestran los datos de esa columna. Es decir, se supone que tiene alguna tabla que contiene una columna binaria como por ejemplo:

CREATE TABLE [dbo].[DataTest](
    [IdStuff] INT IDENTITY(1,1) NOT NULL,
    [ProblemColumn] TIMESTAMP NOT NULL )

En Visual Studio 2008, añadir un nuevo origen de datos que apunta a la tabla sospechoso. Arrastre la tabla desde el explorador de origen de datos sobre la superficie diseñador visual de un nuevo WinForm para crear automáticamente un DataGridView, BindingSource, etc. Ejecutar la aplicación y obtendrá una excepción de tiempo de ejecución. Suena como un defecto, ¿verdad?

Si se examina la colección de columnas de la DataGridView se encuentra que se establece el tipo de columna para DataGridViewImageColumn. ¿Por qué? Debido a que, según Microsoft, .NET asume que las columnas binarias son imágenes. De hecho, Microsoft afirma que este comportamiento es por diseño! Ver este informe de defectos en Microsoft Connect: http://connect.microsoft.com /VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93639

Uno podría suprimir el diálogo de error al manejar el evento DataError para el DataGridView, como el diálogo indica cortésmente, pero eso plantea la pregunta. Quiero encontrar una manera de evitar tener una condición de error en el primer lugar. Es decir, yo quiero tener un DataGridViewTextColumn que muestra una representación textual de los datos binarios, por ejemplo "0x1234a8e9433bb2". Y yo estoy buscando una solución genérica, ya que mi código actual no utiliza una tabla específica como en el ejemplo anterior. Más bien pongo una consulta algo arbitraria en un dataAdapter.SelectCommand, a continuación, invoque

dataAdapter.Fill(dataTable)

para generar automáticamente mi dataTable. Puesto que es el DataGridView que tiene el error (en mi humilde opinión), estoy pensando que tengo que comprobar las columnas de la tabla de datos (es decir, dataTable.Columns [n] .DataType.Name.Equals ( "byte []")?) y convertir cualquier matrices de bytes a sus formas de texto de forma manual antes de conectar el dataTable a DataGridView con

bindingSource.DataSource = dataTable;

Mi pregunta entonces:

¿Hay una manera más simple o más elegante para mostrar las columnas binarias en un DataGridView?

(Tenga en cuenta que este problema existe tanto con VS 2005 y VS 2008, .NET 2.0 y .NET 3.5.)

¿Fue útil?

Solución 2

Alentados por la respuesta de dilema, además de haber permitido el tiempo suficiente desde la publicación de mi pregunta :-) tener una nueva perspectiva, se me ocurrió una solución razonablemente limpia bajo la apariencia del método MorphBinaryColumns continuación, incrustado en una prueba de muestra completa programa ( excepto para el diseñador de VS genera el código de mi WinForm contiene un único DataGridView).

MorphBinaryColumns examina la colección de columnas y, para cada uno, que es una columna binaria, genera una nueva columna con el valor convertido a una cadena hexadecimal, entonces intercambia a cabo la columna original sustituyéndolo por uno nuevo, conservando el orden de las columnas originales.

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }

  private void Form1_Load(object sender, EventArgs e)
  {
    var sqlCnn = new SqlConnection("..."); // fill in your connection string
    string strsql = "select ... from ..."; // fill in your query

    var dataAdapter = new SqlDataAdapter();
    var dataTable = new DataTable();
    dataAdapter.SelectCommand = new SqlCommand(strsql, sqlCnn);
    dataAdapter.Fill(dataTable);
    MorphBinaryColumns(dataTable);
    dataGridView1.DataSource = dataTable;
  }

  private void MorphBinaryColumns(DataTable table)
  {
    var targetNames =  table.Columns.Cast<DataColumn>()
      .Where(col => col.DataType.Equals(typeof(byte[])))
      .Select(col => col.ColumnName).ToList();
    foreach (string colName in targetNames)
    {
      // add new column and put it where the old column was
      var tmpName = "new";
      table.Columns.Add(new DataColumn(tmpName, typeof (string)));
      table.Columns[tmpName].SetOrdinal(table.Columns[colName].Ordinal);

      // fill in values in new column for every row
      foreach (DataRow row in table.Rows)
      {
        row[tmpName] = "0x" + string.Join("",
          ((byte[]) row[colName]).Select(b => b.ToString("X2")).ToArray());
      }

      // cleanup
      table.Columns.Remove(colName);
      table.Columns[tmpName].ColumnName = colName;
    }
  }
}

Otros consejos

Añadir unas mejoras en enfoque anterior. # 1 manejo de columnas nulas binarios, # 2 mejoró el rendimiento al convertir un montón de columnas (usando el mismo constructor de cadena y otra vez), # 3 Longitud máxima de pantalla 8000 para evitar la conversión muy grandes columnas binarias de cadena ... # 4 Temperatura de la columna creación nombre utilizando un GUID para evitar conflictos de nombres en caso de que haya una columna denominada "temp" ...

/// <summary>
/// Maximum length of binary data to display (display is truncated after this length)
/// </summary>
const int maxBinaryDisplayString = 8000;

/// <summary>
/// Accepts datatable and converts all binary columns into textual representation of a binary column
/// For use when display binary columns in a DataGridView
/// </summary>
/// <param name="t">Input data table</param>
/// <returns>Updated data table, with binary columns replaced</returns>
private DataTable FixBinaryColumnsForDisplay(DataTable t)
{
    List<string> binaryColumnNames = t.Columns.Cast<DataColumn>().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;
}
/// <summary>
/// Converts binary data column to a string equivalent, including handling of null columns
/// </summary>
/// <param name="hexBuilder">String builder pre-allocated for maximum space needed</param>
/// <param name="columnValue">Column value, expected to be of type byte []</param>
/// <returns>String representation of column value</returns>
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<displayLength; i++)
        {
            hexBuilder.Append(hexChars[(int)byteArray[i] >> 4]);
            hexBuilder.Append(hexChars[(int)byteArray[i] % 0x10]);
        }
        return hexBuilder.ToString();
    }
}

Usted puede encontrar esto útil: http://social.msdn.microsoft .com / Foros / en / winformsdatacontrols / hilo / 593606df-0bcb-49e9-8e55-497024699743

Básicamente:

  • Obtención de los datos de la base de datos a la tabla de datos
  • a continuación, añadir una nueva columna (typeof (string))
  • a continuación, escribir el contenido binario sobre (usando bytearray a cadena hexadecimal) en esa nueva columna

  • entonces databind.

Es muy sencillo y molesto, sin embargo, que resuelve eficazmente el problema.

¿Qué hay de basar su consulta en una vista que hace un yeso durante esa columna?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top