How to check whether postback caused by a Dynamic link button
Asked Answered
M

4

12

I have a button control. On click of this button I need to add a Link Button dynamically. The Link Button needs an event handler. Hence the dynamic Link button is first added in the Page_Load and cleared and added again in the button click handler. Please read Dynamic Control’s Event Handler’s Working for understanding the business requirement for this.

I have read On postback, how can I check which control cause postback in Page_Init event for identifying the control that caused the postback (inside Page_Load). But it is not working for my scenario.

What change need to be done to confirm whether the postback was caused by link button (inside Page_Load)?

Note: Refer the following for another scenario where it is inevitable https://codereview.stackexchange.com/questions/20510/custom-paging-in-asp-net-web-application

Note 1: I need to get the postback control ID as the first step inside if (Page.IsPostBack). I need to add the dynamic link buttons control only if it is a postback from the button or the link button. There will be other controls that causes postback. For such postbacks we should not execute this code.

Note 2: I am getting empty string for Request["__EVENTARGUMENT"] in the Page_Load

Related Question: By what event, the dynamic controls will be available in the Page (for using in FindControl). @Tung says - "Your GetPostBackControlId method is properly getting the name of the control that caused the postback, but it is unable to find a control with that id through page.FindControl because the linkbutton has not been created yet, and so page does not know of its existence. "

ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PostbackTest.aspx.cs" Inherits="PostbackTest"
MasterPageFile="~/TestMasterPage.master" %>

<asp:Content ID="myContent" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div id="holder" runat="server">
</div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="TestClick" />
</asp:Content>

CODE BEHIND

public partial class PostbackTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

    if(Page.IsPostBack)
    {
        string IDValue = GetPostBackControlId(this.Page);
        int x = 0;

        holder.Controls.Clear();
        LinkButton lnkDynamic = new LinkButton();
        lnkDynamic.Click += new EventHandler(LinkClick);
        lnkDynamic.ID = "lnkDynamic123";
        lnkDynamic.Text = "lnkDynamic123";
        holder.Controls.Add(lnkDynamic);
    }
}

protected void TestClick(object sender, EventArgs e)
{
    holder.Controls.Clear();
    LinkButton lnkDynamic = new LinkButton();
    lnkDynamic.Click += new EventHandler(LinkClick);
    lnkDynamic.ID = "lnkDynamic123";
    lnkDynamic.Text = "lnkDynamic123";
    holder.Controls.Add(lnkDynamic);
}

protected void LinkClick(object sender, EventArgs e)
{

}

public static string GetPostBackControlId(Page page)
{
    if (!page.IsPostBack)
    {
        return string.Empty;
    }

    Control control = null;

    // First check the "__EVENTTARGET" for  controls with "_doPostBack" function
    string controlName = page.Request.Params["__EVENTTARGET"];
    if (!String.IsNullOrEmpty(controlName))
    {
        control = page.FindControl(controlName);
    }
    else
    {
        // if __EVENTTARGET is null, the control is a button type 
        string controlId;
        Control foundControl;

        foreach (string ctl in page.Request.Form)
        {
            // Handle ImageButton they having an additional "quasi-property" in their Id which identifies mouse x and y coordinates
            if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
            {
                controlId = ctl.Substring(0, ctl.Length - 2);
                foundControl = page.FindControl(controlId);
            }
            else
            {
                foundControl = page.FindControl(ctl);
            }

            if (!(foundControl is Button || foundControl is ImageButton)) continue;

            control = foundControl;
            break;
        }
    }

    return control == null ? String.Empty : control.ID;
}
}

REFERENCE

  1. On postback, how can I check which control cause postback in Page_Init event
  2. Dynamic Control’s Event Handler’s Working
  3. Understanding the JavaScript __doPostBack Function
  4. Access JavaScript variables on PostBack using ASP.NET Code
  5. How does ASP.NET know which event to fire during a postback?
  6. how to remove 'name' attribute from server controls?
  7. How to use __doPostBack()
Marshallmarshallese answered 23/1, 2013 at 18:27 Comment(6)
Your GetPostBackControlId method is properly getting the name of the control that caused the postback, but it is unable to find a control with that id through page.FindControl because the linkbutton has not been created yet, and so page does not know of its existence. If your link button is always going to be given the id,linkDynamic123, then @Dan Hunex's solution should work for you.Teary
@Teary I am getting empty string for Request["__EVENTARGUMENT"] in the Page_LoadMarshallmarshallese
@Teary By what event, the dynamic controls will be available in the Page (for using in FindControl) ?Marshallmarshallese
as matk pointed out, it should be __EVENTTARGET. I did not notice that Dan had used __EVENTARGUMENT.Teary
Please see my answer to how to use __doPostBack: How to use __doPostBack()Tiddly
Won't the loop simply return the first button or imagebutton it finds? There doesn't appear to be anything checking if that was actually the right item.Kitkitchen
A
8

A postback in asp.net is done by the java script function __doPostback(source, parameter)

so in your case it would be

    __doPostback("lnkDynamic123","") something like this

So in the code behind do the following

    var btnTrigger = Request["__EVENTTARGET"]; 

     if(btnTrigger=="lnkDynamic123") 
{
}

--- this would tell that it is your linkbutton that causes the postback

Admeasurement answered 23/1, 2013 at 23:38 Comment(2)
I am getting empty string for Request["__EVENTARGUMENT"]Marshallmarshallese
That should be Request["__EVENTTARGET"].Unhandled
U
4

You can move the call to the GetPostBackControlId method after the LinkButton has been added to the page:

