ImageButton PostBack Help

Discussion in 'ASP .Net Building Controls' started by Anthony Merante, Jul 5, 2006.

  1. I cant figure out why this ImageButton doesn't post back the way a Button
    does. Can anyone explain to me why the RaisePostBackEvent() method doesn't
    get called here..

    public class MyControl : CompositeControl, IPostBackEventHandler

    {

    ImageButton img;

    protected override void CreateChildControls()

    {

    this.CreateControls();

    }

    private void CreateControls()

    {

    img = new ImageButton();

    img.ID = this.UniqueID;

    }



    protected override void Render(HtmlTextWriter writer)

    {

    img.RenderControl(writer);

    }



    #region IPostBackEventHandler Members



    public void RaisePostBackEvent(string eventArgument)

    {

    throw new Exception("The method or operation is not
    implemented.");

    }



    #endregion

    }



    If I change the ImageButton to a Button, the RaisePostBackEvent is called,
    but not with a ImageButton. Also, I'd like to write up a Command Event
    instead of the whole RaisePostbackEvent but that wouldn't fire either.



    What silliness is happening here?



    Thanks
     
    Anthony Merante, Jul 5, 2006
    #1
    1. Advertisements

  2. Anthony Merante

    Teemu Keiski Guest

    In CreateControls, you also need to add the ImageButton to Controls
    collection, so that postbacking works

    private void CreateControls()
    {
    img = new ImageButton();
    img.ID = this.UniqueID;
    Controls.Add(img);
    }
     
    Teemu Keiski, Jul 10, 2006
    #2
    1. Advertisements

  3. Thanks for responding Teemu,

    That doesnt seem to help. I've done that as well. I must have deleted that
    line when i cleaned up the example to show.

    I'm still at a loss to understand why this doesnt work. Any other ideas?
     
    Anthony Merante, Jul 11, 2006
    #3
  4. Anthony Merante

    Teemu Keiski Guest

    Hi,

    sorry, I took a deeper look into your control. Reason is that ImageButton
    handles its own Click event (it itself implements IPostBackEventHandler) and
    therefore it won't be raised in your own custom control. In order to call
    RaisePostBackEvent in your custom control instead of on ImageButton, you
    would need have your own custom control as source for the postbacking (e.g
    it should cause the postback). Now it's the ImageButton, since it will be
    clicked, and it handles its own events.

    Simple way is to wire event handler for the ImageButton's Click event, that
    way you'd get notified when it is clicked and remove IPostBackEventHandler
    totally from your custom control.
     
    Teemu Keiski, Jul 12, 2006
    #4
  5. Hmm, interesting.

    I think i understand what you're saying but both the Button and ImageButton
    implement IPostBackEventHandler. Why would the Button work and the
    ImageButton not work. I have gotten the example to work by doing just as you
    suggested, ie having the custom control handling the postback. One thing i
    noticed while looking at Object Browser is that Button inherits from
    WebControl and the ImageButton Inherits from Image ( which inherits from
    WebControl ). Do you think that this inheritance hierarchy is not bubbling
    up the event properly ?

    Also, I HAVE tried to wire up a click event for my imageButton and that
    didnt work either (though i haven't tried it without IPostBackEventHandler,
    I'll try this tonight.)

    Thanks again for responding,
    t
     
    Anthony Merante, Jul 12, 2006
    #5
  6. Anthony Merante

    Teemu Keiski Guest

    Post the entire code you have, or was the previous such?

    Teemu
     
    Teemu Keiski, Jul 17, 2006
    #6
  7. Anthony Merante

    sam Guest

    What you are doing is seting the ID of the button to the UniqueID of
    your composite control, so that when the button is rendered is name
    attribute will be rendered in such a way so as your composite control
    will receive the postback event. Not really my cup of tea, but thats
    just my opinion.

    Anyway, if you download Reflector:

    (In Page class)
    private void ProcessPostData(NameValueCollection postData, bool
    fBeforeLoad)
    {
    if (this._changedPostDataConsumers == null)
    {
    this._changedPostDataConsumers = new ArrayList();
    }
    if (postData != null)
    {
    foreach (string text1 in postData)
    {
    if ((text1 != null) &&
    !Page.IsSystemPostField(text1))
    {
    Control control1 = this.FindControl(text1);
    if (control1 == null)
    {
    if (fBeforeLoad)
    {
    if (this._leftoverPostData == null)
    {
    this._leftoverPostData = new
    NameValueCollection();
    }
    this._leftoverPostData.Add(text1,
    null);
    }
    }
    else
    {
    IPostBackDataHandler handler1 =
    control1.PostBackDataHandler;
    if (handler1 == null)
    {
    if (control1.PostBackEventHandler
    != null)
    {

    this.RegisterRequiresRaiseEvent(control1.PostBackEventHandler);
    }
    }
    .....

    The above code is sniffing the form data for name values that match the
    uniqueID of controls that implement IPostBackEventHandler and
    automatically registering them for RaisePostBackEvent (which it what
    fires your RaisePostBackEvent and incidentally the OnClick event in the
    standard MS controls). This sniffing is successful for the button
    because it submits just its name in the form collection. The
    ImageButton instead submits name.x and name.y, and so the sniffing will
    not be successful

    Also, the ImageButton implements both IPostBackEventHandler *and*
    IPostBackDataHandler, and so it wouldnt be successful anyway (as you
    can see by a close inspection of the code above)

    Here is the code I'm talking about for
    Page.RegisterRequiresRaiseEvent():

    public virtual void RegisterRequiresRaiseEvent(IPostBackEventHandler
    control)
    {
    this._registeredControlThatRequireRaiseEvent = control;
    }

    which in Page.RaisePostBackEvent() finally calls your
    RaisePostBackEvent:

    private void RaisePostBackEvent(NameValueCollection postData)
    {
    if (this._registeredControlThatRequireRaiseEvent != null)
    {

    this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent,
    null);
    }
    }
    .....

    It seems that if you simply called
    Page.RegisterRequiresRaiseEvent(this) sometime in your composite
    control that would work fine.

    I'm not sure why they did it this way. Its also possible my analysis
    may be wrong. Can Teemu shed some more light on this?

    -Sam
     
    sam, Jul 19, 2006
    #7
  8. Anthony Merante

    Teemu Keiski Guest

    Inline:
    It was with v1.x that if control implemented both IPostBAckEventHandler and
    IPostBackDataHandler, IPostBackDataHandler implementation was the one
    getting called and IPostBackEventHandler wasn't. Therefore this type of
    control would need to call Page.RegisterRequiresRaiseEvent like ImageButton
    does in its LoadPostData method (IPostBackDataHandler implementation).
    However, I think it should work with v2.x already, at least with some of my
    experimenting it did but based on reflected code it seems to be like in
    v.1.x. And ImageButton's implementation supports that view.
    Exaclty because RegisterRaiseEvent is used when control itself cannot raise
    the event (or better said page framework cannot) one reason being dual
    implementation of interfaces or when the control itself isn't source of the
    event. If you have CompositeControl with ImageButton as child control and
    when you click the ImageButton, your composite control's
    IPostBackEventHandler implementation won't be called. ImageButton's will be,
    because it was the control responsible for the postback.

    Implementing IPostBackEventHandler in custom control would make sense only
    when control itself will be the source of the event. Basically you could
    just wire handler for the Click event internally in the control and then
    raise a new top-level event with no interface implementation.

    Based on previous discussion I wrote a couple of implementations with Button
    and ImageButton as child control.

    'ButtonCompositeControl.cs

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;

    /// <summary>
    /// Summary description for ButtonCompositeControl
    /// </summary>
    namespace Samples
    {
    public class ButtonCompositeControl : CompositeControl
    {

    protected override void CreateChildControls()
    {
    Button btn = new Button();
    btn.ID = "Button1";
    btn.Text = "Click me, I'm a Button";
    btn.Click += new EventHandler(btn_Click);
    Controls.Add(btn);
    }

    void btn_Click(object sender, EventArgs e)
    {
    OnButtonClick(e);
    }

    #region "Event implementation"
    private static readonly object EventButtonClick = new object();

    public event EventHandler ButtonClick
    {
    add
    {
    Events.AddHandler(EventButtonClick, value);
    }
    remove
    {
    Events.RemoveHandler(EventButtonClick, value);
    }
    }

    protected virtual void OnButtonClick(EventArgs e)
    {
    EventHandler eh = Events[EventButtonClick] as EventHandler;
    if (eh != null)
    {
    eh(this, e);
    }
    }
    #endregion





    }
    }

    'ImageButtonCompositeControl.cs

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;

    /// <summary>
    /// Summary description for ButtonCompositeControl
    /// </summary>
    namespace Samples
    {
    public class ImageButtonCompositeControl : CompositeControl
    {

    protected override void CreateChildControls()
    {
    ImageButton imgbtn = new ImageButton();
    imgbtn.ID = "ImageButton1";
    imgbtn.AlternateText = "Click me, I'm an ImageButton";
    imgbtn.Click += new ImageClickEventHandler(imgbtn_Click);
    Controls.Add(imgbtn);
    }

    void imgbtn_Click(object sender, ImageClickEventArgs e)
    {
    OnImageButtonClick(e);
    }

    #region "Event implementation"
    private static readonly object EventImageButtonClick = new object();

    public event ImageClickEventHandler ImageButtonClick
    {
    add
    {
    Events.AddHandler(EventImageButtonClick, value);
    }
    remove
    {
    Events.RemoveHandler(EventImageButtonClick, value);
    }
    }

    protected virtual void OnImageButtonClick(ImageClickEventArgs e)
    {
    ImageClickEventHandler iceh = Events[EventImageButtonClick] as
    ImageClickEventHandler;
    if (iceh != null)
    {
    iceh(this, e);
    }
    }
    #endregion





    }
    }

    'AND HERE's THE TEST PAGE FOR THEM (CODE FILES IN APP_CODE)

    <%@ Page Language="C#" %>
    <%@ Register Namespace="Samples" TagPrefix="ss" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script runat="server">

    protected void Button1_ButtonClick(object sender, EventArgs e)
    {
    Response.Write("Button1 was clicked");
    }


    protected void Button2_ImageButtonClick(object sender,
    ImageClickEventArgs e)
    {
    Response.Write("Button2 was clicked");
    }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
    <title>Untitled Page</title>
    </head>
    <body>
    <form id="form1" runat="server">
    <div>
    <ss:ButtonCompositeControl runat="server" ID="Button1"
    OnButtonClick="Button1_ButtonClick" />
    <ss:ImageButtonCompositeControl runat="server" ID="Button2"
    OnImageButtonClick="Button2_ImageButtonClick" />
    </div>
    </form>
    </body>
    </html>
     
    Teemu Keiski, Jul 19, 2006
    #8
  9. Anthony Merante

    Tony Merante Guest

    Teemu and Sam,

    Thanks for the help. I think i have seen my errors. I think i figured out a
    few things with your help.

    this line was my problem
    img.ID = this.UniqueId;

    I should not have set my consituent control's ID the same as the
    CustomControl. I did that because of examples i've seen that implement the
    IPostbackDataHandler. In hindsight, I see that I dont need those Methods in
    that interface to capture an event that my constiuent control already
    handles for me. Once i set the ID of my IMageButton to anything other than
    this.UniqueID, the img button's Click event fired.

    Now, to my next question.. I'll start another thread on that.

    Thanks a lot for your help!!
    Tony Merante




     
    Tony Merante, Jul 23, 2006
    #9
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.