Laden...

[gelöst] ASP.NET 3.5: Tabelle mit Dynamischen erzeugten Rows - Diverse Probleme

Erstellt von Birne vor 13 Jahren Letzter Beitrag vor 13 Jahren 3.496 Views
B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren
[gelöst] ASP.NET 3.5: Tabelle mit Dynamischen erzeugten Rows - Diverse Probleme

Hallo Community,

ich stehe derzeit vor einem Problem im Rahmen eines ASP.NET 3.5 Controls.
Ich hoffe ihr könnt mir abermals helfen.

_
Problembeschreibung:

Ich füge zur Laufzeit einer Tabelle neue Zeilen hinzu.
Die Rows leiten von der Klasse TableRows ab und** implementieren **neben Textboxen udn Inputfeldern auch Buttons.

Die Rows werden der Table nicht direkt hinzugefügt, sie werden zunächst in eine** interne Liste geworfen.
Diese Liste speicher ich
im Sessionobjekt**, um die Rows nach einem POST Back nicht zu verlieren.

Die Rows besitzen eine Propertie welche eine List aller Buttons in den Rows zurückgibt.

Ich habe eine Extra Methode geschrieben welche mir die** inetrne Liste ausliest** und die Rows eben dieser dann zur Tabelle hinzufügt, sowie Button Events registriert, da ja auch diese durch den POST Back verloren gehen.

Es treten im konkreten Fall** zwei Probeleme** auf:

  • Die Buttons reagiseren nur bei jedem zweiten Klick :I

  • Beim Löschen von Rows aus der Liste und der Table, kommt die Table völlig durcheinander und verteilt die Werte der Rows random und die entsprechenden Row wird erst nach mehrmaligem Löschen wird gelöscht, sie rutscht zunächst im Index immer weiter nach oben. Row Nr. 87 müsste 87 mal gelöscht werden, bis sie denn auch wirklich nicht mehr in der Tabelle erscheint.

Beispiel Code:


protected void Page_Load(object sender, EventArgs e)
        {
            // Liest das Sessionobjekt aus
            if (Session["rowList"] == null)
            {
                rowList = new List<AbgeleiteteRow>();
            }
            else
            {
                rowList = (List<AbgeleiteteRow>)Session["rowList"];
            }

            // Fügt der Table die neuen Rows hinzu und melden alle Events der Buttons an
            ShowTable();
        }


        protected void ShowTable()
        {
            foreach (AbgeleiteteRow row in rowList)
            {
                foreach (AbgeleiteteRowButton btn in row.Buttons)
                {
                    // Eventhandler anmelden
                    btn.Click += new EventHandler(Click_EventHandler);
                }
                // Rows der Table hinzufügen
               TheTable.Rows.Add(row);
            }
        }

Der Klick Event Handler


        void Click_Eventhandler(object sender, EventArgs e)
        {
            AbgeleiteteRowButton btn = sender as AbgeleiteteRowButton;
            
            // jeder Button enthält eine referenz auf seine Row
            AbgeleiteteRow RowOfButton = btn.AbgeleiteteRow;

            // Löschen oder neu anfügen
            if (btn.AddOrRemove) // Hinzufügen
            {
                // Wir fügen eien neue AbgeleiteteRow hinzu
                AbgeleiteteRow newAbgeleiteteRow = newAbgeleiteteRow(RowOfButton.IsRepeatable, true, RowOfButton.ZAObjectTypeId, RowOfButton.Name);

                // Die Row wird direkt unter dem Vorgängereingefügt
                rowList.Insert(rowList.IndexOf(recievedRow) + 1, newAbgeleiteteRow);
            }
            else // Löschen
            {
               
                // Die Row aus der internene Liste an der richtigen Stelle löschen
                rowList.RemoveAt(rowList.IndexOf(RowOfButton));

                // Die Row aus der Table löschen
                TheTable.Rows.Remove(RowOfButton);
                
            }
            // Die RowListe in das Sessionobjekt werfen
            Session["rowList"] = rowList;

            // DIe Tabelle anzeigen
            ShowTable();
        }