protected void Page_Load(object sender, EventArgs e)
{
    if (Page.IsPostBack)
    {
        holder.Controls.Clear();
        LinkButton lnkDynamic = new LinkButton();
        lnkDynamic.Click += new EventHandler(LinkClick);
        lnkDynamic.ID = "lnkDynamic123";
        lnkDynamic.Text = "lnkDynamic123";
        holder.Controls.Add(lnkDynamic);

        string IDValue = GetPostBackControlId(this.Page);

        if (IDValue == lnkDynamic.ID)
            LinkClick(lnkDynamic, new EventArgs());
    }
}

Calling the click event handler here also more closely mimics the standard ASP.NET Page Life Cycle, where Postback event handling occurs after the Load event.

Edit:

If the control ID must be determined before the LinkButtons are created, you can create a naming scheme for the link button IDs, e.g. lnkDynamic_1, lnkDynamic_2 etc. Request["__EVENTTARGET"] will then contain the auto-generated control ID such as “ctl00$mc$lnkDynamic_1”, which you can use to identify which LinkButton caused the postback.

Unhandled answered 29/1, 2013 at 10:43 Comment(5)
I should be able to get the postback control ID as the first step inside if (Page.IsPostBack). This insulation is NOT what I requiredMarshallmarshallese
Your example already shows how to get the postback control ID as the first step - by inspecting Request["__EVENTTARGET"]. If you need to get a reference to the actual control, then this is impossible, because at this point the control hasn't been created yet, as @Teary already pointed out. Can you elaborate why it is required to get the control ID in the first step? Your example doesn't make it clear why moving the GetPostBackControlId call a few lines down is not an option.Unhandled
I need to add the dynamic link buttons control only if it is a postback from the button or the link button. There will be other controls that causes postback. For such postbacks we should not execute this code.Marshallmarshallese
Then you could create a naming scheme for the link buttons, e.g. lnkDynamic_1, lnkDynamic_2 etc., and check if Request["__EVENTTARGET"] starts with "lnkDynamic". This will tell you if any of the LinkButton controls caused the postback.Unhandled
Sorry, that should be "contains" instead of "starts with". Request["__EVENTTARGET"] will contain the ID created by ASP.NET, such as "ctl00$mc$lnkDynamic_1".Unhandled
C
2

If You're getting the post back control id correctly but FindControl returns nothing, then it's probably because You're using a master page. Basically, someControl.FindControl(id) searches through controls that are in someControl.NamingContainer naming container. But in Your case, the Button1 control is in the ContentPlaceHolder1, which is a naming container, and not directly in the Page naming container, so You won't find it by invoking Page.FindControl. If You can't predict in which naming container the control You're looking for is going to be (e.g. post back can be caused by two different buttons from two different content placeholders), then You can write an extension that'll search for a control recursively, like so:

public static class Extensions
{
    public static Control FindControlRecursively(this Control control, string id)
    {
        if (control.ID == id)
            return control;
        Control result = default(Control);
        foreach (Control child in control.Controls)
        {
            result = child.FindControlRecursively(id);
            if (result != default(Control)) break;
        }
        return result;
    }
}

Use it with caution though, because this method will return the first control that it finds with the specified id (and You can have multiple controls with the same id - but they should be in different naming containers; naming containers are meant to differentiate between controls with same ids, just as namespaces are meant to differentiate between classes with same names).

Alternatively, You could try to use FindControl(string id, int pathOffset) overload, but I think it's pretty tricky.

Also, check this question out.

Charolettecharon answered 1/2, 2013 at 8:42 Comment(0)
S
2

First approach (wouldn't recommend but it's more flexible)

One completely different approach - although I don't really feel like I should promote it - is to add a hidden field to the form.

The value of this hidden field might be something like false by default.

In case of clicking one of the dynamic buttons which should cause the dynamic controls to be added again, you can simply change the hidden fields value to true on client side before performing the postback (eventually you want/have to modify the client side onclick handler to make this happen).

Of course it would be possible to store more information in such a field, like the controls id and the argument (but you can get those values as described in the other answers). No naming schema would be required in this case.

This hidden field could be "static". So it would be accessible in code behind all time. Anyhow, you might want to implement something to make sure that nobody is playing around with its values and fakes a callback which looks like it originated from one of these dynamic links.

However, this whole approach just helps you getting the id of the control. Until you create the control again, you won't be able to get the instance through NamingContainer.FindControl (as mentioned in the other answers already ;)). And in case you create it, you don't need to find it anymore.

Second approach (might not be suitable due to its contraints)

If you want to do it the clean way, you need to create your controls OnLoad, no matter if something was clicked or not. Additionally, the dynamic controls ID has to be the same as the one you sent to the client in the first place. You subscribe to its Click or Command event and set its visibility to false. Inside the click event handler, you set the senders visibility to true again. This implies, that you don't care if that link is created but instead just don't want to send it to the client. The example below only works for a single link of course (but you could easily modify it to cover a whole group of links).

public void Page_Load(object sender, EventArgs e)
{
  LinkButton dynamicButton = new LinkButton();
  dynamicButton.ID = "linkDynamic123";
  // this id needs to be the same as it was when you 
  // first sent the page containing the dynamic link to the client
  dynamicButton.Click += DynamicButton_Click;
  dynamicButton.Visible = false;
  Controls.Add(dynamicButton);
}

public void DynamicButton_Click(object sender, EventArgs e)
{
  // as you created the control during Page.Load, this event will be fired. 
  ((LinkButton)sender).Visible = true;
}
Schulein answered 1/2, 2013 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.