Frage

Wenn ein Datensatz eine Spalte enthält, die ein Zeitstempel oder eine andere Binärwert ist, wirft seine zugehörige Datagridview ein Argument, wenn in dieser Spalte keine Daten. Das heißt, vorausgesetzt, dass Sie eine Tabelle haben eine binäre Spalte enthält, wie zum Beispiel:

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

In Visual Studio 2008 eine neue Datenquelle hinzufügen, um die Verdächtigen Tabelle zeigen. Ziehen Sie die Tabelle aus der Datenquelle-Explorer auf die visuellen Designer Oberfläche eines neuen WinForm, um automatisch eine Datagridview zu erstellen, Binding usw. Führen Sie die Anwendung, und Sie werden eine Laufzeitausnahme erhalten. Klingt wie ein Defekt, nicht wahr?

Wenn Sie die Columns-Sammlung des Datagridview untersuchen werden Sie feststellen, dass es den Spaltentyp DataGridViewImageColumn setzt. Warum? Denn nach Microsoft, geht davon aus, dass .NET binäre Spalten sind Bilder. Tatsächlich bestätigt Microsoft, dass dieses Verhalten von Entwurf ist! Sehen Sie diesen Defekt Bericht über Microsoft Connect: http://connect.microsoft.com /VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93639

Man könnte den Fehlerdialog unterdrücken, indem das Dataerror-Ereignisses für die Datagridview-Handling, wie der Dialog höflich zeigt an, aber das wirft die Frage auf. Ich möchte einen Weg finden, um einen Fehlerzustand in erster Linie zu vermeiden ist. Das heißt, ich möchte ein DataGridViewTextColumn haben eine textliche Darstellung der binären Daten, die zeigen, z.B. "0x1234a8e9433bb2". Und ich bin auf der Suche für eine generische Lösung, da mein eigentlicher Code nicht eine bestimmte Tabelle, wie in meinem obigen Beispiel verwenden ist. Vielmehr habe ich eine etwas willkürliche Abfrage in eine dataAdapter.SelectCommand, dann rufen Sie

dataAdapter.Fill(dataTable)

, um automatisch generieren meine Datatable. Da es die Datagridview ist, dass die (IMHO) Fehler hat, ich denke, dass ich die Spalten der Datentabelle überprüfen müssen (dh dataTable.Columns [n] .DataType.Name.Equals ( „Byte []“)?) und konvertieren alle Byte-Arrays, um ihre Textformen manuell, bevor ich die Datatable Datagridview mit

connect
bindingSource.DataSource = dataTable;

Meine Frage ist dann:

Gibt es eine einfachere oder elegante Weise binäre Spalten in einem Datagridview angezeigt werden?

(Beachten Sie, dass dieses Problem sowohl existiert mit VS 2005 und VS 2008, .NET 2.0 und .NET 3.5.)

War es hilfreich?

Lösung 2

von Quandary Antwort Angespornt sowie seit der Veröffentlichung meiner Frage ausreichend Zeit hat, eine neue Perspektive zu haben :-), kam ich mit einer einigermaßen sauberen Lösung in der Gestalt der MorphBinaryColumns Methode unten, eingebettet in einem vollständigen Probe-Test auf Programm ( außer für VS Designer-generierten Code aus meiner WinForm einen einzigen Datagridview enthält).

MorphBinaryColumns sucht die Spalte Sammlung und für jeden, der eine binäre Spalte ist, erzeugt eine neue Säule, die mit dem auf einen Hex-String-gewandelter Wert, dann die ursprüngliche Spalte es mit dem neuen ersetzt auslagert, die ursprünglichen Spaltenreihenfolge beibehalten wird.

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

Andere Tipps

ein paar Verbesserungen oben Ansatz Hinzufügen. # 1 null binäre Spalten Handhabung, # 2 ein verbesserte Leistung, wenn viele Spalten (unter Verwendung derselben Saite Builder über und über), # 3 maximale Anzeigelänge von 8000 Umwandlung zu vermeiden, wirklich große binäre Spalten zu bespannen Umwandlung ... # 4 Temp Spalte Schaffung nennen guid mit Namenskollisionen zu vermeiden, falls es eine Spalte „temp“ ...

benannt ist
/// <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();
    }
}

Sie könnte dies nützlich sein: http://social.msdn.microsoft .com / Foren / en / winformsdatacontrols / thread / 593606df-0bcb-49e9-8e55-497024699743

Grundsätzlich gilt:

  • Abrufen der Daten aus der DB auf die Datatable
  • dann das Hinzufügen einer neuen Spalte (typeof (string))
  • schreiben Sie dann den binären Inhalt über (unter Verwendung von bytearray zu hex string) in diese neue Spalte

  • dann databind.

Es ist einfach und ärgerlich, aber es löst das Problem wirksam.

Wie wäre Ihre Abfrage auf einer Ansicht zu stützen, die für diese Spalte eine CAST das?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top