ich habe ein paar Fragen zum DataGridView:
1. Ist es möglich eine Fußzeile zu erstellen? Ich meine eine
DataGridViewRow die am unteren Ende des DataGridView fixiert ist, nicht
mitscrollt und auch keinen normalen Datensatz, sondern z. B. die Anzahl
der Datensätze o. ä. anzeigt. Diese Zeile soll immer am unteren Ende des
DataGridView zu sehen sein, sowohl wenn weniger Zeilen als möglich auf
einmal angezeigt werden (oder gar keine) als auch wenn es sehr viele
Zeilen sind. Beispiel siehe [1].
2. Das DataGridView ist unbound und wird komplett im Code aufgebaut.
Dies geht leider nicht anders da alle in [1] zu sehenden, nicht grauen
Spalten sehr dynamisch sind, und zwar in Bezug auf Existenz, Inhalt und
Verhalten. Den anderen Spalten habe ich vor dem Hinzufügen zum
DataGridView konstante Namen zugewiesen. Beim Laden der Daten wollte ich
dann auf die Zellen über diese Namen statt über deren Indizes zugreifen,
das hat jedoch nicht funktioniert:
const string IDColumn = "ID";
void LoadData()
{
DataGridViewRow row = (DataGridViewRow)dgView.RowTemplate.Clone();
row.CreateCells(dgView);
// Startnummer
DataGridViewCell cell = row.Cells[IDColumn]; // Es gibt keine Zelle
mit dem Namen.
// ...
}
Wozu sind dann die Namen da??
[1] http://mvf.gmxhome.de/ExtendedDataGridView.gif
Gruß,
Marco
> [DataGridView]
> 1. Ist es möglich eine Fußzeile zu erstellen?
Es gibt die Möglichkeit eine Zeile "einzufrieren".
Diese bleibt dann während eines Zeilen-Scroll-
Vorganges fixiert. Dies ist aber Excel-Like eher
für Kopfzeilen interessant.
dataGridView1.Rows[0].Frozen=true;
Man kann aber auch durch die Visible-Eigenschaft
dataGridView1.Rows[2].Visible = false;
Zellen nicht erscheinen lassen. Zusammen mit der
DataGridView.FirstDisplayedRow kann man beim
Scroll-Ereignis nur spezielle Rows sichtbar halten.
Für eine Fusszeile gibt es u.a. den Ansatz
eines durchsichtigen Bottom-gedockten Panels:
public Form1()
{ InitializeComponent(); //dgv -> dataGridView1
dgv.Rows.CollectionChanged += new
CollectionChangeEventHandler(Rows_CollectionChanged);
}
Panel pn = new Panel();
void Rows_CollectionChanged(object sender,CollectionChangeEventArgs e)
{ if (dgv.Rows.Count > 0)
{ if (!dgv.Controls.Contains(pn))
{ pn.Dock = DockStyle.Bottom;
pn.Height = dgv.Rows[0].HeaderCell.PreferredSize.Height;
pn.BackColor = Color.Transparent; dgv.Controls.Add(pn);
}
}
} // unterste Row wird dadurch nicht neugezeichnet
> 2.
> const string IDColumn = "ID";
> void LoadData()
> { DataGridViewRow row = (DataGridViewRow)dgView.RowTemplate.Clone();
> row.CreateCells(dgView);
> DataGridViewCell cell = row.Cells[IDColumn]; // Es gibt keinen.. Namen.
> } // Wozu sind dann die Namen da??
Deine "row" hängt noch im luftleeren Raum.
Sie ist nicht an ein DataColumn-Schema gebunden.
ciao Frank
--
Dipl.Inf. Frank Dzaebel [MCP/MVP C#]
http://Dzaebel.NET
Marco
row.CreateCells(dgView);
die row gleich dem dgView hinzugefügt statt erst wenn ich alle Zellen
gefüllt habe. Dann ist die row auch an das DataColumn-Schema gebunden,
aber irgendwie mache ich da immer noch etwas falsch. Denn
cell.Value = 133; // cell.ValueType == typeof(int)
wirft eine ArgumentOutOfRangeException, cell.Tag = 133; hingegen
funktioniert.
Message: "Specified argument was out of the range of valid values.
Parameter name: rowIndex"
rowIndex ist -1, aber warum, die Zeile habe ich doch schon zum
DataGridView hinzugefügt? Laut dgView.Rows hat die row aber den Index 0.
Gruß,
Marco
>> Für eine Fusszeile gibt es u.a. den Ansatz
>> eines durchsichtigen Bottom-gedockten Panels:
> Klingt sehr interessant, werde ich ausprobieren. Wenn sich nun der Inhalt in
> der Fußzeile irgendwie ändert, reicht dann ein pn.Invalidate() oder muss ich
> da noch etwas beachten, um die Fußzeile neu zeichnen zu lassen?
Im Prinzip reicht das, aber es gibt noch ein paar
"Kleinigkeiten" deswegen evtl. sauberer Ansatz :
public Form1()
{ InitializeComponent();
dgv.CellPainting += new DataGridViewCellPaintingEventHandler(
dgv_CellPainting);
dgv.Scroll += new ScrollEventHandler(dgv_Scroll);
dgv.Resize += new EventHandler(dgv_Resize);
}
void dgv_Scroll(object sender,ScrollEventArgs e)
{dgv.Invalidate();}
void dgv_Resize(object sender,EventArgs e)
{dgv.Invalidate();}
Font myFont = new Font("Arial",12,FontStyle.Bold);
Brush myBrush = Brushes.Blue;
Point myPoint = new Point(0,0);
Brush lyBrush = Brushes.LightYellow;
const int myColumn= 0;
void dgv_CellPainting(object sender,DataGridViewCellPaintingEventArgs e)
{ if (e.RowIndex == LastDisplayedRow())
if (e.ColumnIndex == myColumn)
{ e.Graphics.FillRectangle(lyBrush,e.CellBounds);
e.Graphics.DrawString("123,45",myFont,myBrush,e.CellBounds);
e.Handled = true; // für 123,45 dann die Summe einsetzen.
}
}
private int LastDisplayedRow()
{ for (int i=dgv.FirstDisplayedScrollingRowIndex;
i<dgv.Rows.Count; i++)
{ if (dgv.Rows[i].Displayed) continue; else return i-1;
} return -1;
Gruß Marco
> DataGridView-Fusszeile möglich?
Für das DataGrid (.NET 1.1) habe ich hier noch
eine sehr umfangreiche Lösung von MS gefunden:
[How to sum the fields in a Windows Forms DataGrid control and display the
calculated totals in a footer by using Visual C# .NET]
http://support.microsoft.com/kb/842290/en-us
public Form1()
{ InitializeComponent();
dgv.CellPainting += new DataGridViewCellPaintingEventHandler(
dgv_CellPainting);
dgv.Scroll += new ScrollEventHandler(dgv_Scroll);
dgv.Resize += new EventHandler(dgv_Resize);
}
void dgv_Scroll(object sender,ScrollEventArgs e)
{dgv.Invalidate();}
void dgv_Resize(object sender,EventArgs e)
{dgv.Invalidate();}
Font myFont = new Font("Arial",12,FontStyle.Bold);
Brush myBrush = Brushes.Blue;
Point myPoint = new Point(0,0);
Brush lyBrush = Brushes.LightYellow;
const int myColumn= 0;
void dgv_CellPainting(object sender,DataGridViewCellPaintingEventArgs e)
{ if (e.RowIndex == LastDisplayedRow())
if (e.ColumnIndex == myColumn)
{ e.Graphics.FillRectangle(lyBrush,e.CellBounds);
e.Graphics.DrawString("123,45",myFont,myBrush,e.CellBounds);
e.Handled = true; // für 123,45 dann die Summe einsetzen.
}
}
private int LastDisplayedRow()
{
if (dgv.FirstDisplayedScrollingRowIndex < 0) return -1;
for (int i = dgv.FirstDisplayedScrollingRowIndex;
i < dgv.Rows.Count; i++)
if (dgv.Rows[i].Displayed) continue; else return i - 1;
return dgv.Rows.Count - 1;
Ich muss jetzt erst mal die eigentliche Logik voranbringen.
Gruß Marco
Gruß
Marco
> Nachtrag: Mit 40 Zeilen springt die Fußzeile beim Scrollen hin und her (d. h.
> in Scrollrichtung), steht danach aber wieder an der richtigen Stelle. Gibt es
> da eine Möglichkeit, das zu verhindern, etwa OnScrollBegin und OnScrollEnd
> oder etwas Derartiges?
Meinst Du, dass die Zeile einen kurzen Augenblick
beim Scrollen eine Zeile höher gezeichnet wird und dann
wieder als Fusszeile korrekt?
> Meinst Du, dass die Zeile einen kurzen Augenblick
> beim Scrollen eine Zeile höher gezeichnet wird und dann
> wieder als Fusszeile korrekt?
Wenn ja, mach z.B. folgendes:
a) Lösche den Code für das dgv_Scroll(obj,...) Event ersatzlos.
b) Subclass'e das DataGridView:
class MyDataGridView : DataGridView
{ public MyDataGridView()
{ this.VerticalScrollBar.ValueChanged +=
new EventHandler(VSB_ValueChanged);
}
void VSB_ValueChanged(object sender,EventArgs e)
{ this.Invalidate(); }
}
c) ersetze die beiden Vorkommen der DataGridView-
Definition durch MyDataGridView.
Wird ja langsam ganz brauchbar :)
ich habe auch ein änliches Problem. Ich habe ein dataTable und dies
wird in einem GridView angezeigt.
jetzt habe ich ja die einfache Möglichkeit über VS2005 dem GridView
einen Header und Footer anzufügen. Wie greife ich jetzt aber im Code
auf die einzelnen Zellen im Footer zu? das heist konkret, ich möchte
im footer jeder Spalte einen beliebigen Wert schreiben.
ich habe das hier im Beitrag nicht gefunden oder habe es übersehen.
Grüsse
Christoph
Das ist in ASP.NET 2.0. Wir sprachen ja bislang
über ein WinForm-DataGridView, aber ok.
Da würde mans (als Beispiel) etwa so machen:
GridViewRow footerRow;
protected void Page_Load(object sender,EventArgs e)
{ GridView1.ShowFooter = true;
footerRow = GridView1.FooterRow;
DataControlFieldCell dfc0 = (DataControlFieldCell)footerRow.Cells[0];
dfc0.Text = "Hallo";
DataControlFieldCell dfc1 = (DataControlFieldCell)footerRow.Cells[1];
dfc1.Text = "Christoph!";
>GridViewRow footerRow;
>protected void Page_Load(object sender,EventArgs e)
>{ GridView1.ShowFooter = true;
> footerRow = GridView1.FooterRow;
> DataControlFieldCell dfc0 = (DataControlFieldCell)footerRow.Cells[0];
> dfc0.Text = "Hallo";
> DataControlFieldCell dfc1 = (DataControlFieldCell)footerRow.Cells[1];
> dfc1.Text = "Christoph!";
>}
Dieser code geht bei mir leider nicht, da ich ein DataGrid und kein
GridView verwende. Ich könnte jetzt zwar ein GridView verwenden, aber
dann funktioniert der Export ins Excel wieder nicht.
hast du mir evt. ein Tipp, wie ich das mit einem DataGrid lösen
könnte?
grüsse
christoph
>Dieser code geht bei mir leider nicht, da ich ein DataGrid und kein
>GridView verwende. Ich könnte jetzt zwar ein GridView verwenden, aber
>dann funktioniert der Export ins Excel wieder nicht.
Also der sollte eigentlich funktionieren, wenn auch
mit ggf. abgeändertem Code.
>hast du mir evt. ein Tipp, wie ich das mit einem DataGrid lösen
>könnte?
Für das .NET 1.1 DataGrid ist eine FooterRow wegen
(zumindest) fehlendem CellPainting Event recht schwierig
zu machen. Ich würde da evtl. einfach unter das DataGrid-
Control TextBoxen mit der "Column.Width" der DataGrid-Spalten
einfügen. Dann sollte das Grid möglichst keinen horizontalen
Scrollbar haben, da die Summen da (normal) dann nicht
mitwandern. Ausserdem feste nicht änderbaren Breiten der
DataGrid-Spalten.
>Also der sollte eigentlich funktionieren, wenn auch
>mit ggf. abgeändertem Code.
ich bekomme hier den Fehler:
footerRow = dg.FooterRow;
da das DataGrid keine Definition für 'FooterRow' hat. das GridView hat
es allerdings.
kann ich das irgendwie umproggen? ich konnte die Daten schon in eine
neue Row machen und diese dann im DataGrid anzeigen lassen, aber da
kann ich den Text nicht Fett machen und auch keine andere
Hintergrundfarbe hinzufügen. Im Footer wäre dies dann aber schon der
Fall. Also vielelicht geht es ja schon, habe aber nichts gefunden im
netz.
grüsse
christoph
>Also der sollte eigentlich funktionieren, wenn auch
>mit ggf. abgeändertem Code.
>ich bekomme hier den Fehler:
>footerRow = dg.FooterRow;
eben, ich sagte ja auch, dass eine FooterRow
für das DataGrid 1.1 schwer zu machen sei, und
dass ich eben an Deiner Stelle eigene TextBoxen
unter das Grid zeichnen würde.
Oder gibt es da einen bestimmten Grund, warum das
bei Dir nicht gehen sollte?
>Oder gibt es da einen bestimmten Grund, warum das
>bei Dir nicht gehen sollte?
wenn ich eine Textbox darunter mache, dann wird mir diese danach nicht
ins Excel exportiert. Ich verwende .NET 2.0 ist es da auch schwer zu
machen?
gruss
christoph
Au, dann haben wir etwas aneinander vorbeigeredet.
Ich frage jetzt lieber nochmal.
Du verwendest also unter .NET 2.0 das DataGrid?
Als WinForm oder Web-Control?
... DataGrid ([1.1 WinForm], [1.1 ASP.NET]), aber unter 2.0 möglich
... DataGridView (WinForm nur 2.0)
.. GridView (ASP.NET 2.0)
hier ständig durcheinanderwirbeln ...
Jedenfalls schon mal vielversprechend, wenn
Du .NET 2.0 benutzt.
[zum Excel-Export:]
Das ist ja eigentlich nur so, das der DataSource
mit einem bestimmten Code nach Excel transferiert wird.
Gibt es aber wieder 100 Möglichkeiten.
Wie sieht denn der Code zum Transferieren nach Excel
aus?
>Du verwendest also unter .NET 2.0 das DataGrid?
>Als WinForm oder Web-Control?
>... DataGrid ([1.1 WinForm], [1.1 ASP.NET]), aber unter 2.0 möglich
>... DataGridView (WinForm nur 2.0)
>.. GridView (ASP.NET 2.0)
also ich habe eine WebAnwendung und habe da ein DataGrid unter .NET
2.0!
Wie gesagt, das DataGrid kann ich exportieren, verwende ich aber ein
DataGridView, bekomme ich beim Export ein Fehler von wegen dass das
Control nicht in den HTML tags liegt.
Desshalb würde ich gerne meine Daten in den Footer vom DataGrid
schreiben und müsste somit nichts mehr anpassen.
Grüsse
Christoph
>also ich habe eine WebAnwendung und habe da ein
> DataGrid unter .NET 2.0!
Leider ist da die Antwort zu meiner Frage nach einem
(Ansatz) Code des Exportes nach Excel noch nicht dabei.
Aber ok, auf die FooterRow im DataGrid unter 2.0
kannst Du z.B. folgendermassen zugreifen:
protected void Page_Load(object sender, System.EventArgs e)
{ if (!IsPostBack)
{ oleDbDataAdapter1.Fill(dataSet11); // als Beispiel
this.DataBind();
}
if (footerRow != null)
{ footerRow.Cells[0].Text = "123"; // oder auslesen
footerRow.Cells[1].Text = "123";
}
}
DataGridItem footerRow;
protected void DataGrid1_ItemDataBound(object sender,DataGridItemEventArgs e)
{ if (e.Item.ItemType == ListItemType.Footer) footerRow = e.Item;
}
siehe auch:
[Pager- und Footerzeilen des DataGrid erweitern]
http://www.aspheute.com/artikel/20040318.htm
hier noch der Export ins Excel. Ich hatte gestern den code nicht zur
Hand.
//SC: START EXPORT data ins Excel
protected void Button1_Click(object sender, EventArgs e)
{
Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.Charset = "";
this.EnableViewState = false;
System.IO.StringWriter oStringWriter = new
System.IO.StringWriter();
System.Web.UI.HtmlTextWriter oHtmlTextWriter = new
System.Web.UI.HtmlTextWriter(oStringWriter);
this.ClearControls(dg);
dg.RenderControl(oHtmlTextWriter);
Response.Write(oStringWriter.ToString());
Response.End();
}
private void ClearControls(Control control)
{
for (int i = control.Controls.Count - 1; i >= 0; i--)
{
ClearControls(control.Controls[i]);
}
if (!(control is TableCell))
{
if (control.GetType().GetProperty("SelectedItem") != null)
{
LiteralControl literal = new LiteralControl();
control.Parent.Controls.Add(literal);
try
{
literal.Text =
(string)control.GetType().GetProperty("SelectedItem").GetValue(control,
null);
}
catch
{
}
control.Parent.Controls.Remove(control);
}
else
if (control.GetType().GetProperty("Text") != null)
{
LiteralControl literal = new LiteralControl();
control.Parent.Controls.Add(literal);
literal.Text =
(string)control.GetType().GetProperty("Text").GetValue(control, null);
control.Parent.Controls.Remove(control);
}
}
return;
}
//SC: END EXPORT data ins Excel
das mit dem Footer hat geklappt... DANKE
gruss
Christoph