Ich sitze an dieser Stelle fest, weiss nicht, warum die Evenets nur jedme zeitwen Click funktionieren, oder die Rows nicht korrekt gelöscht werden.

Ich hoffe ihr könnt mir helfen
Vielen Dank schonmal !

Birne

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

ich habe den Code jetzt nicht eingehend auf Fehler untersucht, aber ich vermute Du bekommst Probleme mit dem ViewState, weil Du die Verwaltung der Tabelle vollständig selbst übernehmen willst.

Schalte mal den ViewState ab (EnableViewState auf false setzten, entweder für die Tabelle oder für die ganze Page), und schau mal was dann passiert.

Dynamische Steuerelemente solltest Du möglichst schon im Init-Ereignis erstellen.

Allgemein solltest dDu Dich mit dem Lebenszyklus von ASP.NET-Seiten befassen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren
Problem 2 damit gelöst.

Vielen Dank für die Ausführliche und Hilfreiche Antwort und den Link.

Die Tabellenrows lassen sich jetzt wunderbar löschen, auch mit den Werten in der Tabelle wird kein Lotto mehr gespielt 👍

_
Bleibt nur noch Problem 1 über,

die Events reagieren jeweils nur beim zweiten Klick.
Nach jedem ersten Click, verschwinden ALLE zuvor gemachten Eingaben. Beim Click 2 läufts dann.

Da stimm etwas mit dem Lifecycle nicht, nur was ? 🙁

Vielen Dank bisher !

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

in Deinem Code aus dem Startbeitrag machst u noch einen systematischen Fehler:

  • Du erstellst die Rows im Load (oder mittlerweile Init?) durch den Aufruf von ShowTable.
  • im Click-Handler erstellst Du sie nochmal
  • beide male hängst Du den EventHandler an das selbe Objekt
  • dann behältst Du das Objekt in der Session, so daß beim nächsten Aufruf noch mehr EventHandler dazukommen, ohne daß jemals die alten deregistriert werden.

Es ist mir eigentlich schleierhaft, wie das überhaupt laufen kann.

Diese Liste speicher ich im Sessionobjekt, um die Rows nach einem POST Back nicht zu verlieren.

Besser wäre IMHO, die Controls in jedem Aufruf neu zu erstellen. Das entspricht auch der üblichen Vorgehensweise, wenn man keine Datenbindung benutzt. Am besten vergibst DU dann auch gleich eine eindeutige ID.

sowie Button Events registriert, da ja auch diese durch den POST Back verloren gehen. Auch diese können neu registriert werdne, wenn die Rows neu erstellt werden. Diese Arbeit könntest Du Dir wahrscheinlich sogar vom ViewState abnehmen lassen, wenn Du es wieder einschaltest.

Deine Vorgehensweise bisher ist also nicht gerade konventionell -> betrachte meine Antwort daher als Stups in eine andere Richtung. Das alles genauer und umfassend zu beleuchten, würde allerdings den Rahmen des Threads sprengen, dafür ist die Doku da und etliche Quellen im Internet, die sich damit befassen.

Bei konkreten Fragen in der Ausarbeitung kannst Du aber gerne nochmal nachfragen.

Gruß, MarsSTein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Hallo Marsstein,

ich habe jetzt deinen rat befolgt, mich mit dem Lifecycle befasst und auch die Rows alle im init erzeugt.
Ich komem trotzdem nicht witer.

Ich habe bereits eine Exkursion in Javascript unternommen - mit mäßigem Erfolg.

Derzeit gehe ich Folgt vor im LifeCycle meines Controls

Init

  • Erzeugen der Rows, durch auslesen der internen Liste

Load

  • Anmelden der Events

Prerender

  • Temporäres anfügen der Row an die Table (geht beim nächsten Postback natürlich verloren)

Problematischerweise sitzt das Eventhandling ja zwischen dem Load und dem PreRender ...
Wenn ich also in meinem Click Event handler eine neue Row meiner Liste hinzufüge, gibt es keine funktionierende Möglichkeit diese auch anzuzeigen.

