Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Faking a PostBack in a DataGrid column – is there an easier way?


:P
On this page:

Ok, this may seem a bit silly but I don’t think I’ve gone down this particular path before.

 

I need to create a custom template column in a DataGrid and add several hyperlinks into the same column. The hyperlinks need to then post back to the page and be handled. Because there are multiple links in the same column I don't think button columns and the grid fired events work in this case.

 

I haven’t gone done this path because in most applications I simply tend to use classic style postbacks with a query string and be done with it. In this particular app this doesn’t work for a variety of reasons because the page is fairly complex and the query string parameters interfere. The other approach is to use a Button Column and then handle the Command event for the button which is fairly straight forward as well.

 

But if you end up doing your own postbacks to the same page things get a bit more ugly. I wonder whether there isn’t a better way than what I’m doing, which works just fine but feels a bit like a hack.

 

So inside of my datagrid I have a template column that does basically this:

 

<asp:templatecolumn headertext="Comment">

      <headerstyle horizontalalign="Center" width="100px"></headerstyle>

      <itemtemplate>

              <%# wwUtils.TextAbstract( Eval("Comment") ) %>
              <br /><i>

                  <a href="javascript:__doPostBack('btn_DownloadStatus','<%# Eval("Pk")%>')">

                  <%# Eval("Downloaded") %></a>

                  | <a href="javascript:if ( confirm('Are you sure you want to delete this invoice?') ) { __doPostBack('btn_Delete','<%# Eval("Pk")%>') }" >Delete</a>

                  </i>

      </itemtemplate>

</asp:templatecolumn>

 

I’m using hand coded __doPostBack() script calls to force a post back to the form. Inside of the __doPostBack() calls I use a couple of LinkButtons that I stuck on the form to act as the event target for the clicks. They’re in the form and invisible through their style settings:

 

<!-- Command Handler Buttons. These are invisible and only used to handle delete and downloaded events -->

<asp:LinkButton ID="btnDelete" runat="server" Text="Button" OnClick="btnDelete_Click" Visible="true" style="display:none" />

<asp:LinkButton ID="btnDownloadStatus" runat="server"  Text="Button" OnClick="btnDownloadStatus_Click" Visible="false" style="display:none" />

 

I then have a the Click handlers hooked up to these invisible buttons. Note that I have to use a style to hide the control – visible is required to get the __doPostBack() method rendered into the HTML. Hmmm… isn’t there method on the Page or ClientScript object to force this to render? I sure couldn’t find it short of having a control active that implements IPostBackHandler.

 

From there I can read the EventArgument to get my context for the record I’m working with which in this case is a Pk for the item:

 

/// <summary>

/// Handles the grid's Download toggle operation

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void btnDownloadStatus_Click(object sender, EventArgs e)

{

      int Pk = 0;

 

      if (int.TryParse(Request.Form["__eventArgument"], out Pk))

      {

          if (!Invoice.Load(Pk))

              this.lblErrorMessage.Text = Invoice.ErrorMessage + ".";

          else

          {

              Invoice.Entity.Downloaded = !Invoice.Entity.Downloaded;

              Invoice.Save();

          }

      }

}

 

Now all of this works well actually, but it just doesn’t feel right <g>. I feel like I’m beating ASP.NET into submission with this low level approach and it sure took a bit of trial and error just to arrive here…

 

So, is there a more official way to accomplish this?


The Voices of Reason


 

Gabe
January 26, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

I have had to do something very similar to this. I wasn't as creative and simply used the URL query string. This approach got messy and messed with the pages viewstate. Your approach is much more clever, although no more elegant. ;) I'll be intersted to see if anyone posts a simpler solution.

Bertrand Le Roy
January 26, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

Well, you shouldn't output the __doPostback thing yourself. You can use ClientScript.GetPostBackEventReference: http://msdn2.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.getpostbackeventreference.aspx or ClientScript.GetPostBackClientHyperLink: http://msdn2.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.getpostbackclienthyperlink.aspx

If you do that, it will automatically call the internal method Page.RegisterPostBackScript, which will output the __doPostback function to the client...

Wilco Bauwer
January 26, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

> "Because there are multiple links in the same column I don't think button columns and the grid fired events work in this case."

Why not? You should be able to simply use a LinkButton (or any other control that bubbles certain events for that matter) and either handle its Click/Command event, or the ItemCommand event on your grid (due to the bubbling mechanism in ASP.NET).

> "Hmmm… isn’t there method on the Page or ClientScript object to force this to render?"

Sorry if I missed something, but you should be able to simply call Page[.ClientScript].GetPostBackClientHyperlink(...). When that method is called, the page should render the __doPostBack script.

Wilco Bauwer
January 26, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

To elaborate a bit... I would change your download status link to a LinkButton and set its CommandName to say "downloadStatus" and its eventArgument to for the PK. You can then either handle the ItemCommand event of your grid or you could directly handle the Command event of the LinkButton. Both event args objects will contain the CommandName/CommandArgument.

Your delete button could be implemented similarly. Alternatively however, you could also set the CommandName to "delete", which would raise the DeleteCommand on your grid directly.

Havagan
January 27, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

I tend to use a drop down list for things like this. I'll put a DDL that has an item for each possible action... View, Edit, Delete, Add Comment, etc. Then I have the OnSelectedIndexChanged event call a method to handle the postback.

<asp:DropDownList ... OnSelectedIndexChanged="PerformAction()"></asp:DropDown>

From there my PerformAction() method grabs the DDL sender object to access the .SelectedItem property to find out what action to perform.

Protected Sub PerformAction(ByVal sender As System.Object, ByVal e as System.EventArgs)

Dim ddl As DropDownList = DirectCast(sender, DropDownList)

ddl.SelectedItem.Value 'holds the action to perform.

End Sub

Ben Scheirman
January 27, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

I don't see any reason why you can't use standard linkbuttons there.


Obviously you can't use a linkbuttonColumn, but then again, when CAN you?

Rick Strahl
January 28, 2006

# re: Faking a PostBack in a DataGrid column – is there an easier way?

Thanks all for the help. I have to admit that I tend to do things the 'raw html' way, more often than I should. Often it seems simply easier to do things that way than wade through the myriad of object properties and event handlers that need to be implemented.

I had previously tried to use LinkButtons and ItemCommands but I must have done something wrong - I couldn't get it to work. Sure enough now though when I tried again I had this up and running in a few minutes.

In this case it's definitely easier and cleaner to create LinkButtons and use the ItemCommand command event to capture the output.

Here's what I ended up with as Wilco suggested:
<asp:templatecolumn headertext="Downloaded">
<headerstyle horizontalalign="Center" width="100px"></headerstyle>
<itemtemplate>
<asp:LinkButton runat="server" ID="btnGridDownloaded" CommandName="DownloadStatus" CommandArgument='<%# Eval("pk") %>'><%# Eval("Downloaded") %></asp:LinkButton>
| <asp:LinkButton runat="server" ID="btnGridDelete" CommandName="DeleteInvoice" CommandArgument='<%# Eval("pk") %>'
OnClientClick="javascript:if ( confirm('Are you sure you want to delete this invoice?') ) return true; else return false;">Delete</asp:LinkButton>
</itemtemplate>
</asp:templatecolumn>

Then implement the ItemCommand method and check the e.CommandName and e.CommandArgument properties to decide what to do in response to the link clicks.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2025