Nochmal DataGridView, VirtualMode und Rows.Height

15/04/2009 - 00:41 von Michaela Meier | Report spam
Hi,

Dieses Problem macht mich wahnsinnig!

Ich hatte fast gedacht, daß ich einen tollen Workaround zu
http://groups.google.com/group/micr...02d0e9f09#
gefunden hàtte (dynamische Anpassung der Zeilenhöhe).
Aber leider will das Ding mal wieder nicht so wie ich.
Im Prinzip besteht das Programm aus nichts weiter als diesem Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
DataTable dt = new DataTable();
DataGridView grd = new DataGridView();

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
dt.Columns.Add("Index", typeof(int));
dt.Columns.Add("Image", typeof(Image));
dt.Columns.Add("Name", typeof(string));

Random rand = new Random();
for (int i = 0; i < 100; i++)
{
DataRow dr = dt.NewRow();
dr["Index"] = i;
dr["Image"] = new Bitmap(1, 1);
int r = rand.Next(10);
if (r > 7)
{
Bitmap bmp = new Bitmap(30, 40);
Graphics g = Graphics.FromImage(bmp);
g.DrawRectangle(new Pen(Color.Black), 0, 0, 29,
39);
g.FillRectangle(new SolidBrush(Color.Red), 2, 2,
26, 36);
dr["Image"] = bmp;
}
dr["Name"] = string.Format("Bild {0}", i);
dt.Rows.Add(dr);
}
grd.Location = new Point(0, 0);
grd.Size = new Size(200, 100);
grd.Visible = true;
grd.VirtualMode = true;
grd.Dock = DockStyle.Fill;
grd.RowHeadersVisible = false;
grd.ReadOnly = true;
grd.SelectionMode DataGridViewSelectionMode.FullRowSelect;
grd.AutoSizeColumnsMode DataGridViewAutoSizeColumnsMode.Fill;
grd.AllowUserToResizeColumns = false;
grd.AllowUserToResizeRows = false;
grd.CellValueNeeded += new
DataGridViewCellValueEventHandler(grd_CellValueNeeded);
grd.DataError += new DataGridViewDataErrorEventHandler
(grd_DataError);
this.Controls.Add(grd);

grd.Columns.Add("Index", "");
grd.Columns["Index"].Visible = false;
DataGridViewImageColumn colImage = new
DataGridViewImageColumn();
colImage.Name = "Image";
colImage.HeaderText = "";
colImage.AutoSizeMode DataGridViewAutoSizeColumnMode.None;
colImage.Width = 32;
grd.Columns.Add(colImage);
grd.Columns.Add("Name", "Name");

grd.Rows.AddCopies(0, 100);
}

void grd_DataError(object sender,
DataGridViewDataErrorEventArgs e)
{
e.Cancel=true;
}

void grd_CellValueNeeded(object sender,
DataGridViewCellValueEventArgs e)
{
e.Value = dt.Rows[e.RowIndex][e.ColumnIndex];
if (e.ColumnIndex == 1)
{
Bitmap bmp = (Bitmap)dt.Rows[e.RowIndex]["Image"];
if (bmp.Height > 1 && grd.Rows[e.RowIndex].Height <
41)
{
grd.Rows[e.RowIndex].Height = 41;
}
}
}
}
}

Mit den einzigen Unterschieden:
- Das DataTable wird natürlich per OleDbCommand aus einer Datenbank
gefüllt
- Die Bitmaps werden aus einer Datei eingelesen
- Das Grid befindet sich nicht direkt auf der Form sondern ist Teil
eines UserControls.
- Der obige Beispiel-Code crasht _nicht_!

Besagtes UserControl jedoch sondert mit reproduzierbarer
Regelmàßigkeit beim Scrollen die folgende Fehlermeldung ab, und zwar
sobald die erste anzupassende Zeile in den sichtbaren Bereich geràt.
"Invalid cast from 'System.String' to 'System.Drawing.Image'."

Nach làngerem Haareraufen und Sucherei hat sich herauskristallisiert,
daß die Zeile
grd.Rows[e.RowIndex].Height = 41;
der Übeltàter ist. Sobald ich den Teil auskommentiere, ist Ruhe im
Karton.

Mit
e.Cancel=true
im DataError-Event erziele ich denselben Effekt, aber ich wüßte schon
gerne, was genau ich da ignoriere und wieso dieser Fehler überhaupt
auftritt.

Innerhalb eines try-catch-Blocks làßt sich der Fehler übrigens nicht
fangen.

Hat jemand eine Idee? Hilfe :-(
 

Lesen sie die antworten

#1 Frank Dzaebel
15/04/2009 - 08:41 | Warnen spam
Hallo Michaela,

DataGridView (dynamische Anpassung der Zeilenhöhe).



Das wàre ein ~mögliches Vorgehen. Da die (abtrakte)
Anforderung nicht deutlich ist, kann natürlich nicht gesagt
werden, ob es nicht bessere Methoden gàbe.

Aber - in Deinem Code stecken "Annahmen",
die Du dort eigentlich am Anfang abchecken musst, wenn
Du das Grid nach aussen hin modifizierbar zur Verfügung
stellen willst. Zum Beispiel könnte ggf. jemand evtl. :

grd.Columns["Name"].AutoSizeMode DataGridViewAutoSizeColumnMode.DisplayedCells;

setzen o.à.. Dann kann's knallen.
______

zur Sicherheit ... einige andere Fehler/Gefahren haben
sich in Deinem Code eingeschlichen ...

- Benutze keine direkten Zahlen, sondern besser
Konstanten mit semantisch treffenden Namen.
- Wenn Variablen miteinander in Beziehung sind, implementiere
dies in der Definition dieser Variablen, sodass eine
Änderung der einen ggf. die der anderen mitführt.
- Graphics, Pen, Bitmap sind Objekte, die möglichst
früh mit Dispose entsorgt werden sollten, weil diese
unmanaged Ressourcen binden.
- Dein Graphics wird zu oft erzeugt, es reicht einmal. ...

wie gesagt, dies ist nur zur Sicherheit, offensichtlich galt dies
nur als kurzes Codebeispiel, um den Effekt zu verdeutlichen.


ciao Frank
Dipl.Inf. Frank Dzaebel [MCP/MVP C#]
http://Dzaebel.NET

Ähnliche fragen