Ich habe in einer ASP.NET-Applikation ein (sehr grosses) GridView. Ich möchte da gerne den Header fixieren, damit man beim scrollen immer sieht, welche Spalte was ist.
Nun das Problem: wenn ich im CSS
position: fixed
eingebe bleibt der Header zwar stehen, hat aber nicht mehr die gleiche Breite wie die Tabelle (siehe Anhang). Das liegt wohl daran, dass sich die Spaltenbreite an der Breite des Inhalts orientiert. Wir krieg ich es nun hin, dass der Header die gleiche Breite wie die Tabelle beibehält?
PS: Zum fixierten Header habe ich noch folgendes gefunden:
Im CSS soll man dies angeben:
POSITION: relative;
TOP: expression(this.offsetParent.scrollTop-1.0);
Allerdings bleibt bei mir der Header so nicht stehen und die Angabe bei "top" führt zu ner Fehlermeldung (ungültiger Wert für Eigenschaft)
Für Webanwendungen gilt viel mehr als für Desktop Anwendungen: nur die Daten laden und Anzeigen, die der User wirklich aktiv nutzen kann.
Es riesiges Grid mit 984234 Einträgen macht im Web genauso wenig sinn, wie auf dem Desktop; zusätzlich wird aber das Laden drastisch langsamer.
Wieso arbeitest Du nicht mit Infinity Scroll, das dynamisch Elemente nachlädt oder mit Paging?
PS: das Bootstrap Template unterstützt glaube ich fixe Header bei Tabellen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich hab versucht, die Sache im Code Behind zu richten:
for (int i = 0; i < daten.HeaderRow.Cells.Count; i++)
{
daten.HeaderRow.Cells[i].Width = daten.Rows[0].Cells[i].Width;
// daten ist der Name des GridViews
}
Hat nur leider nicht hingehauen 🙁
Hi MrChangeLog,
ist ja klar, daß das nicht geht. Die Spaltenbreiten werden ja erst im Browser berechnet...
Die ersten Suchergebnisse bei Google sind übrigens:
CSS Only Fixed Table Headers und
How to make Scrollable Table with fixed headers using CSS
Schonmal dort reingeschaut?
Weeks of programming can save you hours of planning
Natürlich nicht.
Der Server kennt die dynamische Breite auch nicht.
Kann er auch gar nicht, da HTTP verbindunglos ist und die Schleife auf dem Server ausgeführt wird; weit bevor der Clietn vom Server das fertige HTML Konstrukt als Antwort des Requests bekommt.
> Grundlagen Webentwicklung 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
ist ja klar, daß das nicht geht. Die Spaltenbreiten werden ja erst im Browser berechnet...
Aber warum kann ich dann Dinge wie Hintergrundfarbe oder Rahmenart auf diese Weise definieren?
Und ja, die Links kenne ich, aber die bringen mir nichts. Wie ich einen fixen Header machen kann weiss ich ja bereits. Das ist auch nicht das Problem, sondern die Breite.
Edit: wenn ich den Spalten eine fixe Breite geben würde, würds natürlich funktionieren. Das möchte ich aber nicht, da die Basis für Tabellen mit unterschiedlicher Spaltenzahl funktionieren soll und die bei fixer Spaltenbreite sonst schnell viel zu Breit werden würde ... zudem sieht es doof aus, wenn ne Spalte, die z.B. nur 6-stellige Strings enthält 350 Pixel breit ist.
Weil Du Farben im Gegensatz zu den Breiten statisch in Deinem Code definierst. Die Breiten willst Du dynamisch haben und sind vom Client abhängig. Das muss also auf dem Client ausgeführt werden und nicht auf dem Server.
Bitte eigne Dir das Verständnis an, wie Webanwendungen funktionieren. Insbesondere HTTP - das ist das A und O.
Wenn Du mit statischen Breiten in Deinem Code arbeitest, was Du hier aber gar nicht willst, dann funktioniert auch diese Art und Weise.
Aber Du kannst nicht vom Server auf den Client zugreifen und fragen, wie die Breite ist.
So funktioniert das Internet nicht.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich habe nun versucht, die Breiten der Zellen im Header via JavaScript anzupassen:
function setWidths() {
var daten = document.getElementById("daten");
for (var i = 0; i < daten.rows[0].childElementCount; i++) {
daten.rows[0].cells[i].offsetWidth = daten.rows[1].cells[i].offsetWidth;
}
}
Das Skript läuft durch, aber die Breiten ändern sich leider trotzdem nicht.
Edit:
WebForms ist auch die falsche Basis, um Inhalte mit JavaScript zu manipulieren.
Es beisst sich mit JavaScript.
Wenn überhaupt wäre es der korrekte Weg, auf den EndRequest-Handler des Postbacks zu hören und dort das Ausführen zu triggern.
Mit viel Glück funktioniert auch jQuery's .on('change')
Event.
Du hast ganz einfach die falsche Basis mit WebForms für sowas.
Dafür wurde WebForms einfach nicht ausgelegt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Zusatz:
Mit
<body onload="window.setTimeout('setWidths()',500);">
kann ich das Ausführen des Skripts verzögern, sodass es erst ausgeführt wird, wenn die Seite geladen ist. Funktionieren tut's trotzdem nicht.
Dass dieses Body-Onload Event funktioniert/funktionieren könnte basiert einzig und allein auf der Annahme, dass Du nach 500ms alle Daten geholt und gerendert hast.
Ist es einmal langsamer als 500ms, passiert nichts. Ist quasi wie Lotto: nur Glück.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Dass dieses Body-Onload Event funktioniert/funktionieren könnte ...
es funktioniert ja eben nicht (bzw. das Skript wird ausgeführt, hat aber nicht das gewünschte Ergebnis).
Ich habe es auch schon mit 30000ms (30s) getestet. Das Ergebnis ist das selbe.
Hallo,
Startscripte für eine Seite sollte man unter WebForms mit ClientScript.RegisterStartupScript(...)
registrieren. Die werden dann erst ausgeführt wenn die Seite geladen ist (es sei den nes werden Daten über Ajax nachgeladen).
Ob man offsetWidth direkt auf dem Element setzten kann, bin ich mir nicht sicher... ich würde es eher mit elem.style.width = otherElem.offsetWidth + 'px'
versuchen.
Ob das alles in Deinem Fall hilft weiss ich nicht. Deine Methode ergibt nicht wirklich Sinn. Du versuchst die Width für jede Zelle zu stezen, aber nur in der ersten Zeile ?!? Was soll der Browser Deiner Ansicht nach damit anfangen?
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
Hallo,
Ob das alles in Deinem Fall hilft weiss ich nicht. Deine Methode ergibt nicht wirklich Sinn. Du versuchst die Width für jede Zelle zu stezen, aber nur in der ersten Zeile ?!? Was soll der Browser Deiner Ansicht nach damit anfangen?
Gruß, MarsStein
Im Prinzip steht alles im Startbeitrag: die Breite der Spalten im GridView wird vom jeweiligen Inhalt bestimmt - genauer: das GridView enthält Strings verschiedener Länge; die Breite der Spalte entspricht dem längsten String in dieser Spalte (+ 8px Padding links und rechts).
Wenn ich den Header nun fixiere, orientieren sich seine Zellen nicht mehr am Rest des GridViews sondern passen die Breite an ihren eigenen Inhalt an (siehe Bild im Startbeitrag).
Mit dem Skript möchte ich nun erreichen, dass jede Zelle des Headers (=daten.rows[0]) die gleiche Breite hat, wie die entsprechende Zelle der ersten Zeile (=daten.rows[1]) des GridViews (ich könnte auch eine beliebige andere Zeile als Referenz nehmen, da ja alle gleich Breit sind).
Hallo,
schau mal in Fixed Table Header Atop Scrollable GridView in ASP.NET und dem dort verlinkten Artikel Scrollable GridView with Fixed Headers in ASP.Net
hth
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
⚠
Nun klappt es!
ClientScript.RegisterStartupScript(daten.GetType(), "JavaScriptFile", "setWidths()", true);
und
function setWidths() {
var daten = document.getElementById("daten");
for (var i = 0; i < daten.rows[0].cells.length; i++) {
daten.rows[0].cells[i].width = daten.rows[1].cells[i].offsetWidth - 18 + "px";
}
}
Komisch ist nur: die Zellen erhalten zwar die korrekte Breite (offsetWidth), werden aus unerfindlichen Gründen aber (alle) um 18px zu gross angezeigt (daher das "-18" im Code).
Weil Du wahrscheinlich noch CSS Code hast, der hier greift.
Siehst Du aber alles in der Entwicklerkonsole von Chrome.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo,
um 18px zu gross angezeigt (daher das "-18" im Code)
Vorsicht! Schau Dir lieber genau an, wo der Grund für dieses Verhalten liegt (wahrscheinlich CSS, wie Abt schreibt, ggf. aber auch borders/paddings etc.).
Mit solchen magischen Konstanten kannst Du Glück haben - meiner Erfahrung nach gibt sowas aber meistens unterschiedliche Ergebnisse in verschiedenen Browsern...
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
:]
function setWidths() { var daten = document.getElementById("daten"); for (var i = 0; i < daten.rows[0].cells.length; i++) { daten.rows[0].cells[i].width = daten.rows[1].cells[i].offsetWidth - 18 + "px"; } }
Komisch ist nur: die Zellen erhalten zwar die korrekte Breite (offsetWidth), werden aus unerfindlichen Gründen aber (alle) um 18px zu gross angezeigt (daher das "-18" im Code).
(Korrektur: es sind tatsächlich 17px) Ich habe mich etwas schlau gemacht und gehe nun davon aus, dass sich die 17px wie folgt zusammensetzen: margin-left 8px + margin-right 8px + border 1px.
Nur eins verstehe ich nicht: die erste Zelle des Headers hat nun eine Breite von 269 Pixel. Die Zelle direkt darunter hat (laut Box Modell) eine Breite von 268.4 Pixel; den Unterschied von 0.6 Pixel sieht man leider. Aber: wie geht das überhaupt? Sowas wie "Zentelspixel" gibt es doch gar nicht?
Natürlich kann es das geben.
Ordentliche Oberflächen sind responsive und arbeiten an vielen Stellen mit relativen Werten /(zB- Prozentverhältnisse).
Dadurch kommt es logischerweise zu Kommazahlen, die dann der Browser beim Rendering entsprechend selbst umsetzt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code