Ich kann die Rows auch nicht erst im Prerender erzeugen, weil die Eventhandler erst nach einem Button Click und dem damit verbundenen Postback angemeldet werden müssen.

Ich muss meine Rows und Events also im Init erzeugen, anonsten wird der Eventhandler beim Clicken garnicht erst aufgerufen.

Bisher bin ich mit allen meinen Versuchen das Problem in den Griff zu bekommen gescheitert.
Als da wären:

  • Postback verursache im ButtonClick event. Gibt im günstigstens Fall nen JScript Error an dieser Stelle.

  • Buttons mit OnClientClick Event mit Javascript für Postback versehen. Called die Loadmethode gleich zweimal ...

  • Die Row welche der internen Liste hinzugefügt wurde im Preload Event der Table zuweisen:
    Funktioniert bis ich die nächste Row hinzufüge. Dann treten seltsame Effekte auf, bei welchen in Vermute es liegt an der Identifikation der Rows. ASP.NET und meine inetrne Liste vertragen sich also nicht :0

Wie löse ich nun das Problem ? 😦

Ich habe mich das ganez WE tot gegoogelt. so ziemlich Alles ausprobiert, nichts hilft :S

Ich bitte um Rat.

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

Erzeugen der Rows, durch auslesen der internen Liste

Versuchst Du immer noch, die Rows über diese Liste zu persistieren?
Du solltest die Controls jedenfalls nicht in der Liste halten, eher die benötigten Daten zum Erzeugen der Controls. Die Controls sollten im Init immer wieder mit new erzeugt werden.
Du kannnst dann die einzelnen Zeilen im EventHandler erstellen und hinzufügen, sorge nur dafür daß sie beim nächsten Aufruf im Init miterstellt werden.

Alternativvorschlag:
In Deinem Fall würde ich Dir eher dazu raten, ViewState wieder einzuschalten und mit Datenbindung zu arbeiten.
Sprich Du erstellst Dir z.B. eine DataTable mit den Spalten, die Du in der Tabelle haben willst, und ein GridView für die Anzeige. Dann bindest Du die Tabelle ans Gridview (nur wenn kein PostBack vorliegt - andernfalls ist der ViewState dran). Für die Einfüge-Operationen kannst Du dann z.B. ein CommandField verwenden, dann läuft das allermeiste automatisch. Im Handler, der eine Zeile hinzufügt, fügst Du in Wirklichkeit der gebundenen DataTable eine Zeile hinzu, und bindest die Daten neu.

Das wäre so die "normale" Lösung. Die verlinkte Doku-Seite ist sehr umfangreich, aber auch sehr hilfreich. Wenn Du diesen Weg einschlagen willst, empfehle ich, sie zuerst komplett zu lesen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Hallo Marsstein und vielen Dank für deine bisherige Hilfe.

Bevor ich mich an den Alkternativvorschlag heranwage, habe ich variante 1 noch einmal ausprobieret.

Erzeugen der Rows, durch auslesen der internen Liste
Versuchst Du immer noch, die Rows über diese Liste zu persistieren?
Du solltest die Controls jedenfalls nicht in der Liste halten, eher die benötigten Daten zum Erzeugen der Controls. Die Controls sollten im Init immer wieder mit new erzeugt werden.
Du kannnst dann die einzelnen Zeilen im EventHandler erstellen und hinzufügen, sorge nur dafür daß sie beim nächsten Aufruf im Init miterstellt werden.

Ok, ich lese jetzt meine Interne Liste aus, erstelle aber neue Rows mit den Properties der Rows aus der internen Liste.

Doch nach wie vor treten mir unerklärliche Effekte auf 😦

Die Events reagieren nur bei jedem zweitem Click, auf jeden ersten Click fügt sich ein "+" an irgendeine Zelle ein und ein die bisherigen Rowzellen scheinen wild durcheinander zu fliegen.

Aktuelle Implementation sieht wie folgt aus:

INIT

  • Einmaliges füllen der internen Liste (!IsPostback).
  • Auslesen der internen Liste aber mit new neue Rows erzeugen und der Tabelle hinzufügen
  • Events anmelden
  • Button referenzen aus sicherheitsgründen übergeben

