Announcement

Collapse
No announcement yet.

Probleme mit Events (nur jeder zweite Klick löst ein Event aus)

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Probleme mit Events (nur jeder zweite Klick löst ein Event aus)

    Hallo!<BR><BR>
    Situation:
    Es handelt sich um eine Auflistung von Artikeln für einen Shop. In jeder Reihe ist eine Textbox für die Anzahl des Artikels und ein Button zur Übernahme der Menge. Ändere ich die Anzahl in der Textbox und drücke den Button zum übernehmen, funktioniert es nur jedes zweite Mal.
    Wenn ich die Seite zum ersten Mal lade und drücke dann den Button funktioniert es. Drücke ich erneut funktioniert es nicht. Drücke ich anschließend noch mal, dann geht’s und dann wieder nicht und so weiter und so fort …
    <BR><BR>
    Ich weiß nicht mehr weiter. Stefan
    <BR><BR>
    Hier ein stark vereinfachtes Beispiel (zeigt aber die Problematik)
    <BR><BR>
    <PRE>
    private void Page_Load(object sender, System.EventArgs e)
    {
    doListing();
    }

    private void doListing()
    {
    tblArtikel.Controls.Clear();

    for(int i = 0; i < 10; i++)
    {
    TableRow tr = new TableRow();
    TableCell td = new TableCell();
    Button btn = new Button();
    btn.Text = i.ToString();
    btn.CommandArgument = i.ToString();
    btn.Command +=new CommandEventHandler(btn_Command);
    td.Controls.Add(btn);
    tr.Controls.Add(td);
    tblArtikel.Controls.Add(tr);
    }
    }

    private void btn_Command(object sender, CommandEventArgs e)
    {
    //Modifizieren
    Response.Write(e.CommandArgument);
    doListing();
    }
    </PRE>

  • #2
    Hallo Stefan,

    zwei Probleme fallen mir auf:

    1) In Page_Load wird doListing aufgerufen, unabhängig davon, ob die Seite zum ersten Mal oder in einem Postback aufgerufen wird. Das führt dazu, daß doListing bei einem Klick auf den Button zweimal aufgerufen wird: Einmal in Page_Load und einmal in btn_Command.

    Abhilfe schafft das IsPostBack-Property der Page. Es ist true, wenn die Seite als Folge eines Postbacks geladen wird.

    private void Page_Load(object sender, System.EventArgs e)

    {

    if (!IsPostBack) {

    doListing();

    }

    }

    2) Dein Button ist nicht statisch auf der Seite definiert, sondern er wird in doListing dynamisch geladen. Dies geschieht in der Behandlung des Page.Load-Ereignis und danach nochmal im btn_Command.

    Für das Laden von dynamisch generierte Controls ist es wichtig, den Ablauf der Ereignisse in ASP.NET beim Aufbau einer Postback-Seite zu beachten. Zuerst kommt Page.Init, das dazu führt, daß alle Controls geladen werden. Danach versorgt ASP.NET die geladenen Controls mit den Informationen aus dem Viewstate und danach wird Page.Load ausgelöst. Im zugehörigen Eventhandler Page_Load stehen dann die Controls und ihr Status zur Verfügung.

    Wird ein Control erst in Page_Load geladen, dann kann ASP.NET das Control nicht mehr mit den Viewstate-Informationen initialisieren.

    Wenn Du also deine Controls dynamisch laden willst oder musst, dann solltest Du das im Eventhandler für Page.Init tun und nicht in Page_Load.

    Hth,

    Klau

    Comment


    • #3
      Hallo Klaus,<br />
      die Variante mit der Property <I>&quot;IsPostBack&quot;</I> habe ich schon ausprobiert. Da hatte ich folgendes Problem: Nachdem die Seite geladen war und man einen Button bet&auml;tig hatte kam ich nicht mehr in die Methode <I>btn_Command</I>. Und somit war danach auch keine Tabelle mehr zu sehen. Ich habe den Aufruf von <I>doListing()</I> in <I>Page_Load</I> nach <I>OnInit</I> verlegt. Ist aber nach wie vor dieselbe Problematik. Auf den Viewstate bin ich nicht angewiesen, jedoch auf das dynamische laden von den Buttons. Da es ja eine &quot;n&quot; Anzahl an Artikeln geben kann. <br />
      Den zweite Aufruf der Methode <I>doListing()</I> im der Methode <I>btn_command</I> brauche ich ja auf Grund des Ablaufes der Ereignisbehandlung von ASP.NET (init -&gt; load -&gt; events). Denn erst in der Ereignisroutine von Button (<I>btn_command</I>) kann ich auf die Ver&auml;nderung reagieren und dann kann ich ja erst die ver&auml;nderte Liste ausgeben.<br />
      <br />
      Ich habe echt keinen Plan mehr. Ich habe auch im Moment keine andere Idee um diese Situation zu l&ouml;sen. <B>Vielen Dank!</B> Stefa

      Comment


      • #4
        Hallo Stefan,

        den Viewstate brauchst Du schon, da das CommandArgument für den Button im Viewstate zwischen den Postbacks gespeichert wird.

        Folgendes Beispiel funktioniert bei mir:

        public class WebForm1 : System.Web.UI.Page

        {

        protected System.Web.UI.WebControls.Label Label1;

        protected System.Web.UI.WebControls.Table Table1;

        protected Button btn ;


        private void Page_Init(object sender, System.EventArgs e)

        {

        TableRow tr = new TableRow();

        TableCell td = new TableCell();

        btn = new Button();

        btn.Text = "DynBtn";

        btn.ID="DynBtnID";


        btn.CommandArgument= "DynBtnCmdArg "+System.DateTime.Now.ToString();

        btn.Command +=new CommandEventHandler(btn_Command);


        td.Controls.Add(btn);

        tr.Controls.Add(td);

        Table1.Controls.Add(tr);

        }


        private void Page_Load(object sender, System.EventArgs e)

        {

        }


        private void btn_Command(object sender, CommandEventArgs e)

        {

        Label1.Text=e.CommandArgument.ToString();

        btn.CommandArgument = "DynBtnCmdArg "+System.DateTime.Now.ToString();

        }
        }
        }

        Die Variable btn muss ausserhalb der Eventhandler deklariert werden, da beide Eventhandler Page_Init und btn_Command auf dieselbe Instanz zugreifen müssen. Du musst das Beispiel wahrscheinlich um ein Array oder eine Arraylist erweitern, da Du ja mehrere Buttons hast.

        Schöne Grüße,

        Klau

        Comment


        • #5
          Guten Morgen Klaus,<br />
          <br />
          erstmal Vielen Dank f&uuml;r deine M&uuml;hen! Dein Beispiel funktioniert bei mir auch einwandfrei. Ich habe noch mal ein kleines Beispiel Programm erstellt was meine Situation besser zeigt. Vielleicht k&ouml;nntest du es soweit ändern das es funktioniert. Du hast geschrieben:<br />
          <br />
          <I>Die Variable btn muss ausserhalb der Eventhandler deklariert werden, da beide Eventhandler Page_Init und btn_Command auf dieselbe Instanz zugreifen m&uuml;ssen. Du musst das Beispiel wahrscheinlich um ein Array oder eine Arraylist erweitern, da Du ja mehrere Buttons hast.</I><br />
          <br />
          Ich versteh zwar was du meinst, jedoch haperst's bei der Umsetzung. Stefan<br /><br />
          <pre>
          public class WebForm1 : System.Web.UI.Page
          {
          protected System.Web.UI.WebControls.Table Table1;

          private void Page_Init(object sender, System.EventArgs e)
          {
          // das ist nur für das Beispiel. Normalerweise existiert eine ArrayList in der Session-Variablen mit Instanzen von Item (Anzahl, ID, ..)
          if(!IsPostBack)
          {
          // der index dient als ID und i dient als Anzahl
          ArrayList arrAnz = new ArrayList();
          for(int i = 0; i < 10; i++)
          arrAnz.Add(i);

          Session["anz"] = arrAnz;
          }

          doListing((ArrayList)Session["anz"]);
          }

          private void Page_Load(object sender, System.EventArgs e)
          {

          }

          private void btn_Command(object sender, CommandEventArgs e)
          {
          // Festellen welcher Button gedrück worden ist
          string ID = e.CommandArgument.ToString();

          // die dazu gehörige TextBox finden
          TextBox txt = (TextBox) FindControl(ID);
          ArrayList arrAnz = (ArrayList)Session["anz"];

          for(int i = 0; i < arrAnz.Count; i++)
          {
          if(i == Convert.ToInt32(ID))
          {
          // den veränderen Menge aktualisieren
          arrAnz.RemoveAt(i);
          arrAnz.Insert(i, Convert.ToInt32(txt.Text));
          break;
          }
          }

          Session["anz"] = arrAnz;
          // wäre meine Aufruf der veränderten Liste
          //doListing(arrAnz);
          }

          private void doListing(ArrayList nArrAnz)
          {
          Table1.Controls.Clear();

          for(int i = 0; i < 10; i++)
          {
          TableRow tr = new TableRow();

          TableCell td0 = new TableCell();
          //Soll den Preis darstellen
          td0.Text = i.ToString();

          // TextBox für die Anzahl des Artikels
          TableCell td1 = new TableCell();
          TextBox txtAnz = new TextBox();
          txtAnz.Text = nArrAnz[i].ToString();
          txtAnz.ID = i.ToString();
          td1.Controls.Add(txtAnz);

          // Summe aus Preis(td0) und Menge(td1)
          TableCell td2 = new TableCell();
          Label lblSum = new Label();
          int sum = Convert.ToInt32(td0.Text) * Convert.ToInt32(txtAnz.Text);
          lblSum.Text = sum.ToString()+ " summe";
          td2.Controls.Add(lblSum);

          TableCell td3 = new TableCell();
          Button btn = new Button();
          btn.Text = "Menge ändern " + i.ToString();
          btn.CommandArgument = i.ToString();
          btn.Command +=new CommandEventHandler(btn_Command);
          td3.Controls.Add(btn);

          tr.Controls.Add(td0);
          tr.Controls.Add(td1);
          tr.Controls.Add(td2);
          tr.Controls.Add(td3);
          Table1.Controls.Add(tr);
          }
          }

          // von VS.NET
          #region Vom Web Form-Designer generierter Code
          override protected void OnInit(EventArgs e)
          {
          InitializeComponent();
          base.OnInit(e);
          }

          private void InitializeComponent()
          {
          this.Load += new System.EventHandler(this.Page_Load);

          // Habe ich angelegt, hoffe das ist so richtig!?
          this.Init += new System.EventHandler(this.Page_Init);
          }
          #endregion
          }

          </pre&gt

          Comment


          • #6
            Hallo Stefan,

            die Definition von btn ist in Deinem Code kein Problem, weil Du in btn_Command nicht mehr darauf zugreifst, sondern nur das Commandargument nutzt - und das wird als Argument in die Funktion übergeben. Ich hab Deinen Code jedenfalls so zum Laufen bekommen.

            Drei Dinge sind mir noch aufgefallen:

            1)

            arrAnz.RemoveAt(i);
            arrAnz.Insert(i, Convert.ToInt32(txt.Text));

            kannst Du ersetzen durch

            (int) arr.Anz(i)=Convert.ToInt32(txt.Text)

            2)
            // Habe ich angelegt, hoffe das ist so richtig!?
            this.Init += new System.EventHandler(this.Page_Init);

            Das geht normalerweise in VS.NET automatisch:
            - Designer-Ansicht der Seite aufrufen
            - Im Eigenschaften-Fenster die Page auswählen
            - Das Event-Symbol (gelber Blitz) anklicken
            - Es werden alle Events angezeigt, die Page kennt
            - Beim gewünschten Event den Namen des Handlers eintragen
            - VS.NET legt den Handler richtig an.

            3) Deine Anwendung lässt sich wahrscheinlich mit einem DataGrid einfacher implementieren. Hier ist eine recht umfassende Zusammenstellung dazu:

            http://aspnet.4guysfromrolla.com/articles/040502-1.aspx

            Die Beispiele sind zwar in VB.NET, aber die Funktion ist in C# dieselbe.

            Schöne Grüße,

            Klau

            Comment


            • #7
              Hallo Klaus,<BR><BR>
              das hört sich ja gut an! Dennoch weiß ich nicht wie ich das umsetzen kann. Wäre nett von dir wenn du mir mal deine Quellcode zeigen könntest. SORRY!<BR>
              Vielen Dank für deine anderen Tipps. Wenn die Anwendung läuft werde ich mich mal mit dem Artikel auseinandersetzen.<BR><BR>Danke und schöne Grüße Stefa

              Comment


              • #8
                Hallo Stefan,

                so läufts bei mir:

                <PRE>
                using System;
                using System.Collections;
                using System.ComponentModel;
                using System.Data;
                using System.Drawing;
                using System.Web;
                using System.Web.UI;
                using System.Web.UI.WebControls;
                using System.Web.SessionState;

                public class WebForm1 : System.Web.UI.Page
                {
                protected System.Web.UI.WebControls.Table Table1;

                private void Page_Init(object sender, System.EventArgs e)
                {
                if(!IsPostBack)
                {
                ArrayList arrAnz = new ArrayList();
                for(int i = 0; i < 10; i++)
                {
                arrAnz.Add(i);
                Session["anz"] = arrAnz;
                }
                }
                doListing((ArrayList)Session["anz"]);
                }
                private void Page_Load(object sender, System.EventArgs e)
                { }

                private void Button_Command(object sender, System.Web.UI.WebControls.CommandEventArgs e)
                {
                string ID = e.CommandArgument.ToString();
                TextBox txt = (TextBox) FindControl(ID);
                ArrayList arrAnz = (ArrayList)Session["anz"];
                for(int i = 0; i < arrAnz.Count; i++)
                {
                if(i == Convert.ToInt32(ID))
                {
                arrAnz[i]= Convert.ToInt32(txt.Text);
                break;
                }
                } Session["anz"] = arrAnz;
                Label lbl;
                String IDS;
                int sum=0;

                for(int i = 0; i < 10; i++)
                {
                IDS="dynLabel"+i.ToString();
                lbl = (Label) FindControl(IDS);
                sum+=(int) arrAnz[i];
                lbl.Text=sum.ToString()+ " summe";
                }

                }

                private void doListing(ArrayList nArrAnz)
                {
                Table1.Controls.Clear();

                for(int i = 0; i < 10; i++)
                {

                TableRow tr = new TableRow();
                TableCell td0 = new TableCell();
                td0.Text = i.ToString();
                TableCell td1 = new TableCell();
                TextBox txtAnz = new TextBox();
                txtAnz.Text = nArrAnz[i].ToString();
                txtAnz.ID = i.ToString();
                td1.Controls.Add(txtAnz);
                TableCell td2 = new TableCell();
                Label lblSum = new Label();
                lblSum.ID="dynLabel"+i.ToString();
                int sum = Convert.ToInt32(td0.Text) * Convert.ToInt32(txtAnz.Text);
                lblSum.Text = sum.ToString()+ " summe";
                td2.Controls.Add(lblSum);
                TableCell td3 = new TableCell();
                Button btn = new Button();
                btn.Text = "Menge ändern " + i.ToString();
                btn.CommandArgument = i.ToString();
                btn.Command +=new CommandEventHandler(Button_Command);
                td3.Controls.Add(btn);
                tr.Controls.Add(td0);
                tr.Controls.Add(td1);
                tr.Controls.Add(td2);
                tr.Controls.Add(td3);
                Table1.Controls.Add(tr);
                }
                }

                #region Vom Web Form-Designer generierter Code

                override protected void OnInit(EventArgs e)
                {
                InitializeComponent();
                base.OnInit(e);

                }private void InitializeComponent()
                {
                this.Load += new System.EventHandler(this.Page_Load);
                this.Init += new System.EventHandler(this.Page_Init);
                }
                #endregion

                }

                </PRE>

                Als VB.NET-Entwickler hab ich's nicht so mit den eckigen Klammern. Die Anweisung aus meinem letzten Posting muss in C# so heißen:

                arrAnz[i]= Convert.ToInt32(txt.Text);

                Schöne Grüße,

                Klau

                Comment

                Working...
                X