Si un jeu de données contient une colonne une chronométrage ou une autre valeur binaire, son DataGridView associé jette une phrase argumentException, lors de l'affichage des données dans cette colonne. C'est-à-dire que vous avez une table contenant une colonne binaire telle que: dans Visual Studio 2008, ajoutez une nouvelle source de données pointant sur la table suspecte. Faites glisser la table de l'explorateur de source de données sur la surface des concepteurs visuels d'une nouvelle Winform pour créer automatiquement un DataGridView, BindingSource, etc. Exécutez l'application et vous obtiendrez une exception d'exécution. Cela ressemble à un défaut, à droite? P> Si vous examinez la collection de colonnes du DataGridView, vous constaterez qu'il définit le type de colonne sur DataGridViewImagecolumn. Pourquoi? Parce que, selon Microsoft, .NET suppose que les colonnes binaires sont des images. En effet, Microsoft affirme que ce comportement est par conception! Voir ce rapport de défaut sur Microsoft Connect: http://connect.microsoft.com /Visualstudio/feedback/vieweedback.aspx?feedbackID=93639 p> On pourrait supprimer la boîte de dialogue d'erreur en manipulant l'événement DataError pour la DataGridView, car la boîte de dialogue indique poliment, mais qui supplie la question. Je veux trouver un moyen d'éviter d'avoir une condition d'erreur en premier lieu. C'est-à-dire que je veux avoir un dataGridViewTextColumn montrant une représentation textuelle des données binaires, par exemple. "0x1234A8E9433BB2". Et je cherche une solution générique, car mon code actuel n'utilise pas de table spécifique comme dans mon exemple ci-dessus. Plutôt, je mets une requête quelque peu arbitraire dans un datadapter.selectCommand, puis appelez p> pour générer automatiquement mon jeu de données. Comme il s'agit de la DataGridView qui a le bogue (IMHO), je pense que je dois vérifier les colonnes de la table de données (c.-à-d. DataTable.Columns [n] .DataType.name.equals ("octets []")?) et convertir des matrices d'octets à leurs formulaires de texte manuellement avant de connecter le jeu de données au dataGridView avec p> ma question alors: p> est là Un moyen plus simple ou plus élégant d'afficher des colonnes binaires dans un DataGridView? em> p> (Notez que ce problème existe avec VS 2005 et VS 2008, .NET 2.0 et .NET 3.5.) p> p>
4 Réponses :
Que diriez-vous de baser votre requête sur une vue qui fait une fonte pour cette colonne? P>
Deux raisons: (1) Je ne pense pas qu'il y ait un moyen de le faire avec une interrogation. Microsoft montre ce qui est probablement le moyen le plus simple de le faire, nécessitant une procédure stockée; Voir support.microsoft.com/kb/104829 (2) J'aimerais qu'il soit transparent à l'utilisateur qui est entré dans la chaîne de requête arbitraire.
Vous pourriez trouver cela utile: http://social.msdn.microsoft .com / Forums / FR / WinFormsDatacontrols / Filetage / 593606DF-0BCB-49E9-8E55-497024699743 P>
Fondamentalement: p>
puis écrivez le contenu binaire sur (en utilisant byearray to hex String) dans cette nouvelle colonne p> li>
alors Databind. p> li> ul>
C'est simple et gênant, mais cela résout efficacement le problème. P>
Essentiellement, votre résumé réitère de manière concise ce que j'ai énoncé dans ma question. Néanmoins, votre contribution m'a poussé à regarder un nouveau regard sur le problème et à proposer une solution générique, alors je vous donne un uppote. Merci!
Essentiellement, vous êtes correct, car je n'ai lu que la partie supérieure. Désolé. Cependant, vous vouliez le faire dans la grille elle-même, ce qui est un peu complexe. Mais jamais moins, +1 pour ce très beau morceau de code.
stimulé par la réponse du devis, plus ayant permis de suffisamment de temps depuis la publication de ma question pour avoir une perspective fraîche :-), je suis proposé une solution raisonnablement propre dans l'apparence du MorphbarinyColumns examine la collection de colonnes et, pour chacune une colonne binaire,
Génère une nouvelle colonne avec la valeur convertie en une chaîne hexagonale, puis sève la colonne d'origine le remplaçant avec le nouveau, préservant l'ordre de colonne d'origine. P> MorphbinyColumns code> Méthode ci-dessous , incorporé dans un programme de test d'échantillon complet ( sauf em> pour le code généré par My Winform contenant un seul DataGridView).
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;
}
}
}
Ajout de quelques améliorations à l'approche ci-dessus. # 1 Gestion des colonnes binaires nulles NULL, # 2 amélioration des performances lors de la conversion de lots de colonnes (en utilisant le même constructeur de cordes de plus et sur), # 3 Longueur d'affichage maximale de 8000 pour éviter de convertir des colonnes binaires vraiment grandes en chaîne ... # 4 Création de la colonne Temp Nom à l'aide d'un GUID pour éviter les collisions de noms au cas où une colonne nommée "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(); } }