Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Wanet Telecoms Ltd on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Page Load and Event Handlers 1

Status
Not open for further replies.

MalCarne

Technical User
Apr 1, 2005
70
US
I've run across a problem that I now understand the cause of, but have no idea how to resolve. I'm building controls on a form on the fly, based on a datareader's contents. It's dynamic, so I never know how many sets of controls that I'll need.
Basically, on pageLoad I put:
an image
a <ul>
a delete button
an update button

on the form.

The onclick event handler for the update goes to another page, so it's not an issue. My delete button, on the other hand does a submit.
I now understand that event handlers are process after pageLoad. This leaves me with a problem of the display being built before the delete eventhandler runs, so I'm always in a state of displaying one more set of controls than should be there.

Can someone tell me how I can place the delete event so that it processes before the pageLoad events? Can I check for the sender and act accordingly?
 
if your adding controls dynamically this must happen in the Page_Init stage so it hooks into viewstate properly.

why not use a repeater control to list your information? then you don't have to worry about Event Handlers and dynamic controls.
Code:
<asp:Repeater id="MyRepeater" runat="server">
   <HeaderTemplate>
         <ul>
   </HeaderTemplate>
   <ItemTemplate>
         <li>
           <asp:img id="img" runat="server" src='<%#Eval("ImageUrl") %>'
           <asp:button id="edit" runat="server" OnClientClick="window.location(...); return false;" text="Edit" />
           <asp:button id="delete" runat="server" OnClick="delete_Click" text="Delete" CommandArgument='<%#Eval("ID") %>' />
         </li>
   </ItemTemplate>
   <FooterTemplate>
         </ul>
   </FooterTemplate>
</asp:Repeater>

protected void delete_Click(object sender, EventArgs e)
{
     Button btn = (Button)sender;
     int id = int.Parse(sender.CommandArgument);
     //call delete function
}

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
That make sense. I'll give it a try, thanks.
 
hmm, not quite what I'm looking for. In this, I can have anywhere from 1 to 10 sets of controls that I'm putting into a div for each set. Each set will then have an image, a list of features, and the two buttons. What your example does is build a big ul containing the items in one list.

what I had was this:

Code:
        getLocker = objCmd.ExecuteReader();
        while (getLocker.Read()) 
        { 
            int locker = getLocker.GetInt32(0);
            string prod_code=getLocker.GetString(1);
            string prod=getLocker.GetString(2);
            int color_code=getLocker.GetInt32(3);
            string color=getLocker.GetString(4);
            string size=getLocker.GetString(6);
            string logo = getLocker.GetString(8);
            
            HtmlGenericControl div = new HtmlGenericControl("div");
            div.Attributes.Add("class", "lockeritem");
            pic.Controls.Add(div);
            Label lblProd = new Label();
            lblProd.Text = prod;
            div.Controls.Add(lblProd);
            HyperLink hl = new HyperLink();
            hl.Attributes.Add("href","updateItem.aspx?" + locker);
            hl.ImageUrl="../images/products/" + prod_code + "/" + prod_code + "_" + color + ".jpg";
            div.Controls.Add(hl);
            HtmlGenericControl ul = new HtmlGenericControl("ul");
            div.Controls.Add(ul);
            HtmlGenericControl liC = new HtmlGenericControl("li");
            liC.InnerText = "Color: " + color;
            ul.Controls.Add(liC);
            HtmlGenericControl liS = new HtmlGenericControl("li");
            liS.InnerText = "Size: " + size;
            ul.Controls.Add(liS);
            HtmlGenericControl liL = new HtmlGenericControl("li");
            liL.InnerText = "Logo: " + logo;
            ul.Controls.Add(liL);
            Button btnDelete = new Button();
            btnDelete.ID = "d" + locker.ToString();
            btnDelete.Click +=new EventHandler(btnDelete_Click);
            btnDelete.Text = "Delete This Item";
            div.Controls.Add(btnDelete);
            Button btnUpdate = new Button();
            btnUpdate.ID = "u" + locker.ToString();
            btnUpdate.Click += new EventHandler(btnUpdate_Click);
            btnUpdate.Text = "Change This Item";
            div.Controls.Add(btnUpdate);
        }

But as I said, I've got the problem of the event handler being dealt with after the pageLoad. Is there any way to prod the eventhandler to fire before I call the function above?
Thanks.
 
1st, i can't stress enough that you should seriously consider seperating your html/asp controls from the logic. your current code looks more like asp then asp.net. it's easier to maintain, less coding, and seperates concerns.

