문제

데이터 세트에 타임 스탬프 또는 기타 이진 값인 열이 포함 된 경우 해당 열에 데이터를 표시 할 때 관련 DataGridView가 인수 외환을 던집니다. 즉, 다음과 같은 이진 열이 포함 된 테이블이 있다고 가정합니다.

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

Visual Studio 2008에서 용의자 테이블을 가리키는 새로운 데이터 소스를 추가하십시오. 데이터 소스 탐색기에서 테이블을 새 WINFORM의 비주얼 디자이너 표면으로 드래그하여 DatagridView, BindingSource 등을 자동으로 작성하면 응용 프로그램을 실행하면 런타임 예외가 나타납니다. 결함처럼 들리나요?

DataGridView의 열 모음을 검사하면 열 유형을 DataGridViewImageColumn으로 설정합니다. 왜요? Microsoft에 따르면 .NET은 이진 열이 이미지라고 가정합니다. 실제로, Microsoft는이 동작이 디자인에 의한 것을 확인합니다! Microsoft Connect 에서이 결함 보고서를 참조하십시오. http://connect.microsoft.com/visualstudio/feedback/viewfeedback.aspx?feedbackid=93639

대화 상자가 정중하게 나타내는 것처럼 DatagridView의 DataError 이벤트를 처리하여 오류 대화 상자를 억제 할 수 있지만 질문을 제기합니다. 처음에 오류 상태를 피할 수있는 방법을 찾고 싶습니다. 즉, 바이너리 데이터의 텍스트 표현을 보여주는 DataGridViewTextColumn과 같은 DataGridViewTextColumn (예 : "0x1234A8E9433BB2"를 보여주고 싶습니다. 실제 코드는 위의 예에서와 같이 특정 테이블을 사용하지 않기 때문에 일반 솔루션을 찾고 있습니다. 오히려 DataAdapter.selectCommand에 다소 임의의 쿼리를 넣은 다음 호출합니다.

dataAdapter.Fill(dataTable)

내 데이터 가능성을 자동 생성하기 위해. (IMHO) 버그가있는 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

Quandary의 답변에 의해 박차가 있었고, 신선한 관점을 갖기 위해 질문을 게시 한 이후로 충분한 시간을 허용 한 것 :-), 나는 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;
    }
  }
}

다른 팁

위의 접근 방식에 몇 가지 개선 사항을 추가합니다. #1 널 이진 컬럼 처리, #2 열 향상된 성능을 향상된 성능 (동일한 문자열 빌더 사용)을 계속 변환 할 때 (동일한 문자열 빌더 사용), #3 최대 큰 이진 열을 문자열로 변환하지 않도록 #3 온도 열 만들기 ... #4 온도 열 만들기 이름 충돌을 피하기 위해 Guid를 사용하여 "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();
    }
}

이 유용한 것을 알 수 있습니다.http://social.msdn.microsoft.com/forums/en/winformsdatacontrols/thread/593606df-0bcb-49e9-8e55-497024699743

원래:

  • DB에서 데이터 가능으로 데이터를 가져옵니다
  • 그런 다음 새 열을 추가합니다 (typeof (String))
  • 그런 다음 바이너리 컨텐츠 (BytearRay to Hex String 사용)를 해당 새 열에 쓰십시오.

  • 그런 다음 Databind.

간단하고 성가 시지만 문제를 효과적으로 해결합니다.

그 열에 캐스트를하는보기에 쿼리를 기반으로하는 것은 어떻습니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top