EVENTHANDLER

  • Neue Row erstellen
  • Eventhandler anmelden
  • Row der internen Liste hinzufügen
  • Row der Table hinzufügen

Erster Click:

  • Postback
  • Click Eventhandler wird aufgerufen
  • Zeile wird hinzugefügt an richtiger Stelle

= Alles Schön

Versuch weitere Row anzulegen mit Click auf irgendeinen der Buttons zum adden einer neuen Row:

  • Postback
  • Clickeventhandler wird NICHT AUFGERUFEN
  • '+' erscheint irgendwo in eienr Zelle
  • Zellen durcheinandergewürfelt

Erneuter Click

  • Postback
  • Click Eventhandler wird aufgerufen
  • Zeile wird hinzugefügt an richtiger Stelle

usw. usf.
Auch wenn der Alternativvorschlag besteht und ich diesen wohl eher in Betracht ziehen werde, will ich wissen, warum das Ganze bei der bisherigen Variante so fatal verbuggt.

Alternativvorschlag:
Das wäre so die "normale" Lösung. Die verlinkte Doku-Seite ist sehr umfangreich, aber auch sehr hilfreich. Wenn Du diesen Weg einschlagen willst, empfehle ich, sie zuerst komplett zu lesen.

Werde ich mich definitiv mit befassen
aber dennoch will ich obiges Problem lösen.

EDIT:

Als Anmerkung vielleicht noch.
Es handelt sich bei mir NICHT um eine Seite, sondern um ein Seperates Usercontrol, der Viewstate ist für dieses Usercontrol aber abgeschalten.
Vielen Dank
Birne

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

  • '+' erscheint irgendwo in eienr Zelle

Das ist schon seltsam. Ich schätze, Du versuchst noch irgendwas automatisiertes zu nutzen, was aber nicht funktioniert, weil ViewState abgeschaltet ist oder andere Voraussetzungen fehlen, da Du sonst alles von Hand machst.
Was das genau sein soll, kann ich nicht sagen. Dazu braucht es nochmal etwas Code.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

OK Danke.

Hier also etwas Code:

Members


        /// <summary>
        /// Enthält zur Erstellung der Tabellenspalte benötige Informationen
        /// </summary>
        public List<abgeleiteteRow> rowList;

S1 - Init
Einmalig- und erstmaliges Füllen der internen Liste


            #region - On Start -
            if (!IsPostBack)
            {
                foreach (TypeDataSet.TypeRow row in TypeDataSet.TableName)
                {
                    abgeleiteteRow tRow = new abgeleiteteRow(row.REPEATABLE, false, row.ID, row.NAME);
                    rowList.Add(tRow);
                    tRow.Index = rowList.IndexOf(tRow);
                }
                Session["rowList"] = rowList;
            }
            #endregion - On Start -

Tabelle befüllen


            foreach (abgeleiteteRow row in rowList)
            {
                // Neue Row erstellen
                abgeleiteteRow = new newRow(row.IsRepeatable, row.IsRepeated, row.ZAObjectTypeId, row.Name);
                newRow.DateFrom = row.DateFrom;
                newRow.DateTo = row.DateTo;
                newRow.Days = row.Days;
                newRow.Hours = row.Hours;
                newRow.Remark = row.Remark;
                newRow.Index = row.Index;

                tblObjects.Rows.AddAt(newRow.Index, newRow);

                // Events anmelden, row refenrezne übergeben
                foreach (abgeleiteteRowButton btn in newRow.Buttons)
                {
                    btn.AbgeleiteteRow = newRow;
                    btn.Click +=new EventHandler(btn_Click);
                }
            }

