Laden...

ASP.NET WebForms GridView mit fixem header

Erstellt von MrChangeLog vor 6 Jahren Letzter Beitrag vor 6 Jahren 3.227 Views
MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren
ASP.NET WebForms GridView mit fixem header

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)

16.807 Beiträge seit 2008
vor 6 Jahren

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.

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

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 🙁

5.657 Beiträge seit 2006
vor 6 Jahren

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

16.807 Beiträge seit 2008
vor 6 Jahren

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 😉

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

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.

16.807 Beiträge seit 2008
vor 6 Jahren

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.

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

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:

  1. Wenn ich das Skript dem onclick-Event eines Buttons zuweise wird es ausgeführt, hat aber wie gesagt keine Auswirkung. Ich habe den Verdacht, dass da auch ein PostBack ausgelöst wird, was mir dazwischenfunkt.
  2. Wenn ich das Skript dem onload-Event des Bodys zuweise wird es ausgeführt. Das bringt mir aber nichts, da das GridView dann noch nicht geladen wurde.
  3. Wenn ich das Skript dem onload-Event irgend eines HTML-Steuerelements zuweise wird es NICHT ausgeführt.
16.807 Beiträge seit 2008
vor 6 Jahren

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.

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

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.

16.807 Beiträge seit 2008
vor 6 Jahren

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.

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

Dass dieses Body-Onload Event funktioniert/funktionieren könnte ...

  1. es funktioniert ja eben nicht (bzw. das Skript wird ausgeführt, hat aber nicht das gewünschte Ergebnis).

  2. Ich habe es auch schon mit 30000ms (30s) getestet. Das Ergebnis ist das selbe.

3.170 Beiträge seit 2006
vor 6 Jahren

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

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

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).

3.170 Beiträge seit 2006
vor 6 Jahren

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

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

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).

16.807 Beiträge seit 2008
vor 6 Jahren

Weil Du wahrscheinlich noch CSS Code hast, der hier greift.
Siehst Du aber alles in der Entwicklerkonsole von Chrome.

3.170 Beiträge seit 2006
vor 6 Jahren

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

MrChangeLog Themenstarter:in
121 Beiträge seit 2016
vor 6 Jahren

:]

  
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?

16.807 Beiträge seit 2008
vor 6 Jahren

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.