views:

288

answers:

1

Hi,

I've got a rather lengthy question I'm afraid. I'm fairly new to ASP.NET so please bear with me. I have built a control for an ASP.NET page that lists a number of options. Each option has two clickable areas (call them buttons for the sake of simplicity). One to select the option and one to hide the option.


protected void Page_Load(object sender, EventArgs e)
{
  RenderOptions();
}

public void RenderOptions()
{
  for (int i = 0; i < 5; i++) {
    HtmlGenericControl div1 = new HtmlGenericControl("div");
    div1.Attributes.Add("onclick", ClientScript.GetPostBackEventReference(this, "option" + i));
    m_TreeContainer.Controls.Add(div1);

    HtmlGenericControl div2 = new HtmlGenericControl("div");
    div2.Attributes.Add("onclick", ClientScript.GetPostBackEventReference(this, "option" + i));
    m_TreeContainer.Controls.Add(div2);
  }
}

public void RaisePostBackEvent(string arg) 
{
  //do something
}

This works fine (I do implement the IPostBackEventHandler interface). The problem here is that there doesn't seem to be a way for me to find which HTML element was clicked and thus which action should be performed in the RaisePostBackEvent method.

What I tried to do is create a new class (HtmlDivControl) which looks like this:


class HtmlDivControl : HtmlGenericControl, IPostBackEventHandler
{
  #region Delegates
  public delegate void ClickEventHandler(object sender, string eventArgument);
  #endregion

  #region Properties
  private ClickEventHandler m_Click;
  public ClickEventHandler Click
  {
    get { return m_Click; }
    set { m_Click = value; }
  }
  #endregion

  #region Constructors
  public HtmlDivControl()
  {
  }
  #endregion

  public void RaisePostBackEvent(string eventArgument)
  {
    m_Click.Invoke(this, eventArgument);
  }
}

Now I made div1 and div2 my HtmlDivControl rather than HtmlGenericControl, set the Click property to a method (delegate) and passed the div (div1 or div2) itself as control for the GetPostBackEventReference method. This time, I could not only differentiate between the divs but also pre-determine the action that should be performed. However, the RaisePostBackEvent for controls are called after PageLoad. So the problem I'm with now is that the whole options control is rendered before the events are handled (and thus, an option that should for instance be hidden isn't because the actual hiding happens after the rendering). Moving the RenderOptions() call to the PageLoadComplete method doesn't help either, since then the div controls won't exist yet.

I'm pretty sure I'm missing something quite fundamental here. But could someone please explain me how I should approach something like this?

p.s. How am I supposed to write underscores here? They're used to make text italic? Is there some escape character?

+2  A: 

For someone new to ASP.Net, you've done pretty well so far. Your roadblock here is actually the way you are thinking about the issue. You should get a good grasp of the ASP.Net Page Lifecycle - you are missing something very fundamental.

In a nutshell, you want your page to rebuild it's state to the same way it was before the postback. Then process your events. Then make any state changes.

You're thinking about it as if your html controls should know about their state change at the start of the request, which is incorrect. There has to be the rebuilding phase first. This is critical for ASP.Net to even figure out which events to raise.

What I would recommend:

  1. move your "RenderOptions()" method to the Page_Init handler. This will save you lots of issues if you ever incorporate ViewState into your controls. (I would also rename it, as it's not truly rendering anything, it's just adding your controls to the page. Render has a specific context in ASP.Net).

  2. Then, in your OnClick event handlers for your controls, simply set your controls visibility as necessary, rather than trying to control the way they are rendered. It is always much simpler to set controls to Visible=False rather than try to change the way the controls are being rendered to the page. Remember that if you set Visible=False, there will be zero html sent to the response for that control, but the server will still know it's on the page, so you can still deal with it.

Think about your event handlers as the place where you will change the state of the page. It's where your logic should be in this case, rather than in Page_Load.

womp