S3 - Eventhandling


        void btn_Click(object sender, EventArgs e)
        {
            abgeleiteteRowButton btn = sender as abgeleiteteRowButton;
            abgeleiteteRow recievedRow = btn.AbgeleiteteRow;

            // Löschen oder neu anfügen
            if (btn.AddOrRemove)
            {
                abgeleiteteRow tRow = new abgeleiteteRow(recievedRow.IsRepeatable, true, recievedRow.ZAObjectTypeId, recievedRow.Name);

                this.rowList.Insert(recievedRow.Index + 1, tRow);
                tblObjects.Rows.AddAt(recievedRow.Index + 1, tRow);

            }
            else
            {
                this.rowList.RemoveAt(recievedRow.Index);
                tblObjects.Rows.RemoveAt(recievedRow.Index);
            }
            Session["rowList"] = rowList;
        }

Vielen Dank
Birne

S
902 Beiträge seit 2007
vor 13 Jahren

Hallo,

also so wie ich das sehe, speicherst du die Rows immernoch in der Session, besser ist es diese jedesmal im Init neu zu erzeugen, wie MarsStein schon gesagt hat.

Ich würde dir dennoch empfehlen mit einem GridView zu arbeiten, und deine Aktionen mit Commands in diesem zu behandeln.

mfg
serial

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Hallo,
also so wie ich das sehe, speicherst du die Rows immernoch in der Session, besser ist es diese jedesmal im Init neu zu erzeugen, wie MarsStein schon gesagt hat.

Ich erzeuge die jedesmal neu, in der Session liegen Rows ja, allerdings nutze ich nur die Informationen dieser Rows.

  
 // Neue Row erstellen  
                abgeleiteteRow newRow = new newRow(row.IsRepeatable, row.IsRepeated, row.ZAObjectTypeId, row.Name);  
  

Jede Row in der Table ist eine neu Erzeugte.

Ich würde dir dennoch empfehlen mit einem GridView zu arbeiten, und deine Aktionen mit Commands in diesem zu behandeln.

Wie schon erwähnt, werde ich dies auch tun, allerdings möchte ich dieses Problem gerne lösen, unabhängig davon, ob das es eine elegantere Lösung gibt.

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

jetzt gibt's plötzlich noch eine Klasse newRow - warum? Du verkomplizierst die Sache dadurch ja nur.

            {
                abgeleiteteRow tRow = new abgeleiteteRow(recievedRow.IsRepeatable, true, recievedRow.ZAObjectTypeId, recievedRow.Name);

                this.rowList.Insert(recievedRow.Index + 1, tRow);
                tblObjects.Rows.AddAt(recievedRow.Index + 1, tRow);
// hier hat die neu erzeugte Row noch keinen Click-Handler!!

            }

Siehe meinen Kommentar in obigem Quellcode. Das erklärt zumindest, warum bei Click eines Buttons in einer neuen Zeile das Event nicht ausgelöst wird, aber nicht für die vorhandenen 😦

Warum arbeitest Du mit dieser Ableitung von TableRow, was passiert denn da drin sonst noch? Könnte es an der Implementierung dieser Klasse liegen?

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

S
902 Beiträge seit 2007
vor 13 Jahren

OK,

das sehe ich allerdings problematisch, wenn du es wirklich so machst:

EVENTHANDLER

  • Neue Row erstellen
    - Eventhandler anmelden
  • Row der internen Liste hinzufügen
  • Row der Table hinzufügen

das solltest du NICHT im Eventhandler machen, dies kann auch zu nebeneffekten führen.

mfg
serial

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Hallo,

jetzt gibt's plötzlich noch eine Klasse newRow - warum? Du verkomplizierst die Sache dadurch ja nur.

Sorry Tipfeghler von mir.
Ist korrigiert.

            {  
                abgeleiteteRow tRow = new abgeleiteteRow(recievedRow.IsRepeatable, true, recievedRow.ZAObjectTypeId, recievedRow.Name);  
  
                this.rowList.Insert(recievedRow.Index + 1, tRow);  
                tblObjects.Rows.AddAt(recievedRow.Index + 1, tRow);  
// hier hat die neu erzeugte Row noch keinen Click-Handler!!  
  
            }  
  

Den habe ich wieder rausgenommen, weil er keinen effekt hat.
Wenn ich auf einen Button clicke, wird zunächst der PostBack verursacht, also geht die Clickeventanmeldung ohnehin verloren.

