質問

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 に設定されていることがわかります。なぜ?Microsoft によれば、.NET はバイナリ列がイメージであると想定しているためです。実際、Microsoft は、この動作は仕様によるものであると断言しています。Microsoft Connect で次の不具合レポートを参照してください。 http://connect.microsoft.com/VisualStudio/フィードバック/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 の両方に存在することに注意してください。)

役に立ちましたか?

解決 2

困惑の答えでオンに拍車をかけ、プラス新鮮な視点の:-)を持って、私の質問を投稿するので、十分な時間を許可された、私は完全なサンプルテストに埋め込まれ、以下MorphBinaryColumns方法を装って合理的にきれいな解決策を考え出しましたプログラム(VSのデザイナーのためには、のを除いての単一のDataGridViewを含む私のWinFormからコードを生成しました)。

MorphBinaryColumnsは、バイナリ列であることごとに、列のコレクションを調べ、 16進文字列に変換された値を持つ新しい列を生成し、その後、元の列の順序を維持し、新しいものと交換元の列を交換します。

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

他のヒント

上記のアプローチにいくつかの改良を加え。列の多くを変換する際にヌルバイナリ列、#2を処理#1は、(何度も同じ文字列ビルダーを使用して)文字列に非常に大きなバイナリ列を変換避けるために8000の#3の最大表示長の性能を向上させる...#4一時列を作成

...「一時」という名前の列がある場合に、名前の衝突を避けるために、GUIDを使用して名前
/// <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();
    }
}

これは役に立つかもしれません:http://social.msdn.microsoft.com/Forums/en/winformsdatacontrols/thread/593606df-0bcb-49e9-8e55-497024699743

基本的に:

  • DBからデータテーブルへのデータの取得
  • 次に、新しい列 (typeof(string)) を追加します。
  • 次に、バイナリコンテンツを(bytearrayを16進ストリングに使用して)その新しい列に書き込みます

  • 次にデータバインドします。

シンプルで面倒ですが、問題を効果的に解決します。

どのようにその列のCASTを行うビューでクエリを基づかについてはどうですか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top