2nd, to answer your question no. the postback event cannot fire before page load event. each request is a new request to the server (that's the nature of web). asp.net gets around this with viewstate/postback flag. so with each request to the server the object must be "rebuilt" and viewstate assists in creating the object in it's "previous state". once the page has reached it's previous state the postback event can then be raised.

I recommend reading more about the page life cycle. this will help clarify your sitation.

things get even more complicated when you dynamically add controls (like you're snippet above). they must be added in the Page_Init event or the related viewstate information is not persisted to the client.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
First, let me state that I know just enough about .net to be dangerous and to be a huge pain in the a** in forums like this. I'm a systems guy trying to fill in for a missing developer who is floundering greatly, and for that I appologize. (but my boss wants what he wants, missing developer be damned)

I understand the preference of seperation of logic and controls, but I'm at a loss for an appropriate control to use for this.
If I understand the repeater control correctly, it can have 1 headertemplate and multiple itemtemplates and the header must come first. So, in wanting to add (in this order) a div, an image, an unformatted list, and 2 inputs, am I correct in assuming that I cannot use the repeater, as the headertemplate containing the ul must come first? Or is it possible to add multiple repeaters, but be able to group the elements of each seperately? Or is there another control that would be more suitable.

Thanks in advance for your patience.
 
looking at your code your data is flat. all the values are contained in 1 row. so a simple repeater like this would work:
Code:
<asp:Repeater id="MyRepeater" runat="server">
   <ItemTemplate>
      <div class="lockeritem">
         <%#Eval("prod")%>
         <asp:HyperLink 
            id="link" runat="server" 
            ImageUrl='<%#string.format("../images/products/{0}/{0}_{1}.jpg", Eval("prod_code"), Eval("color")) %>' 
            NavigateUrl='<%#Eval("locker", "updateItem.aspx?{0}") %>' text="My Link" />
         <ul>
            <li><%#Eval("color") %></li>
            <li><%#Eval("size") %></li>
            <li><%#Eval("logo") %></li>
         </ul>
         <asp:button id="edit" runat="server" OnClientClick="window.location(...); return false;" text="Edit" />
           <asp:button id="delete" runat="server" OnClick="delete_Click" text="Delete" CommandArgument='<%#Eval("ID") %>' />
      </div>
   </ItemTemplate>
</asp:Repeater>

protected void delete_Click(object sender, EventArgs e)
{
     Button btn = (Button)sender;
     int id = int.Parse(sender.CommandArgument);
     //call delete function
}
this will produce the follow markup
Code:
<div class="lockeritem">
   <label />
   <a><img /></a>
   <ul>
     <li>Color</li>
     <li>Size</li>
     <li>Logo</li>
   </ul>
   <button delete />
   <button update />
</div>
<div class="lockeritem">
   <label />
   <a><img /></a>
   <ul>
     <li>Color</li>
     <li>Size</li>
     <li>Logo</li>
   </ul>
   <button delete />
   <button update />
</div>
<div class="lockeritem">
   <label />
   <a><img /></a>
   <ul>
     <li>Color</li>
     <li>Size</li>
     <li>Logo</li>
   </ul>
   <button delete />
   <button update />
</div>
...
you can also nest repeaters/grids as well. for more information on this google nested gridview. the principle is the same for repeaters.

repeaters are good for read-only information (one way) information. (your current example.) two way databinding requires gridview, formview, detailsview. these are useful it you want to edit information inline.

now you'll need to address how your getting your data. you need to get the data out of the reader and into either a datatable or a List<T> of custom objects. then bind the table/list to the repeater.

personally I would recommend a 3rd part DAL. to name a few: MS Ent Lib, Castle Active Record, Solution Design LLBL. Ent Lib and Active Record are open source. LLBL cost a few bucks. google ".net OR Mapper" or ".net DAL" for more options.

your project may be too far long for this so other options are: SqlDataSource control (asp.net 2.0) and/or Typed DataSets. You want to avoid keeping DataReaders open because these are a direct link to you db. one of the biggest bottlenecks in any application. so the sooner you can close the reader the better.

check out ADO.Net. this represents the data access objects in the .net framework. I would recommend using a dataaccessadapter to fill a dataset. then bind the dataset to the repeater.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Well smack my ass and call me sally. If you turn it around and look at it a few different ways, it starts to make sense.
For those with my level of denseness, here's what I did

Code:
        <asp:Repeater ID="rpt" runat="server"  >
            <ItemTemplate>
                <div class="lockeritem">
                <img src='<%#"../images/products/" + DataBinder.Eval(Container.DataItem,"prod_id") + "/" + DataBinder.Eval(Container.DataItem,"prod_id") + "_" + DataBinder.Eval(Container.DataItem,"color") + ".jpg"  %>'  />
                <ul>
                <li>
                    '<%# Eval("size") %>'
                </li>
                </ul>
                </div>
            </ItemTemplate>

            
        </asp:Repeater>

Thanks jmeckley, you get a star.
 
You posted your last, while I was posting mine. I much prefer the shorthand that you put in for referencing the data elements. Thanks again.
 
Going to bug you one more time.
All of the controls render just fine, but on the delete click event, I get this error:

CS0117: 'object' does not contain a definition for 'CommandArgument'

I've tried a few variations with no results. Any insight?
 
Code:
Button btn = (Button)sender;
int id = int.Parse(btn.CommandArgument);
//call delete function

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top