سؤال

إذا كانت مجموعة بيانات تحتوي على عمود هو طابع زمني أو قيمة ثنائية أخرى، يلقي DataGridView المرتبط به ArgumentException، عند عرض أي بيانات في هذا العمود. وهذا هو، افترض أن لديك بعض الجدول يحتوي على عمود ثنائي مثل:

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://connnect.microsoft.com/visualstudio/feedback/viewfeedback.aspx؟feedbackid=93639.

يمكن للمرء أن يقمع مربع حوار الخطأ عن طريق معالجة حدث Dataerror ل DataGridView، حيث يشير مربع الحوار بأدب، ولكن هذا يطرح السؤال. أريد أن أجد طريقة لتجنب وجود حالة خطأ في المقام الأول. وهذا هو، أريد أن يكون لدي datagredviewtextcolumn عرض تمثيل نصي للبيانات الثنائية، على سبيل المثال "0x1234A8E9433BB2". وأنا أبحث عن حل عام، لأن الرمز الفعلي الخاص بي لا يستخدم طاولة محددة كما في مثالي أعلاه. بدلا من ذلك وضع استعلام تعسفيا إلى حد ما في DataAdapter.Selectcommand، ثم استدعاء

dataAdapter.Fill(dataTable)

لإنشاء تلقائي DataTable الخاص بي. نظرا لأن DataGridView الذي يحتوي على علة (IMHO)، فأنا أفكر في أنني بحاجة إلى التحقق من أعمدة جدول البيانات (أي DataTable.Columns [n] .datatype.name.Aequales ("البايت [])؟) وتحويل أي صفائف بايت إلى نماذج النص الخاصة بهم يدويا قبل أن أقوم بتوصيل DataTable إلى DataGridView مع

bindingSource.DataSource = dataTable;

سؤالي ثم:

هل هناك طريقة أبسط أو أكثر أناقة لعرض الأعمدة الثنائية في DataGridView؟

(لاحظ أن هذه المشكلة موجودة مع كل من VS 2005 و VS 2008 و .NET 2.0 و .NET 3.5.)

هل كانت مفيدة؟

المحلول 2

حفزت عن طريق الإجابة المانعة، بالإضافة إلى السماح بوقت كاف منذ نشر سؤالي أن يكون منظور جديد :-)، توصلت إلى حل نظيف بشكل معقول في ستار MorphBinaryColumns الطريقة أدناه، مدمجة في برنامج اختبار عينة كاملة (إلا للحصول على رمز مصمم VS الذي تم إنشاؤه من Winform الذي يحتوي على DataGridView واحد).

يفحص Morphbinarycolumns مجموعة العمود، ولكل عمود ثنائي، يولد عمود جديد مع القيمة التي تم تحويلها إلى سلسلة HEX، ثم قم بإعداد العمود الأصلي لاستبداله بمرجع جديد، والحفاظ على ترتيب العمود الأصلي.

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 الحد الأقصى لطول عرض 8000 لتجنب تحويل الأعمدة الثنائية الكبيرة حقا إلى سلسلة ... # 4 إنشاء عمود TEMP الاسم باستخدام 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 إلى DataTable
  • ثم قم بإضافة عمود جديد (TypeOF (سلسلة))
  • ثم اكتب المحتوى الثنائي (باستخدام BYTEARRAY إلى سلسلة Hex) في هذا العمود الجديد

  • ثم DataBind.

إنه بسيط ومزعج، ومع ذلك يحل المشكلة بشكل فعال.

ماذا عن بناء استفسارك على طريقة عرض يقوم بإضاءة لهذا العمود؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top