Das erklärt zumindest, warum bei Click eines Buttons in einer neuen Zeile das Event nicht ausgelöst wird, aber nicht für die vorhandenen 😦

Leider tut es das nicht :S

Warum arbeitest Du mit dieser Ableitung von TableRow, was passiert denn da drin sonst noch? Könnte es an der Implementierung dieser Klasse liegen?

Gruß, MarsStein

Die TableRow enthält Felder für zwei Buttons, 5 typisierte Textboxen und ein Label.
Desweiteren Properties für ein paar IDs und Boolsche Variablen.


OK,

das sehe ich allerdings problematisch, wenn du es wirklich so machst:

EVENTHANDLER

  • Neue Row erstellen
    - Eventhandler anmelden
  • Row der internen Liste hinzufügen
  • Row der Table hinzufügen

das solltest du NICHT im Eventhandler machen, dies kann auch zu nebeneffekten führen.

mfg
serial

Ich habe es probiert, und es hat keinen Effekt weil eben erst der Postback kommt.
Die Eventhandler müssen alle im INIT neu erzeugt werden damit sie funktionieren.

OT aus Interesse:
Welche Probeleme können denn dabei auftreten wenn ich es so machen würde und es täte funktionieren ?
Bei Windows Forms lief das auch immer Prima.

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

Den habe ich wieder rausgenommen, weil er keinen effekt hat.

Bist Du sicher?

Wenn ich auf einen Button clicke, wird zunächst der PostBack verursacht, also geht die Clickeventanmeldung ohnehin verloren. Das ist zwar richtig. Aber wenn der PostBack stattfindet, wird ja genau der Handler ausgeführt, der beim vorherigen Request registriert wurde! Deshalb ist es IMHO nötig, den Handler direkt zu registrieren.
Das stimmt so nicht, u.a. weil ViewState abgeschaltet ist.

Außerdem hast Du offenbar nicht bedacht, daß sich durch die Inserts die Indizes aller nachfolgenden Zeilen verschieben - und die sind noch als Member gespeichert. Das macht höchstwahrscheinlich auch Probleme.

Zusätzlich empehle ich grundsätzlich, eigene IDs für alle Controls zu vergeben.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Hallo,

Den habe ich wieder rausgenommen, weil er keinen effekt hat.
Bist Du sicher?

Ja

Wenn ich auf einen Button clicke, wird zunächst der PostBack verursacht, also geht die Clickeventanmeldung ohnehin verloren.
Das ist zwar richtig. Aber wenn der PostBack stattfindet, wird ja genau der Handler ausgeführt, der beim vorherigen Request registriert wurde! Deshalb ist es IMHO nötig, den Handler direkt zu registrieren.

Probiere das mal mit Hilfe des Debuggers aus. Dem ist nicht so, hat mich auch erstaunt.
Und wenn das so wäre, dann würde ich die dämlichen Rows auch nicht im INIT erzeugen sondenr im Prerender reinwerfen, nur aus Gründen der Eventanmeldung mache ich das.
Es erzählen zwar immer alle, man soll neue Objekte im INIT erzeugen aber den Sinn sehe ich darin nicht, weil in der MSDN steht, das gewisse Änderungen im PreRender durchgeführt werden.
Und so kennt man es auch von Ajax, selber Cicle.
Stage 4 die Seite ist da, alle sichtbaren Änderungen welcher der Entwickler noch wünscht, werden dort getätigt.

Außerdem hast Du offenbar nicht bedacht, daß sich durch die Inserts die Indizes aller nachfolgenden Zeilen verschieben - und die sind noch als Member gespeichert.
Das macht höchstwahrscheinlich auch Probleme.

Argh !!!
Gut, dass du das erwähnst ! Das werde ich gleichmal beheben, ändert aber nichts an den ButtonEvents und den "+" Zeichen 😦

Zusätzlich empehle ich grundsätzlich, eigene IDs für alle Controls zu vergeben.

Im INIT ?

Edit:
Bitte erstmal nicht weiterrätseln, ich bin auf heisser Spur jetzt !
Ich gebe weiteres hier bekannt.

Edit2:
Hat sich wieder erledigt.
Ich könnte noch vermuten er schiebt mir den "+" Text des ersten Buttons, welcher IMMER erzeugt wird auf die vorherige Textbox Cell, macht aber wenig Sinn.

Edit3:
Index Problem behoben.

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

Was das anhängen des Handlers betrifft hast Du recht. Hatte da was falsches im Kopf (siehe Kommentar).
Mein Beispiel ist sehr kurz gehalten, und demonstriert nur das EventHandling:

  1. eine abgeleitete Klasse, die lediglich einen Button enthält:
public class MyRow : TableRow
{
  public Button b;
  public MyRow(int counter)
  {
    this.Cells.Add(new TableCell());
    b = new Button();
    b.Text = counter.ToString();
    this.Cells[0].Controls.Add(b);
  }
}
  1. Ein einfaches UserControl
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" EnableViewState="false" %>
<div style="width:200px;height:80px;background.color:blue">
<asp:Table ID="myTable" runat="server">
</asp:Table>
</div>
public partial class WebUserControl : System.Web.UI.UserControl
{
  List<MyRow> rows = new List<MyRow>();
  public event EventHandler click;
  int rowCount = 0;

  protected override void OnInit(EventArgs e)
  {
    if (Session["rows"] == null)
    {
      rows = new List<MyRow>();
      Session["rows"] = rows;
      rows.Add(new MyRow(rowCount));
    }
    else
    {
      rows = (List<MyRow>)Session["rows"];
    }
    rowCount = 0;
    foreach (MyRow row in rows) 
    {
      MyRow newRow = new MyRow(rowCount);
      rowCount++;
      newRow.b.Click += new EventHandler(insertButton_Click);
      myTable.Rows.Add(newRow);
    }
  }

  void insertButton_Click(object sender, EventArgs e)
  {
    MyRow newRow = new MyRow(rowCount);
    rows.Add(newRow);
    myTable.Rows.Add(newRow);
// hier braucht man den Handler tatsächlich nicht registrieren.
    rowCount++;
  }
}

Das Beispiel tut genau was es soll - es fügt bei Click eine neue Zeile (mit einem neuen Button) hinzu. Und zwar nicht nur bei jedem zweiten, sondern bei jedem. Der Counter ist nur dafür da, damit irgendwas auf den Knöpfen steht.

Anhand dieses Beispiels soltest Du nun herausfinden können, was bei Dir schiefläuft.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren
From the Finest

Super !

Läuft einwandfrei.
Der Fehler in diesem Fall:
Das Buttonpropertie, sowie der Rowaufbau als Solcher.
Ich habe den Cellcontent nun direkt über den Cellindex hinzugefügt und die Buttons einfach Public definiert.

Vielen Dank euch beiden und vorallem Marsstein für eure Mühen !
Birne

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Hallo Community,

ich bins noch einmal:

Nachdem ich also die Row dynamisch im Event hinzugefügt habe, gibt es ein weiteres Problem.
Mit dem Button ist stets die Umschliessende Row verknüpft, diese benötige ich, um unterer anderem den aktuellen Index zu ermitteln.

Wenn ich auf den Button der neuerstellten Row klicke, ist nicht der Button der neuerstellten Row der Sender, sondern stets der letzte in der Auflistung BEVOR, das Buttonevent ausgeführt wurde.

Gibts eine Möglichkeit das zu eleminieren oder ist das, das Resultat aus dem dem Lifecycle ?

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

das ist vermutlich das Resultat automatisch vergebener ID's, weil die vom Server durchnummeriert werden, und damit auch an dieser Stelle eine Indexverschiebung erfolgt.
Wenn Du die IDs für die Buttons selbst vergibst, und dafür sorgst, daß dieselben Knöpfe auch immer dieselbe ID enthalten (also _nicht _einfach durchnummerieren!), sollte sich das Problem erledigen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
Birne Themenstarter:in
67 Beiträge seit 2009
vor 13 Jahren

Danke !

Das hat funktioniert.